changeset 19:5e8e5083da94

brought in common and gba, fixed problems with outdated Makefile.am files in both of these packages
author Robert McIntyre <rlm@mit.edu>
date Sun, 04 Mar 2012 14:33:52 -0600
parents ac56489c2ca6
children ecd30c5e2f5a
files .hgignore AUTHORS COPYING ChangeLog INSTALL NEWS README configure.ac src/Makefile.am src/NLS.h src/Port.h src/common/CheatSearch.cpp src/common/CheatSearch.h src/common/Makefile.am src/common/System.h src/common/Text.cpp src/common/Text.h src/common/Util.cpp src/common/Util.h src/common/inputGlobal.h src/common/lua-engine.cpp src/common/memgzio.c src/common/memgzio.h src/common/movie.cpp src/common/movie.h src/common/nesvideos-piece.cpp src/common/nesvideos-piece.h src/common/unzip.cpp src/common/unzip.h src/common/vbalua.h src/gb/gbCheats.cpp src/gba/EEprom.cpp src/gba/EEprom.h src/gba/Flash.cpp src/gba/Flash.h src/gba/GBA.cpp src/gba/GBA.h src/gba/GBACheats.cpp src/gba/GBACheats.h src/gba/GBAGfx.cpp src/gba/GBAGfx.h src/gba/GBAGlobals.cpp src/gba/GBAGlobals.h src/gba/GBASound.cpp src/gba/GBASound.h src/gba/GBAinline.h src/gba/Makefile.am src/gba/Mode0.cpp src/gba/Mode1.cpp src/gba/Mode2.cpp src/gba/Mode3.cpp src/gba/Mode4.cpp src/gba/Mode5.cpp src/gba/RTC.cpp src/gba/RTC.h src/gba/Sram.cpp src/gba/Sram.h src/gba/agbprint.cpp src/gba/agbprint.h src/gba/arm-new.h src/gba/armdis.cpp src/gba/armdis.h src/gba/bios.cpp src/gba/bios.h src/gba/elf.cpp src/gba/elf.h src/gba/remote.cpp src/gba/thumb.h
diffstat 64 files changed, 44357 insertions(+), 1364 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/.hgignore	Sat Mar 03 12:06:10 2012 -0600
     1.2 +++ b/.hgignore	Sun Mar 04 14:33:52 2012 -0600
     1.3 @@ -10,4 +10,5 @@
     1.4  configure.scan
     1.5  *Makefile.in*
     1.6  config.h.in
     1.7 -build/*
     1.8 \ No newline at end of file
     1.9 +build/*
    1.10 +build-aux/*
    1.11 \ No newline at end of file
     2.1 --- a/COPYING	Sat Mar 03 12:06:10 2012 -0600
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,674 +0,0 @@
     2.4 -                    GNU GENERAL PUBLIC LICENSE
     2.5 -                       Version 3, 29 June 2007
     2.6 -
     2.7 - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
     2.8 - Everyone is permitted to copy and distribute verbatim copies
     2.9 - of this license document, but changing it is not allowed.
    2.10 -
    2.11 -                            Preamble
    2.12 -
    2.13 -  The GNU General Public License is a free, copyleft license for
    2.14 -software and other kinds of works.
    2.15 -
    2.16 -  The licenses for most software and other practical works are designed
    2.17 -to take away your freedom to share and change the works.  By contrast,
    2.18 -the GNU General Public License is intended to guarantee your freedom to
    2.19 -share and change all versions of a program--to make sure it remains free
    2.20 -software for all its users.  We, the Free Software Foundation, use the
    2.21 -GNU General Public License for most of our software; it applies also to
    2.22 -any other work released this way by its authors.  You can apply it to
    2.23 -your programs, too.
    2.24 -
    2.25 -  When we speak of free software, we are referring to freedom, not
    2.26 -price.  Our General Public Licenses are designed to make sure that you
    2.27 -have the freedom to distribute copies of free software (and charge for
    2.28 -them if you wish), that you receive source code or can get it if you
    2.29 -want it, that you can change the software or use pieces of it in new
    2.30 -free programs, and that you know you can do these things.
    2.31 -
    2.32 -  To protect your rights, we need to prevent others from denying you
    2.33 -these rights or asking you to surrender the rights.  Therefore, you have
    2.34 -certain responsibilities if you distribute copies of the software, or if
    2.35 -you modify it: responsibilities to respect the freedom of others.
    2.36 -
    2.37 -  For example, if you distribute copies of such a program, whether
    2.38 -gratis or for a fee, you must pass on to the recipients the same
    2.39 -freedoms that you received.  You must make sure that they, too, receive
    2.40 -or can get the source code.  And you must show them these terms so they
    2.41 -know their rights.
    2.42 -
    2.43 -  Developers that use the GNU GPL protect your rights with two steps:
    2.44 -(1) assert copyright on the software, and (2) offer you this License
    2.45 -giving you legal permission to copy, distribute and/or modify it.
    2.46 -
    2.47 -  For the developers' and authors' protection, the GPL clearly explains
    2.48 -that there is no warranty for this free software.  For both users' and
    2.49 -authors' sake, the GPL requires that modified versions be marked as
    2.50 -changed, so that their problems will not be attributed erroneously to
    2.51 -authors of previous versions.
    2.52 -
    2.53 -  Some devices are designed to deny users access to install or run
    2.54 -modified versions of the software inside them, although the manufacturer
    2.55 -can do so.  This is fundamentally incompatible with the aim of
    2.56 -protecting users' freedom to change the software.  The systematic
    2.57 -pattern of such abuse occurs in the area of products for individuals to
    2.58 -use, which is precisely where it is most unacceptable.  Therefore, we
    2.59 -have designed this version of the GPL to prohibit the practice for those
    2.60 -products.  If such problems arise substantially in other domains, we
    2.61 -stand ready to extend this provision to those domains in future versions
    2.62 -of the GPL, as needed to protect the freedom of users.
    2.63 -
    2.64 -  Finally, every program is threatened constantly by software patents.
    2.65 -States should not allow patents to restrict development and use of
    2.66 -software on general-purpose computers, but in those that do, we wish to
    2.67 -avoid the special danger that patents applied to a free program could
    2.68 -make it effectively proprietary.  To prevent this, the GPL assures that
    2.69 -patents cannot be used to render the program non-free.
    2.70 -
    2.71 -  The precise terms and conditions for copying, distribution and
    2.72 -modification follow.
    2.73 -
    2.74 -                       TERMS AND CONDITIONS
    2.75 -
    2.76 -  0. Definitions.
    2.77 -
    2.78 -  "This License" refers to version 3 of the GNU General Public License.
    2.79 -
    2.80 -  "Copyright" also means copyright-like laws that apply to other kinds of
    2.81 -works, such as semiconductor masks.
    2.82 -
    2.83 -  "The Program" refers to any copyrightable work licensed under this
    2.84 -License.  Each licensee is addressed as "you".  "Licensees" and
    2.85 -"recipients" may be individuals or organizations.
    2.86 -
    2.87 -  To "modify" a work means to copy from or adapt all or part of the work
    2.88 -in a fashion requiring copyright permission, other than the making of an
    2.89 -exact copy.  The resulting work is called a "modified version" of the
    2.90 -earlier work or a work "based on" the earlier work.
    2.91 -
    2.92 -  A "covered work" means either the unmodified Program or a work based
    2.93 -on the Program.
    2.94 -
    2.95 -  To "propagate" a work means to do anything with it that, without
    2.96 -permission, would make you directly or secondarily liable for
    2.97 -infringement under applicable copyright law, except executing it on a
    2.98 -computer or modifying a private copy.  Propagation includes copying,
    2.99 -distribution (with or without modification), making available to the
   2.100 -public, and in some countries other activities as well.
   2.101 -
   2.102 -  To "convey" a work means any kind of propagation that enables other
   2.103 -parties to make or receive copies.  Mere interaction with a user through
   2.104 -a computer network, with no transfer of a copy, is not conveying.
   2.105 -
   2.106 -  An interactive user interface displays "Appropriate Legal Notices"
   2.107 -to the extent that it includes a convenient and prominently visible
   2.108 -feature that (1) displays an appropriate copyright notice, and (2)
   2.109 -tells the user that there is no warranty for the work (except to the
   2.110 -extent that warranties are provided), that licensees may convey the
   2.111 -work under this License, and how to view a copy of this License.  If
   2.112 -the interface presents a list of user commands or options, such as a
   2.113 -menu, a prominent item in the list meets this criterion.
   2.114 -
   2.115 -  1. Source Code.
   2.116 -
   2.117 -  The "source code" for a work means the preferred form of the work
   2.118 -for making modifications to it.  "Object code" means any non-source
   2.119 -form of a work.
   2.120 -
   2.121 -  A "Standard Interface" means an interface that either is an official
   2.122 -standard defined by a recognized standards body, or, in the case of
   2.123 -interfaces specified for a particular programming language, one that
   2.124 -is widely used among developers working in that language.
   2.125 -
   2.126 -  The "System Libraries" of an executable work include anything, other
   2.127 -than the work as a whole, that (a) is included in the normal form of
   2.128 -packaging a Major Component, but which is not part of that Major
   2.129 -Component, and (b) serves only to enable use of the work with that
   2.130 -Major Component, or to implement a Standard Interface for which an
   2.131 -implementation is available to the public in source code form.  A
   2.132 -"Major Component", in this context, means a major essential component
   2.133 -(kernel, window system, and so on) of the specific operating system
   2.134 -(if any) on which the executable work runs, or a compiler used to
   2.135 -produce the work, or an object code interpreter used to run it.
   2.136 -
   2.137 -  The "Corresponding Source" for a work in object code form means all
   2.138 -the source code needed to generate, install, and (for an executable
   2.139 -work) run the object code and to modify the work, including scripts to
   2.140 -control those activities.  However, it does not include the work's
   2.141 -System Libraries, or general-purpose tools or generally available free
   2.142 -programs which are used unmodified in performing those activities but
   2.143 -which are not part of the work.  For example, Corresponding Source
   2.144 -includes interface definition files associated with source files for
   2.145 -the work, and the source code for shared libraries and dynamically
   2.146 -linked subprograms that the work is specifically designed to require,
   2.147 -such as by intimate data communication or control flow between those
   2.148 -subprograms and other parts of the work.
   2.149 -
   2.150 -  The Corresponding Source need not include anything that users
   2.151 -can regenerate automatically from other parts of the Corresponding
   2.152 -Source.
   2.153 -
   2.154 -  The Corresponding Source for a work in source code form is that
   2.155 -same work.
   2.156 -
   2.157 -  2. Basic Permissions.
   2.158 -
   2.159 -  All rights granted under this License are granted for the term of
   2.160 -copyright on the Program, and are irrevocable provided the stated
   2.161 -conditions are met.  This License explicitly affirms your unlimited
   2.162 -permission to run the unmodified Program.  The output from running a
   2.163 -covered work is covered by this License only if the output, given its
   2.164 -content, constitutes a covered work.  This License acknowledges your
   2.165 -rights of fair use or other equivalent, as provided by copyright law.
   2.166 -
   2.167 -  You may make, run and propagate covered works that you do not
   2.168 -convey, without conditions so long as your license otherwise remains
   2.169 -in force.  You may convey covered works to others for the sole purpose
   2.170 -of having them make modifications exclusively for you, or provide you
   2.171 -with facilities for running those works, provided that you comply with
   2.172 -the terms of this License in conveying all material for which you do
   2.173 -not control copyright.  Those thus making or running the covered works
   2.174 -for you must do so exclusively on your behalf, under your direction
   2.175 -and control, on terms that prohibit them from making any copies of
   2.176 -your copyrighted material outside their relationship with you.
   2.177 -
   2.178 -  Conveying under any other circumstances is permitted solely under
   2.179 -the conditions stated below.  Sublicensing is not allowed; section 10
   2.180 -makes it unnecessary.
   2.181 -
   2.182 -  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
   2.183 -
   2.184 -  No covered work shall be deemed part of an effective technological
   2.185 -measure under any applicable law fulfilling obligations under article
   2.186 -11 of the WIPO copyright treaty adopted on 20 December 1996, or
   2.187 -similar laws prohibiting or restricting circumvention of such
   2.188 -measures.
   2.189 -
   2.190 -  When you convey a covered work, you waive any legal power to forbid
   2.191 -circumvention of technological measures to the extent such circumvention
   2.192 -is effected by exercising rights under this License with respect to
   2.193 -the covered work, and you disclaim any intention to limit operation or
   2.194 -modification of the work as a means of enforcing, against the work's
   2.195 -users, your or third parties' legal rights to forbid circumvention of
   2.196 -technological measures.
   2.197 -
   2.198 -  4. Conveying Verbatim Copies.
   2.199 -
   2.200 -  You may convey verbatim copies of the Program's source code as you
   2.201 -receive it, in any medium, provided that you conspicuously and
   2.202 -appropriately publish on each copy an appropriate copyright notice;
   2.203 -keep intact all notices stating that this License and any
   2.204 -non-permissive terms added in accord with section 7 apply to the code;
   2.205 -keep intact all notices of the absence of any warranty; and give all
   2.206 -recipients a copy of this License along with the Program.
   2.207 -
   2.208 -  You may charge any price or no price for each copy that you convey,
   2.209 -and you may offer support or warranty protection for a fee.
   2.210 -
   2.211 -  5. Conveying Modified Source Versions.
   2.212 -
   2.213 -  You may convey a work based on the Program, or the modifications to
   2.214 -produce it from the Program, in the form of source code under the
   2.215 -terms of section 4, provided that you also meet all of these conditions:
   2.216 -
   2.217 -    a) The work must carry prominent notices stating that you modified
   2.218 -    it, and giving a relevant date.
   2.219 -
   2.220 -    b) The work must carry prominent notices stating that it is
   2.221 -    released under this License and any conditions added under section
   2.222 -    7.  This requirement modifies the requirement in section 4 to
   2.223 -    "keep intact all notices".
   2.224 -
   2.225 -    c) You must license the entire work, as a whole, under this
   2.226 -    License to anyone who comes into possession of a copy.  This
   2.227 -    License will therefore apply, along with any applicable section 7
   2.228 -    additional terms, to the whole of the work, and all its parts,
   2.229 -    regardless of how they are packaged.  This License gives no
   2.230 -    permission to license the work in any other way, but it does not
   2.231 -    invalidate such permission if you have separately received it.
   2.232 -
   2.233 -    d) If the work has interactive user interfaces, each must display
   2.234 -    Appropriate Legal Notices; however, if the Program has interactive
   2.235 -    interfaces that do not display Appropriate Legal Notices, your
   2.236 -    work need not make them do so.
   2.237 -
   2.238 -  A compilation of a covered work with other separate and independent
   2.239 -works, which are not by their nature extensions of the covered work,
   2.240 -and which are not combined with it such as to form a larger program,
   2.241 -in or on a volume of a storage or distribution medium, is called an
   2.242 -"aggregate" if the compilation and its resulting copyright are not
   2.243 -used to limit the access or legal rights of the compilation's users
   2.244 -beyond what the individual works permit.  Inclusion of a covered work
   2.245 -in an aggregate does not cause this License to apply to the other
   2.246 -parts of the aggregate.
   2.247 -
   2.248 -  6. Conveying Non-Source Forms.
   2.249 -
   2.250 -  You may convey a covered work in object code form under the terms
   2.251 -of sections 4 and 5, provided that you also convey the
   2.252 -machine-readable Corresponding Source under the terms of this License,
   2.253 -in one of these ways:
   2.254 -
   2.255 -    a) Convey the object code in, or embodied in, a physical product
   2.256 -    (including a physical distribution medium), accompanied by the
   2.257 -    Corresponding Source fixed on a durable physical medium
   2.258 -    customarily used for software interchange.
   2.259 -
   2.260 -    b) Convey the object code in, or embodied in, a physical product
   2.261 -    (including a physical distribution medium), accompanied by a
   2.262 -    written offer, valid for at least three years and valid for as
   2.263 -    long as you offer spare parts or customer support for that product
   2.264 -    model, to give anyone who possesses the object code either (1) a
   2.265 -    copy of the Corresponding Source for all the software in the
   2.266 -    product that is covered by this License, on a durable physical
   2.267 -    medium customarily used for software interchange, for a price no
   2.268 -    more than your reasonable cost of physically performing this
   2.269 -    conveying of source, or (2) access to copy the
   2.270 -    Corresponding Source from a network server at no charge.
   2.271 -
   2.272 -    c) Convey individual copies of the object code with a copy of the
   2.273 -    written offer to provide the Corresponding Source.  This
   2.274 -    alternative is allowed only occasionally and noncommercially, and
   2.275 -    only if you received the object code with such an offer, in accord
   2.276 -    with subsection 6b.
   2.277 -
   2.278 -    d) Convey the object code by offering access from a designated
   2.279 -    place (gratis or for a charge), and offer equivalent access to the
   2.280 -    Corresponding Source in the same way through the same place at no
   2.281 -    further charge.  You need not require recipients to copy the
   2.282 -    Corresponding Source along with the object code.  If the place to
   2.283 -    copy the object code is a network server, the Corresponding Source
   2.284 -    may be on a different server (operated by you or a third party)
   2.285 -    that supports equivalent copying facilities, provided you maintain
   2.286 -    clear directions next to the object code saying where to find the
   2.287 -    Corresponding Source.  Regardless of what server hosts the
   2.288 -    Corresponding Source, you remain obligated to ensure that it is
   2.289 -    available for as long as needed to satisfy these requirements.
   2.290 -
   2.291 -    e) Convey the object code using peer-to-peer transmission, provided
   2.292 -    you inform other peers where the object code and Corresponding
   2.293 -    Source of the work are being offered to the general public at no
   2.294 -    charge under subsection 6d.
   2.295 -
   2.296 -  A separable portion of the object code, whose source code is excluded
   2.297 -from the Corresponding Source as a System Library, need not be
   2.298 -included in conveying the object code work.
   2.299 -
   2.300 -  A "User Product" is either (1) a "consumer product", which means any
   2.301 -tangible personal property which is normally used for personal, family,
   2.302 -or household purposes, or (2) anything designed or sold for incorporation
   2.303 -into a dwelling.  In determining whether a product is a consumer product,
   2.304 -doubtful cases shall be resolved in favor of coverage.  For a particular
   2.305 -product received by a particular user, "normally used" refers to a
   2.306 -typical or common use of that class of product, regardless of the status
   2.307 -of the particular user or of the way in which the particular user
   2.308 -actually uses, or expects or is expected to use, the product.  A product
   2.309 -is a consumer product regardless of whether the product has substantial
   2.310 -commercial, industrial or non-consumer uses, unless such uses represent
   2.311 -the only significant mode of use of the product.
   2.312 -
   2.313 -  "Installation Information" for a User Product means any methods,
   2.314 -procedures, authorization keys, or other information required to install
   2.315 -and execute modified versions of a covered work in that User Product from
   2.316 -a modified version of its Corresponding Source.  The information must
   2.317 -suffice to ensure that the continued functioning of the modified object
   2.318 -code is in no case prevented or interfered with solely because
   2.319 -modification has been made.
   2.320 -
   2.321 -  If you convey an object code work under this section in, or with, or
   2.322 -specifically for use in, a User Product, and the conveying occurs as
   2.323 -part of a transaction in which the right of possession and use of the
   2.324 -User Product is transferred to the recipient in perpetuity or for a
   2.325 -fixed term (regardless of how the transaction is characterized), the
   2.326 -Corresponding Source conveyed under this section must be accompanied
   2.327 -by the Installation Information.  But this requirement does not apply
   2.328 -if neither you nor any third party retains the ability to install
   2.329 -modified object code on the User Product (for example, the work has
   2.330 -been installed in ROM).
   2.331 -
   2.332 -  The requirement to provide Installation Information does not include a
   2.333 -requirement to continue to provide support service, warranty, or updates
   2.334 -for a work that has been modified or installed by the recipient, or for
   2.335 -the User Product in which it has been modified or installed.  Access to a
   2.336 -network may be denied when the modification itself materially and
   2.337 -adversely affects the operation of the network or violates the rules and
   2.338 -protocols for communication across the network.
   2.339 -
   2.340 -  Corresponding Source conveyed, and Installation Information provided,
   2.341 -in accord with this section must be in a format that is publicly
   2.342 -documented (and with an implementation available to the public in
   2.343 -source code form), and must require no special password or key for
   2.344 -unpacking, reading or copying.
   2.345 -
   2.346 -  7. Additional Terms.
   2.347 -
   2.348 -  "Additional permissions" are terms that supplement the terms of this
   2.349 -License by making exceptions from one or more of its conditions.
   2.350 -Additional permissions that are applicable to the entire Program shall
   2.351 -be treated as though they were included in this License, to the extent
   2.352 -that they are valid under applicable law.  If additional permissions
   2.353 -apply only to part of the Program, that part may be used separately
   2.354 -under those permissions, but the entire Program remains governed by
   2.355 -this License without regard to the additional permissions.
   2.356 -
   2.357 -  When you convey a copy of a covered work, you may at your option
   2.358 -remove any additional permissions from that copy, or from any part of
   2.359 -it.  (Additional permissions may be written to require their own
   2.360 -removal in certain cases when you modify the work.)  You may place
   2.361 -additional permissions on material, added by you to a covered work,
   2.362 -for which you have or can give appropriate copyright permission.
   2.363 -
   2.364 -  Notwithstanding any other provision of this License, for material you
   2.365 -add to a covered work, you may (if authorized by the copyright holders of
   2.366 -that material) supplement the terms of this License with terms:
   2.367 -
   2.368 -    a) Disclaiming warranty or limiting liability differently from the
   2.369 -    terms of sections 15 and 16 of this License; or
   2.370 -
   2.371 -    b) Requiring preservation of specified reasonable legal notices or
   2.372 -    author attributions in that material or in the Appropriate Legal
   2.373 -    Notices displayed by works containing it; or
   2.374 -
   2.375 -    c) Prohibiting misrepresentation of the origin of that material, or
   2.376 -    requiring that modified versions of such material be marked in
   2.377 -    reasonable ways as different from the original version; or
   2.378 -
   2.379 -    d) Limiting the use for publicity purposes of names of licensors or
   2.380 -    authors of the material; or
   2.381 -
   2.382 -    e) Declining to grant rights under trademark law for use of some
   2.383 -    trade names, trademarks, or service marks; or
   2.384 -
   2.385 -    f) Requiring indemnification of licensors and authors of that
   2.386 -    material by anyone who conveys the material (or modified versions of
   2.387 -    it) with contractual assumptions of liability to the recipient, for
   2.388 -    any liability that these contractual assumptions directly impose on
   2.389 -    those licensors and authors.
   2.390 -
   2.391 -  All other non-permissive additional terms are considered "further
   2.392 -restrictions" within the meaning of section 10.  If the Program as you
   2.393 -received it, or any part of it, contains a notice stating that it is
   2.394 -governed by this License along with a term that is a further
   2.395 -restriction, you may remove that term.  If a license document contains
   2.396 -a further restriction but permits relicensing or conveying under this
   2.397 -License, you may add to a covered work material governed by the terms
   2.398 -of that license document, provided that the further restriction does
   2.399 -not survive such relicensing or conveying.
   2.400 -
   2.401 -  If you add terms to a covered work in accord with this section, you
   2.402 -must place, in the relevant source files, a statement of the
   2.403 -additional terms that apply to those files, or a notice indicating
   2.404 -where to find the applicable terms.
   2.405 -
   2.406 -  Additional terms, permissive or non-permissive, may be stated in the
   2.407 -form of a separately written license, or stated as exceptions;
   2.408 -the above requirements apply either way.
   2.409 -
   2.410 -  8. Termination.
   2.411 -
   2.412 -  You may not propagate or modify a covered work except as expressly
   2.413 -provided under this License.  Any attempt otherwise to propagate or
   2.414 -modify it is void, and will automatically terminate your rights under
   2.415 -this License (including any patent licenses granted under the third
   2.416 -paragraph of section 11).
   2.417 -
   2.418 -  However, if you cease all violation of this License, then your
   2.419 -license from a particular copyright holder is reinstated (a)
   2.420 -provisionally, unless and until the copyright holder explicitly and
   2.421 -finally terminates your license, and (b) permanently, if the copyright
   2.422 -holder fails to notify you of the violation by some reasonable means
   2.423 -prior to 60 days after the cessation.
   2.424 -
   2.425 -  Moreover, your license from a particular copyright holder is
   2.426 -reinstated permanently if the copyright holder notifies you of the
   2.427 -violation by some reasonable means, this is the first time you have
   2.428 -received notice of violation of this License (for any work) from that
   2.429 -copyright holder, and you cure the violation prior to 30 days after
   2.430 -your receipt of the notice.
   2.431 -
   2.432 -  Termination of your rights under this section does not terminate the
   2.433 -licenses of parties who have received copies or rights from you under
   2.434 -this License.  If your rights have been terminated and not permanently
   2.435 -reinstated, you do not qualify to receive new licenses for the same
   2.436 -material under section 10.
   2.437 -
   2.438 -  9. Acceptance Not Required for Having Copies.
   2.439 -
   2.440 -  You are not required to accept this License in order to receive or
   2.441 -run a copy of the Program.  Ancillary propagation of a covered work
   2.442 -occurring solely as a consequence of using peer-to-peer transmission
   2.443 -to receive a copy likewise does not require acceptance.  However,
   2.444 -nothing other than this License grants you permission to propagate or
   2.445 -modify any covered work.  These actions infringe copyright if you do
   2.446 -not accept this License.  Therefore, by modifying or propagating a
   2.447 -covered work, you indicate your acceptance of this License to do so.
   2.448 -
   2.449 -  10. Automatic Licensing of Downstream Recipients.
   2.450 -
   2.451 -  Each time you convey a covered work, the recipient automatically
   2.452 -receives a license from the original licensors, to run, modify and
   2.453 -propagate that work, subject to this License.  You are not responsible
   2.454 -for enforcing compliance by third parties with this License.
   2.455 -
   2.456 -  An "entity transaction" is a transaction transferring control of an
   2.457 -organization, or substantially all assets of one, or subdividing an
   2.458 -organization, or merging organizations.  If propagation of a covered
   2.459 -work results from an entity transaction, each party to that
   2.460 -transaction who receives a copy of the work also receives whatever
   2.461 -licenses to the work the party's predecessor in interest had or could
   2.462 -give under the previous paragraph, plus a right to possession of the
   2.463 -Corresponding Source of the work from the predecessor in interest, if
   2.464 -the predecessor has it or can get it with reasonable efforts.
   2.465 -
   2.466 -  You may not impose any further restrictions on the exercise of the
   2.467 -rights granted or affirmed under this License.  For example, you may
   2.468 -not impose a license fee, royalty, or other charge for exercise of
   2.469 -rights granted under this License, and you may not initiate litigation
   2.470 -(including a cross-claim or counterclaim in a lawsuit) alleging that
   2.471 -any patent claim is infringed by making, using, selling, offering for
   2.472 -sale, or importing the Program or any portion of it.
   2.473 -
   2.474 -  11. Patents.
   2.475 -
   2.476 -  A "contributor" is a copyright holder who authorizes use under this
   2.477 -License of the Program or a work on which the Program is based.  The
   2.478 -work thus licensed is called the contributor's "contributor version".
   2.479 -
   2.480 -  A contributor's "essential patent claims" are all patent claims
   2.481 -owned or controlled by the contributor, whether already acquired or
   2.482 -hereafter acquired, that would be infringed by some manner, permitted
   2.483 -by this License, of making, using, or selling its contributor version,
   2.484 -but do not include claims that would be infringed only as a
   2.485 -consequence of further modification of the contributor version.  For
   2.486 -purposes of this definition, "control" includes the right to grant
   2.487 -patent sublicenses in a manner consistent with the requirements of
   2.488 -this License.
   2.489 -
   2.490 -  Each contributor grants you a non-exclusive, worldwide, royalty-free
   2.491 -patent license under the contributor's essential patent claims, to
   2.492 -make, use, sell, offer for sale, import and otherwise run, modify and
   2.493 -propagate the contents of its contributor version.
   2.494 -
   2.495 -  In the following three paragraphs, a "patent license" is any express
   2.496 -agreement or commitment, however denominated, not to enforce a patent
   2.497 -(such as an express permission to practice a patent or covenant not to
   2.498 -sue for patent infringement).  To "grant" such a patent license to a
   2.499 -party means to make such an agreement or commitment not to enforce a
   2.500 -patent against the party.
   2.501 -
   2.502 -  If you convey a covered work, knowingly relying on a patent license,
   2.503 -and the Corresponding Source of the work is not available for anyone
   2.504 -to copy, free of charge and under the terms of this License, through a
   2.505 -publicly available network server or other readily accessible means,
   2.506 -then you must either (1) cause the Corresponding Source to be so
   2.507 -available, or (2) arrange to deprive yourself of the benefit of the
   2.508 -patent license for this particular work, or (3) arrange, in a manner
   2.509 -consistent with the requirements of this License, to extend the patent
   2.510 -license to downstream recipients.  "Knowingly relying" means you have
   2.511 -actual knowledge that, but for the patent license, your conveying the
   2.512 -covered work in a country, or your recipient's use of the covered work
   2.513 -in a country, would infringe one or more identifiable patents in that
   2.514 -country that you have reason to believe are valid.
   2.515 -
   2.516 -  If, pursuant to or in connection with a single transaction or
   2.517 -arrangement, you convey, or propagate by procuring conveyance of, a
   2.518 -covered work, and grant a patent license to some of the parties
   2.519 -receiving the covered work authorizing them to use, propagate, modify
   2.520 -or convey a specific copy of the covered work, then the patent license
   2.521 -you grant is automatically extended to all recipients of the covered
   2.522 -work and works based on it.
   2.523 -
   2.524 -  A patent license is "discriminatory" if it does not include within
   2.525 -the scope of its coverage, prohibits the exercise of, or is
   2.526 -conditioned on the non-exercise of one or more of the rights that are
   2.527 -specifically granted under this License.  You may not convey a covered
   2.528 -work if you are a party to an arrangement with a third party that is
   2.529 -in the business of distributing software, under which you make payment
   2.530 -to the third party based on the extent of your activity of conveying
   2.531 -the work, and under which the third party grants, to any of the
   2.532 -parties who would receive the covered work from you, a discriminatory
   2.533 -patent license (a) in connection with copies of the covered work
   2.534 -conveyed by you (or copies made from those copies), or (b) primarily
   2.535 -for and in connection with specific products or compilations that
   2.536 -contain the covered work, unless you entered into that arrangement,
   2.537 -or that patent license was granted, prior to 28 March 2007.
   2.538 -
   2.539 -  Nothing in this License shall be construed as excluding or limiting
   2.540 -any implied license or other defenses to infringement that may
   2.541 -otherwise be available to you under applicable patent law.
   2.542 -
   2.543 -  12. No Surrender of Others' Freedom.
   2.544 -
   2.545 -  If conditions are imposed on you (whether by court order, agreement or
   2.546 -otherwise) that contradict the conditions of this License, they do not
   2.547 -excuse you from the conditions of this License.  If you cannot convey a
   2.548 -covered work so as to satisfy simultaneously your obligations under this
   2.549 -License and any other pertinent obligations, then as a consequence you may
   2.550 -not convey it at all.  For example, if you agree to terms that obligate you
   2.551 -to collect a royalty for further conveying from those to whom you convey
   2.552 -the Program, the only way you could satisfy both those terms and this
   2.553 -License would be to refrain entirely from conveying the Program.
   2.554 -
   2.555 -  13. Use with the GNU Affero General Public License.
   2.556 -
   2.557 -  Notwithstanding any other provision of this License, you have
   2.558 -permission to link or combine any covered work with a work licensed
   2.559 -under version 3 of the GNU Affero General Public License into a single
   2.560 -combined work, and to convey the resulting work.  The terms of this
   2.561 -License will continue to apply to the part which is the covered work,
   2.562 -but the special requirements of the GNU Affero General Public License,
   2.563 -section 13, concerning interaction through a network will apply to the
   2.564 -combination as such.
   2.565 -
   2.566 -  14. Revised Versions of this License.
   2.567 -
   2.568 -  The Free Software Foundation may publish revised and/or new versions of
   2.569 -the GNU General Public License from time to time.  Such new versions will
   2.570 -be similar in spirit to the present version, but may differ in detail to
   2.571 -address new problems or concerns.
   2.572 -
   2.573 -  Each version is given a distinguishing version number.  If the
   2.574 -Program specifies that a certain numbered version of the GNU General
   2.575 -Public License "or any later version" applies to it, you have the
   2.576 -option of following the terms and conditions either of that numbered
   2.577 -version or of any later version published by the Free Software
   2.578 -Foundation.  If the Program does not specify a version number of the
   2.579 -GNU General Public License, you may choose any version ever published
   2.580 -by the Free Software Foundation.
   2.581 -
   2.582 -  If the Program specifies that a proxy can decide which future
   2.583 -versions of the GNU General Public License can be used, that proxy's
   2.584 -public statement of acceptance of a version permanently authorizes you
   2.585 -to choose that version for the Program.
   2.586 -
   2.587 -  Later license versions may give you additional or different
   2.588 -permissions.  However, no additional obligations are imposed on any
   2.589 -author or copyright holder as a result of your choosing to follow a
   2.590 -later version.
   2.591 -
   2.592 -  15. Disclaimer of Warranty.
   2.593 -
   2.594 -  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
   2.595 -APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
   2.596 -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
   2.597 -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
   2.598 -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   2.599 -PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
   2.600 -IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
   2.601 -ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
   2.602 -
   2.603 -  16. Limitation of Liability.
   2.604 -
   2.605 -  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
   2.606 -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
   2.607 -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
   2.608 -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
   2.609 -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
   2.610 -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
   2.611 -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
   2.612 -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
   2.613 -SUCH DAMAGES.
   2.614 -
   2.615 -  17. Interpretation of Sections 15 and 16.
   2.616 -
   2.617 -  If the disclaimer of warranty and limitation of liability provided
   2.618 -above cannot be given local legal effect according to their terms,
   2.619 -reviewing courts shall apply local law that most closely approximates
   2.620 -an absolute waiver of all civil liability in connection with the
   2.621 -Program, unless a warranty or assumption of liability accompanies a
   2.622 -copy of the Program in return for a fee.
   2.623 -
   2.624 -                     END OF TERMS AND CONDITIONS
   2.625 -
   2.626 -            How to Apply These Terms to Your New Programs
   2.627 -
   2.628 -  If you develop a new program, and you want it to be of the greatest
   2.629 -possible use to the public, the best way to achieve this is to make it
   2.630 -free software which everyone can redistribute and change under these terms.
   2.631 -
   2.632 -  To do so, attach the following notices to the program.  It is safest
   2.633 -to attach them to the start of each source file to most effectively
   2.634 -state the exclusion of warranty; and each file should have at least
   2.635 -the "copyright" line and a pointer to where the full notice is found.
   2.636 -
   2.637 -    <one line to give the program's name and a brief idea of what it does.>
   2.638 -    Copyright (C) <year>  <name of author>
   2.639 -
   2.640 -    This program is free software: you can redistribute it and/or modify
   2.641 -    it under the terms of the GNU General Public License as published by
   2.642 -    the Free Software Foundation, either version 3 of the License, or
   2.643 -    (at your option) any later version.
   2.644 -
   2.645 -    This program is distributed in the hope that it will be useful,
   2.646 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
   2.647 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   2.648 -    GNU General Public License for more details.
   2.649 -
   2.650 -    You should have received a copy of the GNU General Public License
   2.651 -    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   2.652 -
   2.653 -Also add information on how to contact you by electronic and paper mail.
   2.654 -
   2.655 -  If the program does terminal interaction, make it output a short
   2.656 -notice like this when it starts in an interactive mode:
   2.657 -
   2.658 -    <program>  Copyright (C) <year>  <name of author>
   2.659 -    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
   2.660 -    This is free software, and you are welcome to redistribute it
   2.661 -    under certain conditions; type `show c' for details.
   2.662 -
   2.663 -The hypothetical commands `show w' and `show c' should show the appropriate
   2.664 -parts of the General Public License.  Of course, your program's commands
   2.665 -might be different; for a GUI interface, you would use an "about box".
   2.666 -
   2.667 -  You should also get your employer (if you work as a programmer) or school,
   2.668 -if any, to sign a "copyright disclaimer" for the program, if necessary.
   2.669 -For more information on this, and how to apply and follow the GNU GPL, see
   2.670 -<http://www.gnu.org/licenses/>.
   2.671 -
   2.672 -  The GNU General Public License does not permit incorporating your program
   2.673 -into proprietary programs.  If your program is a subroutine library, you
   2.674 -may consider it more useful to permit linking proprietary applications with
   2.675 -the library.  If this is what you want to do, use the GNU Lesser General
   2.676 -Public License instead of this License.  But first, please read
   2.677 -<http://www.gnu.org/philosophy/why-not-lgpl.html>.
     3.1 --- a/INSTALL	Sat Mar 03 12:06:10 2012 -0600
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,365 +0,0 @@
     3.4 -Installation Instructions
     3.5 -*************************
     3.6 -
     3.7 -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
     3.8 -2006, 2007, 2008, 2009 Free Software Foundation, Inc.
     3.9 -
    3.10 -   Copying and distribution of this file, with or without modification,
    3.11 -are permitted in any medium without royalty provided the copyright
    3.12 -notice and this notice are preserved.  This file is offered as-is,
    3.13 -without warranty of any kind.
    3.14 -
    3.15 -Basic Installation
    3.16 -==================
    3.17 -
    3.18 -   Briefly, the shell commands `./configure; make; make install' should
    3.19 -configure, build, and install this package.  The following
    3.20 -more-detailed instructions are generic; see the `README' file for
    3.21 -instructions specific to this package.  Some packages provide this
    3.22 -`INSTALL' file but do not implement all of the features documented
    3.23 -below.  The lack of an optional feature in a given package is not
    3.24 -necessarily a bug.  More recommendations for GNU packages can be found
    3.25 -in *note Makefile Conventions: (standards)Makefile Conventions.
    3.26 -
    3.27 -   The `configure' shell script attempts to guess correct values for
    3.28 -various system-dependent variables used during compilation.  It uses
    3.29 -those values to create a `Makefile' in each directory of the package.
    3.30 -It may also create one or more `.h' files containing system-dependent
    3.31 -definitions.  Finally, it creates a shell script `config.status' that
    3.32 -you can run in the future to recreate the current configuration, and a
    3.33 -file `config.log' containing compiler output (useful mainly for
    3.34 -debugging `configure').
    3.35 -
    3.36 -   It can also use an optional file (typically called `config.cache'
    3.37 -and enabled with `--cache-file=config.cache' or simply `-C') that saves
    3.38 -the results of its tests to speed up reconfiguring.  Caching is
    3.39 -disabled by default to prevent problems with accidental use of stale
    3.40 -cache files.
    3.41 -
    3.42 -   If you need to do unusual things to compile the package, please try
    3.43 -to figure out how `configure' could check whether to do them, and mail
    3.44 -diffs or instructions to the address given in the `README' so they can
    3.45 -be considered for the next release.  If you are using the cache, and at
    3.46 -some point `config.cache' contains results you don't want to keep, you
    3.47 -may remove or edit it.
    3.48 -
    3.49 -   The file `configure.ac' (or `configure.in') is used to create
    3.50 -`configure' by a program called `autoconf'.  You need `configure.ac' if
    3.51 -you want to change it or regenerate `configure' using a newer version
    3.52 -of `autoconf'.
    3.53 -
    3.54 -   The simplest way to compile this package is:
    3.55 -
    3.56 -  1. `cd' to the directory containing the package's source code and type
    3.57 -     `./configure' to configure the package for your system.
    3.58 -
    3.59 -     Running `configure' might take a while.  While running, it prints
    3.60 -     some messages telling which features it is checking for.
    3.61 -
    3.62 -  2. Type `make' to compile the package.
    3.63 -
    3.64 -  3. Optionally, type `make check' to run any self-tests that come with
    3.65 -     the package, generally using the just-built uninstalled binaries.
    3.66 -
    3.67 -  4. Type `make install' to install the programs and any data files and
    3.68 -     documentation.  When installing into a prefix owned by root, it is
    3.69 -     recommended that the package be configured and built as a regular
    3.70 -     user, and only the `make install' phase executed with root
    3.71 -     privileges.
    3.72 -
    3.73 -  5. Optionally, type `make installcheck' to repeat any self-tests, but
    3.74 -     this time using the binaries in their final installed location.
    3.75 -     This target does not install anything.  Running this target as a
    3.76 -     regular user, particularly if the prior `make install' required
    3.77 -     root privileges, verifies that the installation completed
    3.78 -     correctly.
    3.79 -
    3.80 -  6. You can remove the program binaries and object files from the
    3.81 -     source code directory by typing `make clean'.  To also remove the
    3.82 -     files that `configure' created (so you can compile the package for
    3.83 -     a different kind of computer), type `make distclean'.  There is
    3.84 -     also a `make maintainer-clean' target, but that is intended mainly
    3.85 -     for the package's developers.  If you use it, you may have to get
    3.86 -     all sorts of other programs in order to regenerate files that came
    3.87 -     with the distribution.
    3.88 -
    3.89 -  7. Often, you can also type `make uninstall' to remove the installed
    3.90 -     files again.  In practice, not all packages have tested that
    3.91 -     uninstallation works correctly, even though it is required by the
    3.92 -     GNU Coding Standards.
    3.93 -
    3.94 -  8. Some packages, particularly those that use Automake, provide `make
    3.95 -     distcheck', which can by used by developers to test that all other
    3.96 -     targets like `make install' and `make uninstall' work correctly.
    3.97 -     This target is generally not run by end users.
    3.98 -
    3.99 -Compilers and Options
   3.100 -=====================
   3.101 -
   3.102 -   Some systems require unusual options for compilation or linking that
   3.103 -the `configure' script does not know about.  Run `./configure --help'
   3.104 -for details on some of the pertinent environment variables.
   3.105 -
   3.106 -   You can give `configure' initial values for configuration parameters
   3.107 -by setting variables in the command line or in the environment.  Here
   3.108 -is an example:
   3.109 -
   3.110 -     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
   3.111 -
   3.112 -   *Note Defining Variables::, for more details.
   3.113 -
   3.114 -Compiling For Multiple Architectures
   3.115 -====================================
   3.116 -
   3.117 -   You can compile the package for more than one kind of computer at the
   3.118 -same time, by placing the object files for each architecture in their
   3.119 -own directory.  To do this, you can use GNU `make'.  `cd' to the
   3.120 -directory where you want the object files and executables to go and run
   3.121 -the `configure' script.  `configure' automatically checks for the
   3.122 -source code in the directory that `configure' is in and in `..'.  This
   3.123 -is known as a "VPATH" build.
   3.124 -
   3.125 -   With a non-GNU `make', it is safer to compile the package for one
   3.126 -architecture at a time in the source code directory.  After you have
   3.127 -installed the package for one architecture, use `make distclean' before
   3.128 -reconfiguring for another architecture.
   3.129 -
   3.130 -   On MacOS X 10.5 and later systems, you can create libraries and
   3.131 -executables that work on multiple system types--known as "fat" or
   3.132 -"universal" binaries--by specifying multiple `-arch' options to the
   3.133 -compiler but only a single `-arch' option to the preprocessor.  Like
   3.134 -this:
   3.135 -
   3.136 -     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
   3.137 -                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
   3.138 -                 CPP="gcc -E" CXXCPP="g++ -E"
   3.139 -
   3.140 -   This is not guaranteed to produce working output in all cases, you
   3.141 -may have to build one architecture at a time and combine the results
   3.142 -using the `lipo' tool if you have problems.
   3.143 -
   3.144 -Installation Names
   3.145 -==================
   3.146 -
   3.147 -   By default, `make install' installs the package's commands under
   3.148 -`/usr/local/bin', include files under `/usr/local/include', etc.  You
   3.149 -can specify an installation prefix other than `/usr/local' by giving
   3.150 -`configure' the option `--prefix=PREFIX', where PREFIX must be an
   3.151 -absolute file name.
   3.152 -
   3.153 -   You can specify separate installation prefixes for
   3.154 -architecture-specific files and architecture-independent files.  If you
   3.155 -pass the option `--exec-prefix=PREFIX' to `configure', the package uses
   3.156 -PREFIX as the prefix for installing programs and libraries.
   3.157 -Documentation and other data files still use the regular prefix.
   3.158 -
   3.159 -   In addition, if you use an unusual directory layout you can give
   3.160 -options like `--bindir=DIR' to specify different values for particular
   3.161 -kinds of files.  Run `configure --help' for a list of the directories
   3.162 -you can set and what kinds of files go in them.  In general, the
   3.163 -default for these options is expressed in terms of `${prefix}', so that
   3.164 -specifying just `--prefix' will affect all of the other directory
   3.165 -specifications that were not explicitly provided.
   3.166 -
   3.167 -   The most portable way to affect installation locations is to pass the
   3.168 -correct locations to `configure'; however, many packages provide one or
   3.169 -both of the following shortcuts of passing variable assignments to the
   3.170 -`make install' command line to change installation locations without
   3.171 -having to reconfigure or recompile.
   3.172 -
   3.173 -   The first method involves providing an override variable for each
   3.174 -affected directory.  For example, `make install
   3.175 -prefix=/alternate/directory' will choose an alternate location for all
   3.176 -directory configuration variables that were expressed in terms of
   3.177 -`${prefix}'.  Any directories that were specified during `configure',
   3.178 -but not in terms of `${prefix}', must each be overridden at install
   3.179 -time for the entire installation to be relocated.  The approach of
   3.180 -makefile variable overrides for each directory variable is required by
   3.181 -the GNU Coding Standards, and ideally causes no recompilation.
   3.182 -However, some platforms have known limitations with the semantics of
   3.183 -shared libraries that end up requiring recompilation when using this
   3.184 -method, particularly noticeable in packages that use GNU Libtool.
   3.185 -
   3.186 -   The second method involves providing the `DESTDIR' variable.  For
   3.187 -example, `make install DESTDIR=/alternate/directory' will prepend
   3.188 -`/alternate/directory' before all installation names.  The approach of
   3.189 -`DESTDIR' overrides is not required by the GNU Coding Standards, and
   3.190 -does not work on platforms that have drive letters.  On the other hand,
   3.191 -it does better at avoiding recompilation issues, and works well even
   3.192 -when some directory options were not specified in terms of `${prefix}'
   3.193 -at `configure' time.
   3.194 -
   3.195 -Optional Features
   3.196 -=================
   3.197 -
   3.198 -   If the package supports it, you can cause programs to be installed
   3.199 -with an extra prefix or suffix on their names by giving `configure' the
   3.200 -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
   3.201 -
   3.202 -   Some packages pay attention to `--enable-FEATURE' options to
   3.203 -`configure', where FEATURE indicates an optional part of the package.
   3.204 -They may also pay attention to `--with-PACKAGE' options, where PACKAGE
   3.205 -is something like `gnu-as' or `x' (for the X Window System).  The
   3.206 -`README' should mention any `--enable-' and `--with-' options that the
   3.207 -package recognizes.
   3.208 -
   3.209 -   For packages that use the X Window System, `configure' can usually
   3.210 -find the X include and library files automatically, but if it doesn't,
   3.211 -you can use the `configure' options `--x-includes=DIR' and
   3.212 -`--x-libraries=DIR' to specify their locations.
   3.213 -
   3.214 -   Some packages offer the ability to configure how verbose the
   3.215 -execution of `make' will be.  For these packages, running `./configure
   3.216 ---enable-silent-rules' sets the default to minimal output, which can be
   3.217 -overridden with `make V=1'; while running `./configure
   3.218 ---disable-silent-rules' sets the default to verbose, which can be
   3.219 -overridden with `make V=0'.
   3.220 -
   3.221 -Particular systems
   3.222 -==================
   3.223 -
   3.224 -   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
   3.225 -CC is not installed, it is recommended to use the following options in
   3.226 -order to use an ANSI C compiler:
   3.227 -
   3.228 -     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
   3.229 -
   3.230 -and if that doesn't work, install pre-built binaries of GCC for HP-UX.
   3.231 -
   3.232 -   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
   3.233 -parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
   3.234 -a workaround.  If GNU CC is not installed, it is therefore recommended
   3.235 -to try
   3.236 -
   3.237 -     ./configure CC="cc"
   3.238 -
   3.239 -and if that doesn't work, try
   3.240 -
   3.241 -     ./configure CC="cc -nodtk"
   3.242 -
   3.243 -   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
   3.244 -directory contains several dysfunctional programs; working variants of
   3.245 -these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
   3.246 -in your `PATH', put it _after_ `/usr/bin'.
   3.247 -
   3.248 -   On Haiku, software installed for all users goes in `/boot/common',
   3.249 -not `/usr/local'.  It is recommended to use the following options:
   3.250 -
   3.251 -     ./configure --prefix=/boot/common
   3.252 -
   3.253 -Specifying the System Type
   3.254 -==========================
   3.255 -
   3.256 -   There may be some features `configure' cannot figure out
   3.257 -automatically, but needs to determine by the type of machine the package
   3.258 -will run on.  Usually, assuming the package is built to be run on the
   3.259 -_same_ architectures, `configure' can figure that out, but if it prints
   3.260 -a message saying it cannot guess the machine type, give it the
   3.261 -`--build=TYPE' option.  TYPE can either be a short name for the system
   3.262 -type, such as `sun4', or a canonical name which has the form:
   3.263 -
   3.264 -     CPU-COMPANY-SYSTEM
   3.265 -
   3.266 -where SYSTEM can have one of these forms:
   3.267 -
   3.268 -     OS
   3.269 -     KERNEL-OS
   3.270 -
   3.271 -   See the file `config.sub' for the possible values of each field.  If
   3.272 -`config.sub' isn't included in this package, then this package doesn't
   3.273 -need to know the machine type.
   3.274 -
   3.275 -   If you are _building_ compiler tools for cross-compiling, you should
   3.276 -use the option `--target=TYPE' to select the type of system they will
   3.277 -produce code for.
   3.278 -
   3.279 -   If you want to _use_ a cross compiler, that generates code for a
   3.280 -platform different from the build platform, you should specify the
   3.281 -"host" platform (i.e., that on which the generated programs will
   3.282 -eventually be run) with `--host=TYPE'.
   3.283 -
   3.284 -Sharing Defaults
   3.285 -================
   3.286 -
   3.287 -   If you want to set default values for `configure' scripts to share,
   3.288 -you can create a site shell script called `config.site' that gives
   3.289 -default values for variables like `CC', `cache_file', and `prefix'.
   3.290 -`configure' looks for `PREFIX/share/config.site' if it exists, then
   3.291 -`PREFIX/etc/config.site' if it exists.  Or, you can set the
   3.292 -`CONFIG_SITE' environment variable to the location of the site script.
   3.293 -A warning: not all `configure' scripts look for a site script.
   3.294 -
   3.295 -Defining Variables
   3.296 -==================
   3.297 -
   3.298 -   Variables not defined in a site shell script can be set in the
   3.299 -environment passed to `configure'.  However, some packages may run
   3.300 -configure again during the build, and the customized values of these
   3.301 -variables may be lost.  In order to avoid this problem, you should set
   3.302 -them in the `configure' command line, using `VAR=value'.  For example:
   3.303 -
   3.304 -     ./configure CC=/usr/local2/bin/gcc
   3.305 -
   3.306 -causes the specified `gcc' to be used as the C compiler (unless it is
   3.307 -overridden in the site shell script).
   3.308 -
   3.309 -Unfortunately, this technique does not work for `CONFIG_SHELL' due to
   3.310 -an Autoconf bug.  Until the bug is fixed you can use this workaround:
   3.311 -
   3.312 -     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
   3.313 -
   3.314 -`configure' Invocation
   3.315 -======================
   3.316 -
   3.317 -   `configure' recognizes the following options to control how it
   3.318 -operates.
   3.319 -
   3.320 -`--help'
   3.321 -`-h'
   3.322 -     Print a summary of all of the options to `configure', and exit.
   3.323 -
   3.324 -`--help=short'
   3.325 -`--help=recursive'
   3.326 -     Print a summary of the options unique to this package's
   3.327 -     `configure', and exit.  The `short' variant lists options used
   3.328 -     only in the top level, while the `recursive' variant lists options
   3.329 -     also present in any nested packages.
   3.330 -
   3.331 -`--version'
   3.332 -`-V'
   3.333 -     Print the version of Autoconf used to generate the `configure'
   3.334 -     script, and exit.
   3.335 -
   3.336 -`--cache-file=FILE'
   3.337 -     Enable the cache: use and save the results of the tests in FILE,
   3.338 -     traditionally `config.cache'.  FILE defaults to `/dev/null' to
   3.339 -     disable caching.
   3.340 -
   3.341 -`--config-cache'
   3.342 -`-C'
   3.343 -     Alias for `--cache-file=config.cache'.
   3.344 -
   3.345 -`--quiet'
   3.346 -`--silent'
   3.347 -`-q'
   3.348 -     Do not print messages saying which checks are being made.  To
   3.349 -     suppress all normal output, redirect it to `/dev/null' (any error
   3.350 -     messages will still be shown).
   3.351 -
   3.352 -`--srcdir=DIR'
   3.353 -     Look for the package's source code in directory DIR.  Usually
   3.354 -     `configure' can determine that directory automatically.
   3.355 -
   3.356 -`--prefix=DIR'
   3.357 -     Use DIR as the installation prefix.  *note Installation Names::
   3.358 -     for more details, including other options available for fine-tuning
   3.359 -     the installation locations.
   3.360 -
   3.361 -`--no-create'
   3.362 -`-n'
   3.363 -     Run the configure checks, but stop before creating any output
   3.364 -     files.
   3.365 -
   3.366 -`configure' also accepts some other, not widely useful, options.  Run
   3.367 -`configure --help' for more details.
   3.368 -
     4.1 --- a/configure.ac	Sat Mar 03 12:06:10 2012 -0600
     4.2 +++ b/configure.ac	Sun Mar 04 14:33:52 2012 -0600
     4.3 @@ -2,6 +2,10 @@
     4.4  
     4.5  AC_INIT([vba-rlm], [1.0])
     4.6  
     4.7 +AC_CONFIG_AUX_DIR([build-aux])
     4.8 +
     4.9 +AM_INIT_AUTOMAKE([foreign dist-bzip2])
    4.10 +
    4.11  dnl TODO: change this to gba.cpp or something
    4.12  AC_CONFIG_SRCDIR([src/lua/lopcodes.c])
    4.13  AC_CONFIG_HEADERS([config.h])
    4.14 @@ -12,6 +16,17 @@
    4.15  AC_PROG_CC
    4.16  AC_PROG_RANLIB
    4.17  
    4.18 +
    4.19 +
    4.20 +# SDL stuff 
    4.21 +SDL_VERSION=1.2.2
    4.22 +AM_PATH_SDL($SDL_VERSION,[
    4.23 +],[
    4.24 +AC_MSG_ERROR([*** Couldn't find SDL library (version >= $SDL_VERSION).])
    4.25 +])
    4.26 +
    4.27 +
    4.28 +
    4.29  # Checks for header files.
    4.30  AC_CHECK_HEADERS([limits.h locale.h stddef.h stdlib.h string.h unistd.h])
    4.31  
    4.32 @@ -35,9 +50,11 @@
    4.33  AC_CONFIG_FILES([Makefile 
    4.34  	         src/Makefile
    4.35                   src/lua/Makefile
    4.36 -		 src/gb/Makefile])
    4.37 +		 src/gb/Makefile
    4.38 +		 src/gba/Makefile
    4.39 +		 src/common/Makefile])
    4.40  
    4.41 -AM_INIT_AUTOMAKE([dist-bzip2])
    4.42 +
    4.43  
    4.44  AC_OUTPUT
    4.45  
     5.1 --- a/src/Makefile.am	Sat Mar 03 12:06:10 2012 -0600
     5.2 +++ b/src/Makefile.am	Sun Mar 04 14:33:52 2012 -0600
     5.3 @@ -1,1 +1,1 @@
     5.4 -SUBDIRS = lua gb
     5.5 +SUBDIRS = lua gb gba common
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/NLS.h	Sun Mar 04 14:33:52 2012 -0600
     6.3 @@ -0,0 +1,52 @@
     6.4 +#ifndef VBS_NLS_H
     6.5 +#define VBA_NLS_H
     6.6 +
     6.7 +#if _MSC_VER > 1000
     6.8 +#pragma once
     6.9 +#endif // _MSC_VER > 1000
    6.10 +
    6.11 +#define N_(String) (String)
    6.12 +
    6.13 +#define MSG_UNSUPPORTED_VBA_SGM             1
    6.14 +#define MSG_CANNOT_LOAD_SGM                 2
    6.15 +#define MSG_SAVE_GAME_NOT_USING_BIOS        3
    6.16 +#define MSG_SAVE_GAME_USING_BIOS            4
    6.17 +#define MSG_UNSUPPORTED_SAVE_TYPE           5
    6.18 +#define MSG_CANNOT_OPEN_FILE                6
    6.19 +#define MSG_BAD_ZIP_FILE                    7
    6.20 +#define MSG_NO_IMAGE_ON_ZIP                 8
    6.21 +#define MSG_ERROR_OPENING_IMAGE             9
    6.22 +#define MSG_ERROR_READING_IMAGE            10
    6.23 +#define MSG_UNSUPPORTED_BIOS_FUNCTION      11
    6.24 +#define MSG_INVALID_BIOS_FILE_SIZE         12
    6.25 +#define MSG_INVALID_CHEAT_CODE             13
    6.26 +#define MSG_UNKNOWN_ARM_OPCODE             14
    6.27 +#define MSG_UNKNOWN_THUMB_OPCODE           15
    6.28 +#define MSG_ERROR_CREATING_FILE            16
    6.29 +#define MSG_FAILED_TO_READ_SGM             17
    6.30 +#define MSG_FAILED_TO_READ_RTC             18
    6.31 +#define MSG_UNSUPPORTED_VB_SGM             19
    6.32 +#define MSG_CANNOT_LOAD_SGM_FOR            20
    6.33 +#define MSG_ERROR_OPENING_IMAGE_FROM       21
    6.34 +#define MSG_ERROR_READING_IMAGE_FROM       22
    6.35 +#define MSG_UNSUPPORTED_ROM_SIZE           23
    6.36 +#define MSG_UNSUPPORTED_RAM_SIZE           24
    6.37 +#define MSG_UNKNOWN_CARTRIDGE_TYPE         25
    6.38 +#define MSG_MAXIMUM_NUMBER_OF_CHEATS       26
    6.39 +#define MSG_INVALID_GAMESHARK_CODE         27
    6.40 +#define MSG_INVALID_GAMEGENIE_CODE         28
    6.41 +#define MSG_INVALID_CHEAT_TO_REMOVE        29
    6.42 +#define MSG_INVALID_CHEAT_CODE_ADDRESS     30
    6.43 +#define MSG_UNSUPPORTED_CHEAT_LIST_VERSION 31
    6.44 +#define MSG_UNSUPPORTED_CHEAT_LIST_TYPE    32
    6.45 +#define MSG_INVALID_GSA_CODE               33
    6.46 +#define MSG_CANNOT_IMPORT_SNAPSHOT_FOR     34
    6.47 +#define MSG_UNSUPPORTED_SNAPSHOT_FILE      35
    6.48 +#define MSG_UNSUPPORTED_ARM_MODE           36
    6.49 +#define MSG_UNSUPPORTED_CODE_FILE          37
    6.50 +#define MSG_GBA_CODE_WARNING               38
    6.51 +#define MSG_INVALID_CBA_CODE               39
    6.52 +#define MSG_CBA_CODE_WARNING               40
    6.53 +#define MSG_OUT_OF_MEMORY                  41
    6.54 +
    6.55 +#endif // VBA_NLS_H
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/Port.h	Sun Mar 04 14:33:52 2012 -0600
     7.3 @@ -0,0 +1,178 @@
     7.4 +#ifndef VBA_PORT_H
     7.5 +#define VBA_PORT_H
     7.6 +
     7.7 +#if _MSC_VER > 1000
     7.8 +#pragma once
     7.9 +#endif // _MSC_VER > 1000
    7.10 +
    7.11 +#include <ctime>
    7.12 +
    7.13 +#ifndef NULL
    7.14 +#define NULL 0
    7.15 +#endif
    7.16 +
    7.17 +typedef unsigned char bool8;
    7.18 +
    7.19 +#ifdef HAVE_STDINT_H
    7.20 +#include <stdint.h>
    7.21 +
    7.22 +typedef int8_t   int8;
    7.23 +typedef uint8_t  uint8;
    7.24 +typedef int16_t  int16;
    7.25 +typedef uint16_t uint16;
    7.26 +typedef int32_t  int32;
    7.27 +typedef uint32_t uint32;
    7.28 +typedef int64_t  int64;
    7.29 +typedef uint64_t uint64;
    7.30 +typedef intptr_t pint;
    7.31 +
    7.32 +#else /* Don't have stdint.h */
    7.33 +
    7.34 +#ifdef PTR_NOT_INT
    7.35 +typedef long pint;
    7.36 +#else /* pointer is int */
    7.37 +typedef int pint;
    7.38 +#endif /* PTR_NOT_INT */
    7.39 +
    7.40 +/* FIXME: Refactor this by moving out the BORLAND part and unifying typedefs */
    7.41 +#ifndef WIN32
    7.42 +typedef unsigned char  uint8;
    7.43 +typedef unsigned short uint16;
    7.44 +typedef signed char    int8;
    7.45 +typedef short          int16;
    7.46 +typedef int            int32;
    7.47 +typedef unsigned int   uint32;
    7.48 +# ifdef __GNUC__  /* long long is not part of ISO C++ */
    7.49 +__extension__ typedef long long          int64;
    7.50 +__extension__ typedef unsigned long long uint64;
    7.51 +# else
    7.52 +typedef long long          int64;
    7.53 +typedef unsigned long long uint64;
    7.54 +# endif
    7.55 +#else /* WIN32 */
    7.56 +
    7.57 +# ifdef __BORLANDC__
    7.58 +#   include <systypes.h>
    7.59 +# else
    7.60 +
    7.61 +typedef unsigned char  uint8;
    7.62 +typedef unsigned short uint16;
    7.63 +typedef signed char    int8;
    7.64 +typedef short          int16;
    7.65 +
    7.66 +# ifndef WSAAPI
    7.67 +/* winsock2.h typedefs int32 as well. */
    7.68 +typedef long int32;
    7.69 +# endif
    7.70 +
    7.71 +typedef unsigned int uint32;
    7.72 +
    7.73 +# endif /* __BORLANDC__ */
    7.74 +
    7.75 +typedef __int64          int64;
    7.76 +typedef unsigned __int64 uint64;
    7.77 +
    7.78 +#endif /* WIN32 */
    7.79 +#endif /* HAVE_STDINT_H */
    7.80 +
    7.81 +#ifndef WIN32
    7.82 +
    7.83 +#ifndef PATH_MAX
    7.84 +#define PATH_MAX 1024
    7.85 +#endif
    7.86 +
    7.87 +#define _MAX_DIR PATH_MAX
    7.88 +#define _MAX_DRIVE 1
    7.89 +#define _MAX_FNAME PATH_MAX
    7.90 +#define _MAX_EXT PATH_MAX
    7.91 +#define _MAX_PATH PATH_MAX
    7.92 +
    7.93 +#define ZeroMemory(a, b) memset((a), 0, (b))
    7.94 +
    7.95 +void _makepath(char *path, const char *drive, const char *dir,
    7.96 +               const char *fname, const char *ext);
    7.97 +void _splitpath(const char *path, char *drive, char *dir, char *fname,
    7.98 +                char *ext);
    7.99 +#else /* WIN32 */
   7.100 +#define strcasecmp stricmp
   7.101 +#define strncasecmp strnicmp
   7.102 +#endif
   7.103 +
   7.104 +typedef uint8  u8;
   7.105 +typedef uint16 u16;
   7.106 +typedef uint32 u32;
   7.107 +typedef uint64 u64;
   7.108 +typedef int8   s8;
   7.109 +typedef int16  s16;
   7.110 +typedef int32  s32;
   7.111 +typedef int64  s64;
   7.112 +
   7.113 +// for consistency
   7.114 +static inline u8 swap8(u8 v)
   7.115 +{
   7.116 +	return v;
   7.117 +}
   7.118 +
   7.119 +// swaps a 16-bit value
   7.120 +static inline u16 swap16(u16 v)
   7.121 +{
   7.122 +	return (v<<8)|(v>>8);
   7.123 +}
   7.124 +
   7.125 +// swaps a 32-bit value
   7.126 +static inline u32 swap32(u32 v)
   7.127 +{
   7.128 +	return (v<<24)|((v<<8)&0xff0000)|((v>>8)&0xff00)|(v>>24);
   7.129 +}
   7.130 +
   7.131 +#define READ8LE(x) \
   7.132 +    *((u8 *)x)
   7.133 +
   7.134 +#define WRITE8LE(x, v) \
   7.135 +    *((u8 *)x) = (v)
   7.136 +
   7.137 +#ifdef WORDS_BIGENDIAN
   7.138 +#if defined(__GNUC__) && defined(__ppc__)
   7.139 +
   7.140 +#define READ16LE(base) \
   7.141 +    ({ unsigned short lhbrxResult;       \
   7.142 +       __asm__("lhbrx %0, 0, %1" : "=r" (lhbrxResult) : "r" (base) : "memory"); \
   7.143 +       lhbrxResult; })
   7.144 +
   7.145 +#define READ32LE(base) \
   7.146 +    ({ unsigned long lwbrxResult; \
   7.147 +       __asm__("lwbrx %0, 0, %1" : "=r" (lwbrxResult) : "r" (base) : "memory"); \
   7.148 +       lwbrxResult; })
   7.149 +
   7.150 +#define WRITE16LE(base, value) \
   7.151 +    __asm__("sthbrx %0, 0, %1" : : "r" (value), "r" (base) : "memory")
   7.152 +
   7.153 +#define WRITE32LE(base, value) \
   7.154 +    __asm__("stwbrx %0, 0, %1" : : "r" (value), "r" (base) : "memory")
   7.155 +
   7.156 +#else
   7.157 +#define READ16LE(x) \
   7.158 +    swap16(*((u16 *)(x)))
   7.159 +#define READ32LE(x) \
   7.160 +    swap32(*((u32 *)(x)))
   7.161 +#define WRITE16LE(x, v) \
   7.162 +    *((u16 *)x) = swap16((v))
   7.163 +#define WRITE32LE(x, v) \
   7.164 +    *((u32 *)x) = swap32((v))
   7.165 +#endif
   7.166 +#else
   7.167 +#define READ16LE(x) \
   7.168 +    *((u16 *)x)
   7.169 +#define READ32LE(x) \
   7.170 +    *((u32 *)x)
   7.171 +#define WRITE16LE(x, v) \
   7.172 +    *((u16 *)x) = (v)
   7.173 +#define WRITE32LE(x, v) \
   7.174 +    *((u32 *)x) = (v)
   7.175 +#endif
   7.176 +
   7.177 +#ifndef CTASSERT
   7.178 +#define CTASSERT(x)  typedef char __assert ## y[(x) ? 1 : -1];
   7.179 +#endif
   7.180 +
   7.181 +#endif // VBA_PORT_H
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/common/CheatSearch.cpp	Sun Mar 04 14:33:52 2012 -0600
     8.3 @@ -0,0 +1,371 @@
     8.4 +#include <cstdlib>
     8.5 +#include <cstring>
     8.6 +
     8.7 +#include "CheatSearch.h"
     8.8 +
     8.9 +CheatSearchBlock cheatSearchBlocks[4];
    8.10 +
    8.11 +CheatSearchData cheatSearchData = {
    8.12 +	0,
    8.13 +	cheatSearchBlocks
    8.14 +};
    8.15 +
    8.16 +static bool cheatSearchEQ(u32 a, u32 b)
    8.17 +{
    8.18 +	return a == b;
    8.19 +}
    8.20 +
    8.21 +static bool cheatSearchNE(u32 a, u32 b)
    8.22 +{
    8.23 +	return a != b;
    8.24 +}
    8.25 +
    8.26 +static bool cheatSearchLT(u32 a, u32 b)
    8.27 +{
    8.28 +	return a < b;
    8.29 +}
    8.30 +
    8.31 +static bool cheatSearchLE(u32 a, u32 b)
    8.32 +{
    8.33 +	return a <= b;
    8.34 +}
    8.35 +
    8.36 +static bool cheatSearchGT(u32 a, u32 b)
    8.37 +{
    8.38 +	return a > b;
    8.39 +}
    8.40 +
    8.41 +static bool cheatSearchGE(u32 a, u32 b)
    8.42 +{
    8.43 +	return a >= b;
    8.44 +}
    8.45 +
    8.46 +static bool cheatSearchSignedEQ(s32 a, s32 b)
    8.47 +{
    8.48 +	return a == b;
    8.49 +}
    8.50 +
    8.51 +static bool cheatSearchSignedNE(s32 a, s32 b)
    8.52 +{
    8.53 +	return a != b;
    8.54 +}
    8.55 +
    8.56 +static bool cheatSearchSignedLT(s32 a, s32 b)
    8.57 +{
    8.58 +	return a < b;
    8.59 +}
    8.60 +
    8.61 +static bool cheatSearchSignedLE(s32 a, s32 b)
    8.62 +{
    8.63 +	return a <= b;
    8.64 +}
    8.65 +
    8.66 +static bool cheatSearchSignedGT(s32 a, s32 b)
    8.67 +{
    8.68 +	return a > b;
    8.69 +}
    8.70 +
    8.71 +static bool cheatSearchSignedGE(s32 a, s32 b)
    8.72 +{
    8.73 +	return a >= b;
    8.74 +}
    8.75 +
    8.76 +static bool (*cheatSearchFunc[])(u32, u32) = {
    8.77 +	cheatSearchEQ,
    8.78 +	cheatSearchNE,
    8.79 +	cheatSearchLT,
    8.80 +	cheatSearchLE,
    8.81 +	cheatSearchGT,
    8.82 +	cheatSearchGE
    8.83 +};
    8.84 +
    8.85 +static bool (*cheatSearchSignedFunc[])(s32, s32) = {
    8.86 +	cheatSearchSignedEQ,
    8.87 +	cheatSearchSignedNE,
    8.88 +	cheatSearchSignedLT,
    8.89 +	cheatSearchSignedLE,
    8.90 +	cheatSearchSignedGT,
    8.91 +	cheatSearchSignedGE
    8.92 +};
    8.93 +
    8.94 +void cheatSearchSetSavedAndBits(CheatSearchBlock *block)
    8.95 +{
    8.96 +	if (!block->saved)
    8.97 +	{
    8.98 +		block->saved = (u8 *)malloc(block->size);
    8.99 +		memcpy(block->saved, block->data, block->size);
   8.100 +	}
   8.101 +	if (!block->bits)
   8.102 +	{
   8.103 +		block->bits  = (u8 *)malloc(block->size >> 3);
   8.104 +		memset(block->bits, 0xff, block->size >> 3);
   8.105 +	}
   8.106 +}
   8.107 +
   8.108 +void cheatSearchZeroBlock(CheatSearchBlock *block)
   8.109 +{
   8.110 +	block->data	  = 0;
   8.111 +	block->offset = 0;
   8.112 +	block->size	  = 0;
   8.113 +	free(block->saved);
   8.114 +	free(block->bits);
   8.115 +	block->saved  = 0;
   8.116 +	block->bits	  = 0;
   8.117 +}
   8.118 +
   8.119 +void cheatSearchCleanup(CheatSearchData *cs)
   8.120 +{
   8.121 +	int count = cs->count;
   8.122 +
   8.123 +	for (int i = 0; i < count; i++)
   8.124 +	{
   8.125 +		CheatSearchBlock &block = cs->blocks[i];
   8.126 +		free(block.saved);
   8.127 +		free(block.bits);
   8.128 +		block.saved = 0;
   8.129 +		block.bits  = 0;
   8.130 +	}
   8.131 +	cs->count = 0;
   8.132 +}
   8.133 +
   8.134 +void cheatSearchStart(const CheatSearchData *cs)
   8.135 +{
   8.136 +	int count = cs->count;
   8.137 +
   8.138 +	for (int i = 0; i < count; i++)
   8.139 +	{
   8.140 +		CheatSearchBlock *block = &cs->blocks[i];
   8.141 +
   8.142 +		memset(block->bits, 0xff, block->size >> 3);
   8.143 +		memcpy(block->saved, block->data, block->size);
   8.144 +	}
   8.145 +}
   8.146 +
   8.147 +s32 cheatSearchSignedRead(u8 *data, int off, int size)
   8.148 +{
   8.149 +	u32 res = data[off++];
   8.150 +
   8.151 +	switch (size)
   8.152 +	{
   8.153 +	case BITS_8:
   8.154 +		res <<= 24;
   8.155 +		return ((s32)res) >> 24;
   8.156 +	case BITS_16:
   8.157 +		res  |= ((u32)data[off++])<<8;
   8.158 +		res <<= 16;
   8.159 +		return ((s32)res) >> 16;
   8.160 +	case BITS_32:
   8.161 +		res |= ((u32)data[off++])<<8;
   8.162 +		res |= ((u32)data[off++])<<16;
   8.163 +		res |= ((u32)data[off++])<<24;
   8.164 +		return (s32)res;
   8.165 +	}
   8.166 +	return (s32)res;
   8.167 +}
   8.168 +
   8.169 +u32 cheatSearchRead(u8 *data, int off, int size)
   8.170 +{
   8.171 +	u32 res = data[off++];
   8.172 +	if (size == BITS_16)
   8.173 +		res |= ((u32)data[off++])<<8;
   8.174 +	else if (size == BITS_32)
   8.175 +	{
   8.176 +		res |= ((u32)data[off++])<<8;
   8.177 +		res |= ((u32)data[off++])<<16;
   8.178 +		res |= ((u32)data[off++])<<24;
   8.179 +	}
   8.180 +	return res;
   8.181 +}
   8.182 +
   8.183 +void cheatSearch(const CheatSearchData *cs, int compare, int size,
   8.184 +                 bool isSigned)
   8.185 +{
   8.186 +	if (compare < 0 || compare > SEARCH_GE)
   8.187 +		return;
   8.188 +	int inc = 1;
   8.189 +	if (size == BITS_16)
   8.190 +		inc = 2;
   8.191 +	else if (size == BITS_32)
   8.192 +		inc = 4;
   8.193 +
   8.194 +	if (isSigned)
   8.195 +	{
   8.196 +		bool (*func)(s32, s32) = cheatSearchSignedFunc[compare];
   8.197 +
   8.198 +		for (int i = 0; i < cs->count; i++)
   8.199 +		{
   8.200 +			CheatSearchBlock *block = &cs->blocks[i];
   8.201 +			int size2 = block->size;
   8.202 +			u8 *bits  = block->bits;
   8.203 +			u8 *data  = block->data;
   8.204 +			u8 *saved = block->saved;
   8.205 +
   8.206 +			for (int j = 0; j < size2; j += inc)
   8.207 +			{
   8.208 +				if (IS_BIT_SET(bits, j))
   8.209 +				{
   8.210 +					s32 a = cheatSearchSignedRead(data, j, size);
   8.211 +					s32 b = cheatSearchSignedRead(saved, j, size);
   8.212 +
   8.213 +					if (!func(a, b))
   8.214 +					{
   8.215 +						CLEAR_BIT(bits, j);
   8.216 +						if (size == BITS_16)
   8.217 +							CLEAR_BIT(bits, j+1);
   8.218 +						if (size == BITS_32)
   8.219 +						{
   8.220 +							CLEAR_BIT(bits, j+2);
   8.221 +							CLEAR_BIT(bits, j+3);
   8.222 +						}
   8.223 +					}
   8.224 +				}
   8.225 +			}
   8.226 +		}
   8.227 +	}
   8.228 +	else
   8.229 +	{
   8.230 +		bool (*func)(u32, u32) = cheatSearchFunc[compare];
   8.231 +
   8.232 +		for (int i = 0; i < cs->count; i++)
   8.233 +		{
   8.234 +			CheatSearchBlock *block = &cs->blocks[i];
   8.235 +			int size2 = block->size;
   8.236 +			u8 *bits  = block->bits;
   8.237 +			u8 *data  = block->data;
   8.238 +			u8 *saved = block->saved;
   8.239 +
   8.240 +			for (int j = 0; j < size2; j += inc)
   8.241 +			{
   8.242 +				if (IS_BIT_SET(bits, j))
   8.243 +				{
   8.244 +					u32 a = cheatSearchRead(data, j, size);
   8.245 +					u32 b = cheatSearchRead(saved, j, size);
   8.246 +
   8.247 +					if (!func(a, b))
   8.248 +					{
   8.249 +						CLEAR_BIT(bits, j);
   8.250 +						if (size == BITS_16)
   8.251 +							CLEAR_BIT(bits, j+1);
   8.252 +						if (size == BITS_32)
   8.253 +						{
   8.254 +							CLEAR_BIT(bits, j+2);
   8.255 +							CLEAR_BIT(bits, j+3);
   8.256 +						}
   8.257 +					}
   8.258 +				}
   8.259 +			}
   8.260 +		}
   8.261 +	}
   8.262 +}
   8.263 +
   8.264 +void cheatSearchValue(const CheatSearchData *cs, int compare, int size,
   8.265 +                      bool isSigned, u32 value)
   8.266 +{
   8.267 +	if (compare < 0 || compare > SEARCH_GE)
   8.268 +		return;
   8.269 +	int inc = 1;
   8.270 +	if (size == BITS_16)
   8.271 +		inc = 2;
   8.272 +	else if (size == BITS_32)
   8.273 +		inc = 4;
   8.274 +
   8.275 +	if (isSigned)
   8.276 +	{
   8.277 +		bool (*func)(s32, s32) = cheatSearchSignedFunc[compare];
   8.278 +
   8.279 +		for (int i = 0; i < cs->count; i++)
   8.280 +		{
   8.281 +			CheatSearchBlock *block = &cs->blocks[i];
   8.282 +			int size2 = block->size;
   8.283 +			u8 *bits  = block->bits;
   8.284 +			u8 *data  = block->data;
   8.285 +
   8.286 +			for (int j = 0; j < size2; j += inc)
   8.287 +			{
   8.288 +				if (IS_BIT_SET(bits, j))
   8.289 +				{
   8.290 +					s32 a = cheatSearchSignedRead(data, j, size);
   8.291 +					s32 b = (s32)value;
   8.292 +
   8.293 +					if (!func(a, b))
   8.294 +					{
   8.295 +						CLEAR_BIT(bits, j);
   8.296 +						if (size == BITS_16)
   8.297 +							CLEAR_BIT(bits, j+1);
   8.298 +						if (size == BITS_32)
   8.299 +						{
   8.300 +							CLEAR_BIT(bits, j+2);
   8.301 +							CLEAR_BIT(bits, j+3);
   8.302 +						}
   8.303 +					}
   8.304 +				}
   8.305 +			}
   8.306 +		}
   8.307 +	}
   8.308 +	else
   8.309 +	{
   8.310 +		bool (*func)(u32, u32) = cheatSearchFunc[compare];
   8.311 +
   8.312 +		for (int i = 0; i < cs->count; i++)
   8.313 +		{
   8.314 +			CheatSearchBlock *block = &cs->blocks[i];
   8.315 +			int size2 = block->size;
   8.316 +			u8 *bits  = block->bits;
   8.317 +			u8 *data  = block->data;
   8.318 +
   8.319 +			for (int j = 0; j < size2; j += inc)
   8.320 +			{
   8.321 +				if (IS_BIT_SET(bits, j))
   8.322 +				{
   8.323 +					u32 a = cheatSearchRead(data, j, size);
   8.324 +
   8.325 +					if (!func(a, value))
   8.326 +					{
   8.327 +						CLEAR_BIT(bits, j);
   8.328 +						if (size == BITS_16)
   8.329 +							CLEAR_BIT(bits, j+1);
   8.330 +						if (size == BITS_32)
   8.331 +						{
   8.332 +							CLEAR_BIT(bits, j+2);
   8.333 +							CLEAR_BIT(bits, j+3);
   8.334 +						}
   8.335 +					}
   8.336 +				}
   8.337 +			}
   8.338 +		}
   8.339 +	}
   8.340 +}
   8.341 +
   8.342 +int cheatSearchGetCount(const CheatSearchData *cs, int size)
   8.343 +{
   8.344 +	int res = 0;
   8.345 +	int inc = 1;
   8.346 +	if (size == BITS_16)
   8.347 +		inc = 2;
   8.348 +	else if (size == BITS_32)
   8.349 +		inc = 4;
   8.350 +
   8.351 +	for (int i = 0; i < cs->count; i++)
   8.352 +	{
   8.353 +		CheatSearchBlock *block = &cs->blocks[i];
   8.354 +
   8.355 +		int size2 = block->size;
   8.356 +		u8 *bits  = block->bits;
   8.357 +		for (int j = 0; j < size2; j += inc)
   8.358 +		{
   8.359 +			if (IS_BIT_SET(bits, j))
   8.360 +				res++;
   8.361 +		}
   8.362 +	}
   8.363 +	return res;
   8.364 +}
   8.365 +
   8.366 +void cheatSearchUpdateValues(const CheatSearchData *cs)
   8.367 +{
   8.368 +	for (int i = 0; i < cs->count; i++)
   8.369 +	{
   8.370 +		CheatSearchBlock *block = &cs->blocks[i];
   8.371 +
   8.372 +		memcpy(block->saved, block->data, block->size);
   8.373 +	}
   8.374 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/common/CheatSearch.h	Sun Mar 04 14:33:52 2012 -0600
     9.3 @@ -0,0 +1,65 @@
     9.4 +#ifndef VBA_CHEATSEARCH_H
     9.5 +#define VBA_CHEATSEARCH_H
     9.6 +
     9.7 +#if _MSC_VER > 1000
     9.8 +#pragma once
     9.9 +#endif // _MSC_VER > 1000
    9.10 +
    9.11 +#include "../Port.h"
    9.12 +
    9.13 +struct CheatSearchBlock
    9.14 +{
    9.15 +	u8 *data;
    9.16 +	int size;
    9.17 +	u32 offset;
    9.18 +	u8 *saved;
    9.19 +	u8 *bits;
    9.20 +};
    9.21 +
    9.22 +struct CheatSearchData
    9.23 +{
    9.24 +	int count;
    9.25 +	CheatSearchBlock *blocks;
    9.26 +};
    9.27 +
    9.28 +enum
    9.29 +{
    9.30 +	SEARCH_EQ,
    9.31 +	SEARCH_NE,
    9.32 +	SEARCH_LT,
    9.33 +	SEARCH_LE,
    9.34 +	SEARCH_GT,
    9.35 +	SEARCH_GE
    9.36 +};
    9.37 +
    9.38 +enum
    9.39 +{
    9.40 +	BITS_8,
    9.41 +	BITS_16,
    9.42 +	BITS_32
    9.43 +};
    9.44 +
    9.45 +#define SET_BIT(bits, off) \
    9.46 +    (bits)[(off) >> 3] |= (1 << ((off) & 7))
    9.47 +
    9.48 +#define CLEAR_BIT(bits, off) \
    9.49 +    (bits)[(off) >> 3] &= ~(1 << ((off) & 7))
    9.50 +
    9.51 +#define IS_BIT_SET(bits, off) \
    9.52 +    (bits)[(off) >> 3] & (1 << ((off) & 7))
    9.53 +
    9.54 +extern CheatSearchData cheatSearchData;
    9.55 +extern void cheatSearchSetSavedAndBits(CheatSearchBlock *block);
    9.56 +extern void cheatSearchZeroBlock(CheatSearchBlock *block);
    9.57 +extern void cheatSearchCleanup(CheatSearchData *cs);
    9.58 +extern void cheatSearchStart(const CheatSearchData *cs);
    9.59 +extern void cheatSearch(const CheatSearchData *cs, int compare, int size,
    9.60 +                        bool isSigned);
    9.61 +extern void cheatSearchValue(const CheatSearchData *cs, int compare, int size,
    9.62 +                             bool isSigned, u32 value);
    9.63 +extern int cheatSearchGetCount(const CheatSearchData *cs, int size);
    9.64 +extern void cheatSearchUpdateValues(const CheatSearchData *cs);
    9.65 +extern s32 cheatSearchSignedRead(u8 *data, int off, int size);
    9.66 +extern u32 cheatSearchRead(u8 *data, int off, int size);
    9.67 +
    9.68 +#endif // VBA_CHEATSEARCH_H
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/common/Makefile.am	Sun Mar 04 14:33:52 2012 -0600
    10.3 @@ -0,0 +1,31 @@
    10.4 +noinst_LIBRARIES = libgbcom.a
    10.5 +
    10.6 +libgbcom_a_SOURCES = \
    10.7 +	CheatSearch.h		\
    10.8 +	inputGlobal.h		\
    10.9 +	memgzio.h		\
   10.10 +	movie.h			\
   10.11 +	nesvideos-piece.h	\
   10.12 +	System.h		\
   10.13 +	Text.h			\
   10.14 +	unzip.h			\
   10.15 +	Util.h			\
   10.16 +	vbalua.h		\
   10.17 +				\
   10.18 +	CheatSearch.cpp		\
   10.19 +	lua-engine.cpp		\
   10.20 +	memgzio.c		\
   10.21 +	movie.cpp		\
   10.22 +	nesvideos-piece.cpp	\
   10.23 +	Text.cpp		\
   10.24 +	unzip.cpp		\
   10.25 +	Util.cpp		
   10.26 +
   10.27 +
   10.28 +
   10.29 +AM_CPPFLAGS = \
   10.30 +	-I$(top_srcdir)/src		\
   10.31 +	-DSDL				\
   10.32 +	-DSYSCONFDIR=\"$(sysconfdir)\"
   10.33 +
   10.34 +AM_CXXFLAGS = -fno-exceptions @SDL_CFLAGS@
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/common/System.h	Sun Mar 04 14:33:52 2012 -0600
    11.3 @@ -0,0 +1,137 @@
    11.4 +#ifndef VBA_SYSTEM_H
    11.5 +#define VBA_SYSTEM_H
    11.6 +
    11.7 +#if _MSC_VER > 1000
    11.8 +#pragma once
    11.9 +#endif // _MSC_VER > 1000
   11.10 +
   11.11 +#include "zlib.h"
   11.12 +#include "../Port.h"
   11.13 +
   11.14 +// c++ lacks a way to implement Smart Referrences or Delphi-Style Properties
   11.15 +// in order to maintain consistency, value-copied things should not be modified too often
   11.16 +struct EmulatedSystem
   11.17 +{
   11.18 +	// main emulation function
   11.19 +	void (*emuMain)(int);
   11.20 +	// reset emulator
   11.21 +	void (*emuReset)(bool);
   11.22 +	// clean up memory
   11.23 +	void (*emuCleanUp)();
   11.24 +	// load battery file
   11.25 +	bool (*emuReadBattery)(const char *);
   11.26 +	// write battery file
   11.27 +	bool (*emuWriteBattery)(const char *);
   11.28 +	// load battery file from stream
   11.29 +	bool (*emuReadBatteryFromStream)(gzFile);
   11.30 +	// write battery file to stream
   11.31 +	bool (*emuWriteBatteryToStream)(gzFile);
   11.32 +	// load state
   11.33 +	bool (*emuReadState)(const char *);
   11.34 +	// save state
   11.35 +	bool (*emuWriteState)(const char *);
   11.36 +	// load state from stream
   11.37 +	bool (*emuReadStateFromStream)(gzFile);
   11.38 +	// save state to stream
   11.39 +	bool (*emuWriteStateToStream)(gzFile);
   11.40 +	// load memory state (rewind)
   11.41 +	bool (*emuReadMemState)(char *, int);
   11.42 +	// write memory state (rewind)
   11.43 +	bool (*emuWriteMemState)(char *, int);
   11.44 +	// write PNG file
   11.45 +	bool (*emuWritePNG)(const char *);
   11.46 +	// write BMP file
   11.47 +	bool (*emuWriteBMP)(const char *);
   11.48 +	// emulator update CPSR (ARM only)
   11.49 +	void (*emuUpdateCPSR)();
   11.50 +	// emulator has debugger
   11.51 +	bool emuHasDebugger;
   11.52 +	// clock ticks to emulate
   11.53 +	int emuCount;
   11.54 +};
   11.55 +
   11.56 +// why not convert the value type only when doing I/O?
   11.57 +struct EmulatedSystemCounters
   11.58 +{
   11.59 +	int32 frameCount;
   11.60 +	int32 lagCount;
   11.61 +	int32 extraCount;
   11.62 +	bool8 lagged;
   11.63 +	bool8 laggedLast;
   11.64 +};
   11.65 +
   11.66 +extern struct EmulatedSystem theEmulator;
   11.67 +extern struct EmulatedSystemCounters systemCounters;
   11.68 +
   11.69 +extern void log(const char *, ...);
   11.70 +
   11.71 +extern void systemGbPrint(u8 *, int, int, int, int);
   11.72 +extern int  systemScreenCapture(int);
   11.73 +extern void systemRefreshScreen();
   11.74 +extern void systemRenderFrame();
   11.75 +extern void systemRedrawScreen();
   11.76 +extern void systemUpdateListeners();
   11.77 +// updates the joystick data
   11.78 +extern void systemSetSensorX(int32);
   11.79 +extern void systemSetSensorY(int32);
   11.80 +extern void systemResetSensor();
   11.81 +extern int32 systemGetSensorX();
   11.82 +extern int32 systemGetSensorY();
   11.83 +extern void systemUpdateMotionSensor(int);
   11.84 +extern int  systemGetDefaultJoypad();
   11.85 +extern void systemSetDefaultJoypad(int);
   11.86 +extern bool systemReadJoypads();
   11.87 +// return information about the given joystick, -1 for default joystick... the bool is for if motion sensor should be handled
   11.88 +// too
   11.89 +extern u32  systemGetOriginalJoypad(int, bool);
   11.90 +extern u32  systemGetJoypad(int, bool);
   11.91 +extern void systemSetJoypad(int, u32);
   11.92 +extern void systemClearJoypads();
   11.93 +extern void systemMessage(int, const char *, ...);
   11.94 +extern void systemScreenMessage(const char *msg, int slot = 0, int duration = 3000, const char *colorList = NULL);
   11.95 +extern bool systemSoundInit();
   11.96 +extern void systemSoundShutdown();
   11.97 +extern void systemSoundPause();
   11.98 +extern void systemSoundResume();
   11.99 +extern bool systemSoundIsPaused();
  11.100 +extern void systemSoundReset();
  11.101 +extern void systemSoundWriteToBuffer();
  11.102 +extern void systemSoundClearBuffer();
  11.103 +extern bool systemSoundCanChangeQuality();
  11.104 +extern bool systemSoundSetQuality(int quality);
  11.105 +extern u32  systemGetClock();
  11.106 +extern void systemSetTitle(const char *);
  11.107 +extern void systemShowSpeed(int);
  11.108 +extern void systemIncreaseThrottle();
  11.109 +extern void systemDecreaseThrottle();
  11.110 +extern void systemSetThrottle(int);
  11.111 +extern int  systemGetThrottle();
  11.112 +extern void systemFrame();
  11.113 +extern int  systemFramesToSkip();
  11.114 +extern bool systemIsEmulating();
  11.115 +extern void systemGbBorderOn();
  11.116 +extern bool systemIsRunningGBA();
  11.117 +extern bool systemIsSpedUp();
  11.118 +extern bool systemIsPaused();
  11.119 +extern void systemSetPause(bool pause);
  11.120 +extern bool systemPauseOnFrame();
  11.121 +
  11.122 +extern int	systemCartridgeType;
  11.123 +extern int  systemSpeed;
  11.124 +extern bool systemSoundOn;
  11.125 +extern u16  systemColorMap16[0x10000];
  11.126 +extern u32  systemColorMap32[0x10000];
  11.127 +extern u16  systemGbPalette[24];
  11.128 +extern int  systemRedShift;
  11.129 +extern int  systemGreenShift;
  11.130 +extern int  systemBlueShift;
  11.131 +extern int  systemColorDepth;
  11.132 +extern int  systemDebug;
  11.133 +extern int  systemVerbose;
  11.134 +extern int  systemFrameSkip;
  11.135 +extern int  systemSaveUpdateCounter;
  11.136 +
  11.137 +#define SYSTEM_SAVE_UPDATED 30
  11.138 +#define SYSTEM_SAVE_NOT_UPDATED 0
  11.139 +
  11.140 +#endif // VBA_SYSTEM_H
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/common/Text.cpp	Sun Mar 04 14:33:52 2012 -0600
    12.3 @@ -0,0 +1,496 @@
    12.4 +/* FCE Ultra - NES/Famicom Emulator
    12.5 + *
    12.6 + * Copyright notice for this file:
    12.7 + *  Copyright (C) 2002 Ben Parnell
    12.8 + *
    12.9 + * This program is free software; you can redistribute it and/or modify
   12.10 + * it under the terms of the GNU General Public License as published by
   12.11 + * the Free Software Foundation; either version 2 of the License, or
   12.12 + * (at your option) any later version.
   12.13 + *
   12.14 + * This program is distributed in the hope that it will be useful,
   12.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12.17 + * GNU General Public License for more details.
   12.18 + *
   12.19 + * You should have received a copy of the GNU General Public License
   12.20 + * along with this program; if not, write to the Free Software
   12.21 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   12.22 + */
   12.23 +
   12.24 +/* Code originally from fceu/drawing.h file, adapted by Forgotten
   12.25 + */
   12.26 +#include "System.h"
   12.27 +
   12.28 +bool outlinedText = true, transparentText = false;
   12.29 +int  textColor    = 0, textMethod = 1;
   12.30 +
   12.31 +extern u32 RGB_LOW_BITS_MASK;
   12.32 +
   12.33 +static const u8 fontdata2[2048] = {
   12.34 +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x7e, 0xff,  0xdb, 0xff,
   12.35 +	0xc3, 0xe7, 0xff, 0x7e, 0x36, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00,
   12.36 +	0x1c,
   12.37 +	0x3e, 0x1c, 0x7f, 0x7f, 0x3e, 0x1c, 0x3e, 0x08, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x3e, 0x00, 0x00, 0x18, 0x3c, 0x3c,
   12.38 +	0x18,
   12.39 +	0x00, 0x00, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,  0xff, 0xc3,
   12.40 +	0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xf0, 0xe0, 0xf0, 0xbe, 0x33, 0x33, 0x33, 0x1e, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18,
   12.41 +	0x7e,
   12.42 +	0x18, 0xfc, 0xcc, 0xfc, 0x0c, 0x0c, 0x0e, 0x0f, 0x07, 0xfe, 0xc6, 0xfe, 0xc6, 0xc6, 0xe6, 0x67, 0x03, 0x99, 0x5a, 0x3c,
   12.43 +	0xe7,
   12.44 +	0xe7, 0x3c, 0x5a, 0x99, 0x01, 0x07, 0x1f, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x40, 0x70, 0x7c, 0x7f, 0x7c, 0x70, 0x40, 0x00,
   12.45 +	0x18,
   12.46 +	0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, 0xfe, 0xdb, 0xdb, 0xde, 0xd8,
   12.47 +	0xd8,
   12.48 +	0xd8, 0x00, 0x7c, 0xc6, 0x1c, 0x36, 0x36, 0x1c, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c,
   12.49 +	0x7e,
   12.50 +	0x18, 0x7e, 0x3c, 0x18, 0xff, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18,
   12.51 +	0x00,
   12.52 +	0x00, 0x18, 0x30, 0x7f, 0x30, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x7f, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
   12.53 +	0x03,
   12.54 +	0x7f, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, 0x00,
   12.55 +	0xff,
   12.56 +	0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
   12.57 +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1e, 0x1e, 0x0c, 0x0c, 0x00, 0x0c, 0x00, 0x36, 0x36, 0x36, 0x00,
   12.58 +	0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x7f, 0x36, 0x7f, 0x36, 0x36, 0x00, 0x0c, 0x3e, 0x03, 0x1e, 0x30, 0x1f, 0x0c, 0x00,
   12.59 +	0x00,
   12.60 +	0x63, 0x33, 0x18, 0x0c, 0x66, 0x63, 0x00, 0x1c, 0x36, 0x1c, 0x6e, 0x3b, 0x33, 0x6e, 0x00, 0x06, 0x06, 0x03, 0x00, 0x00,
   12.61 +	0x00,
   12.62 +	0x00, 0x00, 0x18, 0x0c, 0x06, 0x06, 0x06, 0x0c, 0x18, 0x00, 0x06, 0x0c, 0x18, 0x18, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x66,
   12.63 +	0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
   12.64 +	0x0c,
   12.65 +	0x06, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x60, 0x30, 0x18,
   12.66 +	0x0c,
   12.67 +	0x06, 0x03, 0x01, 0x00, 0x3e, 0x63, 0x73, 0x7b, 0x6f, 0x67, 0x3e, 0x00, 0x0c, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 0x3f, 0x00,
   12.68 +	0x1e,
   12.69 +	0x33, 0x30, 0x1c, 0x06, 0x33, 0x3f, 0x00, 0x1e, 0x33, 0x30, 0x1c, 0x30, 0x33, 0x1e, 0x00, 0x38, 0x3c, 0x36, 0x33, 0x7f,
   12.70 +	0x30,
   12.71 +	0x78, 0x00, 0x3f, 0x03, 0x1f, 0x30, 0x30, 0x33, 0x1e, 0x00, 0x1c, 0x06, 0x03, 0x1f, 0x33, 0x33, 0x1e, 0x00, 0x3f, 0x33,
   12.72 +	0x30,
   12.73 +	0x18, 0x0c, 0x0c, 0x0c, 0x00, 0x1e, 0x33, 0x33, 0x1e, 0x33, 0x33, 0x1e, 0x00, 0x1e, 0x33, 0x33, 0x3e, 0x30, 0x18, 0x0e,
   12.74 +	0x00,
   12.75 +	0x00, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x0c, 0x06, 0x18, 0x0c, 0x06, 0x03,
   12.76 +	0x06,
   12.77 +	0x0c, 0x18, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x1e,
   12.78 +	0x33,
   12.79 +	0x30, 0x18, 0x0c, 0x00, 0x0c, 0x00,
   12.80 +	0x3e, 0x63, 0x7b, 0x7b, 0x7b, 0x03, 0x1e, 0x00, 0x0c, 0x1e, 0x33, 0x33, 0x3f, 0x33, 0x33, 0x00, 0x3f, 0x66, 0x66, 0x3e,
   12.81 +	0x66, 0x66, 0x3f, 0x00, 0x3c, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3c, 0x00, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x00,
   12.82 +	0x7f,
   12.83 +	0x46, 0x16, 0x1e, 0x16, 0x46, 0x7f, 0x00, 0x7f, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x0f, 0x00, 0x3c, 0x66, 0x03, 0x03, 0x73,
   12.84 +	0x66,
   12.85 +	0x7c, 0x00, 0x33, 0x33, 0x33, 0x3f, 0x33, 0x33, 0x33, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x78, 0x30,
   12.86 +	0x30, 0x30, 0x33, 0x33, 0x1e, 0x00, 0x67, 0x66, 0x36, 0x1e, 0x36, 0x66, 0x67, 0x00, 0x0f, 0x06, 0x06, 0x06, 0x46, 0x66,
   12.87 +	0x7f,
   12.88 +	0x00, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x00, 0x63, 0x67, 0x6f, 0x7b, 0x73, 0x63, 0x63, 0x00, 0x1c, 0x36, 0x63,
   12.89 +	0x63,
   12.90 +	0x63, 0x36, 0x1c, 0x00, 0x3f, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x00, 0x1e, 0x33, 0x33, 0x33, 0x3b, 0x1e, 0x38, 0x00,
   12.91 +	0x3f,
   12.92 +	0x66, 0x66, 0x3e, 0x36, 0x66, 0x67, 0x00, 0x1e, 0x33, 0x07, 0x0e, 0x38, 0x33, 0x1e, 0x00, 0x3f, 0x2d, 0x0c, 0x0c, 0x0c,
   12.93 +	0x0c,
   12.94 +	0x1e, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3f, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x0c, 0x00, 0x63, 0x63,
   12.95 +	0x63,
   12.96 +	0x6b, 0x7f, 0x77, 0x63, 0x00, 0x63, 0x63, 0x36, 0x1c, 0x1c, 0x36, 0x63, 0x00, 0x33, 0x33, 0x33, 0x1e, 0x0c, 0x0c, 0x1e,
   12.97 +	0x00,
   12.98 +	0x7f, 0x63, 0x31, 0x18, 0x4c, 0x66, 0x7f, 0x00, 0x1e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1e, 0x00, 0x03, 0x06, 0x0c, 0x18,
   12.99 +	0x30,
  12.100 +	0x60, 0x40, 0x00, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1e, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
  12.101 +	0x00,
  12.102 +	0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
  12.103 +	0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x6e, 0x00, 0x07, 0x06, 0x06, 0x3e,
  12.104 +	0x66, 0x66, 0x3b, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x03, 0x33, 0x1e, 0x00, 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6e, 0x00,
  12.105 +	0x00,
  12.106 +	0x00, 0x1e, 0x33, 0x3f, 0x03, 0x1e, 0x00, 0x1c, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33,
  12.107 +	0x3e,
  12.108 +	0x30, 0x1f, 0x07, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x67, 0x00, 0x0c, 0x00, 0x0e, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x30, 0x00,
  12.109 +	0x30, 0x30, 0x30, 0x33, 0x33, 0x1e, 0x07, 0x06, 0x66, 0x36, 0x1e, 0x36, 0x67, 0x00, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
  12.110 +	0x1e,
  12.111 +	0x00, 0x00, 0x00, 0x33, 0x7f, 0x7f, 0x6b, 0x63, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e,
  12.112 +	0x33,
  12.113 +	0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66, 0x3e, 0x06, 0x0f, 0x00, 0x00, 0x6e, 0x33, 0x33, 0x3e, 0x30, 0x78,
  12.114 +	0x00,
  12.115 +	0x00, 0x3b, 0x6e, 0x66, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x3e, 0x03, 0x1e, 0x30, 0x1f, 0x00, 0x08, 0x0c, 0x3e, 0x0c, 0x0c,
  12.116 +	0x2c,
  12.117 +	0x18, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x1e, 0x0c, 0x00, 0x00, 0x00,
  12.118 +	0x63,
  12.119 +	0x6b, 0x7f, 0x7f, 0x36, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x3e, 0x30,
  12.120 +	0x1f,
  12.121 +	0x00, 0x00, 0x3f, 0x19, 0x0c, 0x26, 0x3f, 0x00, 0x38, 0x0c, 0x0c, 0x07, 0x0c, 0x0c, 0x38, 0x00, 0x18, 0x18, 0x18, 0x00,
  12.122 +	0x18,
  12.123 +	0x18, 0x18, 0x00, 0x07, 0x0c, 0x0c, 0x38, 0x0c, 0x0c, 0x07, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  12.124 +	0x08,
  12.125 +	0x1c, 0x36, 0x63, 0x63, 0x7f, 0x00,
  12.126 +	0x1e, 0x33, 0x03, 0x33, 0x1e, 0x18, 0x30, 0x1e, 0x00, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7e, 0x00, 0x38, 0x00, 0x1e, 0x33,
  12.127 +	0x3f, 0x03, 0x1e, 0x00, 0x7e, 0xc3, 0x3c, 0x60, 0x7c, 0x66, 0xfc, 0x00, 0x33, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x7e, 0x00,
  12.128 +	0x07,
  12.129 +	0x00, 0x1e, 0x30, 0x3e, 0x33, 0x7e, 0x00, 0x0c, 0x0c, 0x1e, 0x30, 0x3e, 0x33, 0x7e, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x03,
  12.130 +	0x1e,
  12.131 +	0x30, 0x1c, 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x06, 0x3c, 0x00, 0x33, 0x00, 0x1e, 0x33, 0x3f, 0x03, 0x1e, 0x00, 0x07, 0x00,
  12.132 +	0x1e, 0x33, 0x3f, 0x03, 0x1e, 0x00, 0x33, 0x00, 0x0e, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x3e, 0x63, 0x1c, 0x18, 0x18, 0x18,
  12.133 +	0x3c,
  12.134 +	0x00, 0x07, 0x00, 0x0e, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x63, 0x1c, 0x36, 0x63, 0x7f, 0x63, 0x63, 0x00, 0x0c, 0x0c, 0x00,
  12.135 +	0x1e,
  12.136 +	0x33, 0x3f, 0x33, 0x00, 0x38, 0x00, 0x3f, 0x06, 0x1e, 0x06, 0x3f, 0x00, 0x00, 0x00, 0xfe, 0x30, 0xfe, 0x33, 0xfe, 0x00,
  12.137 +	0x7c,
  12.138 +	0x36, 0x33, 0x7f, 0x33, 0x33, 0x73, 0x00, 0x1e, 0x33, 0x00, 0x1e, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x33, 0x00, 0x1e, 0x33,
  12.139 +	0x33,
  12.140 +	0x1e, 0x00, 0x00, 0x07, 0x00, 0x1e, 0x33, 0x33, 0x1e, 0x00, 0x1e, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7e, 0x00, 0x00, 0x07,
  12.141 +	0x00,
  12.142 +	0x33, 0x33, 0x33, 0x7e, 0x00, 0x00, 0x33, 0x00, 0x33, 0x33, 0x3e, 0x30, 0x1f, 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18,
  12.143 +	0x00,
  12.144 +	0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x00, 0x18, 0x18, 0x7e, 0x03, 0x03, 0x7e, 0x18, 0x18, 0x1c, 0x36, 0x26, 0x0f,
  12.145 +	0x06,
  12.146 +	0x67, 0x3f, 0x00, 0x33, 0x33, 0x1e, 0x3f, 0x0c, 0x3f, 0x0c, 0x0c, 0x1f, 0x33, 0x33, 0x5f, 0x63, 0xf3, 0x63, 0xe3, 0x70,
  12.147 +	0xd8,
  12.148 +	0x18, 0x3c, 0x18, 0x18, 0x1b, 0x0e,
  12.149 +	0x38, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x7e, 0x00, 0x1c, 0x00, 0x0e, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x38, 0x00, 0x1e,
  12.150 +	0x33, 0x33, 0x1e, 0x00, 0x00, 0x38, 0x00, 0x33, 0x33, 0x33, 0x7e, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x33, 0x33, 0x33, 0x00,
  12.151 +	0x3f,
  12.152 +	0x00, 0x33, 0x37, 0x3f, 0x3b, 0x33, 0x00, 0x3c, 0x36, 0x36, 0x7c, 0x00, 0x7e, 0x00, 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00,
  12.153 +	0x3e,
  12.154 +	0x00, 0x00, 0x0c, 0x00, 0x0c, 0x06, 0x03, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
  12.155 +	0x00, 0x3f, 0x30, 0x30, 0x00, 0x00, 0xc3, 0x63, 0x33, 0x7b, 0xcc, 0x66, 0x33, 0xf0, 0xc3, 0x63, 0x33, 0xdb, 0xec, 0xf6,
  12.156 +	0xf3,
  12.157 +	0xc0, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, 0x00, 0x33, 0x66,
  12.158 +	0xcc,
  12.159 +	0x66, 0x33, 0x00, 0x00, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55,
  12.160 +	0xdb,
  12.161 +	0xee, 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f,
  12.162 +	0x18,
  12.163 +	0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x6c, 0x6c, 0x6c, 0x00, 0x00,
  12.164 +	0x00,
  12.165 +	0x00, 0x7f, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x6c, 0x6c, 0x6f, 0x60, 0x6f, 0x6c, 0x6c,
  12.166 +	0x6c,
  12.167 +	0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x7f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60,
  12.168 +	0x7f,
  12.169 +	0x00, 0x00, 0x00, 0x6c, 0x6c, 0x6c, 0x6c, 0x7f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
  12.170 +	0x00,
  12.171 +	0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
  12.172 +	0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  12.173 +	0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
  12.174 +	0x18,
  12.175 +	0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x6c, 0x6c, 0x6c, 0x6c, 0xec,
  12.176 +	0x6c,
  12.177 +	0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
  12.178 +	0xef, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xec, 0x6c,
  12.179 +	0x6c,
  12.180 +	0x6c, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xef, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x18, 0x18, 0xff,
  12.181 +	0x00,
  12.182 +	0xff, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
  12.183 +	0x00,
  12.184 +	0x00, 0x00, 0x00, 0xff, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xfc, 0x00, 0x00, 0x00, 0x18, 0x18, 0xf8, 0x18, 0xf8,
  12.185 +	0x00,
  12.186 +	0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
  12.187 +	0x6c,
  12.188 +	0x6c, 0xff, 0x6c, 0x6c, 0x6c, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00,
  12.189 +	0x00,
  12.190 +	0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  12.191 +	0xff,
  12.192 +	0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff,
  12.193 +	0xff,
  12.194 +	0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  12.195 +	0x00, 0x00, 0x6e, 0x3b, 0x13, 0x3b, 0x6e, 0x00, 0x00, 0x1e, 0x33, 0x1f, 0x33, 0x1f, 0x03, 0x03, 0x00, 0x3f, 0x33, 0x03,
  12.196 +	0x03, 0x03, 0x03, 0x00, 0x00, 0x7f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x3f, 0x33, 0x06, 0x0c, 0x06, 0x33, 0x3f, 0x00,
  12.197 +	0x00,
  12.198 +	0x00, 0x7e, 0x1b, 0x1b, 0x1b, 0x0e, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x03, 0x00, 0x6e, 0x3b, 0x18, 0x18,
  12.199 +	0x18,
  12.200 +	0x18, 0x00, 0x3f, 0x0c, 0x1e, 0x33, 0x33, 0x1e, 0x0c, 0x3f, 0x1c, 0x36, 0x63, 0x7f, 0x63, 0x36, 0x1c, 0x00, 0x1c, 0x36,
  12.201 +	0x63, 0x63, 0x36, 0x36, 0x77, 0x00, 0x38, 0x0c, 0x18, 0x3e, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e,
  12.202 +	0x00,
  12.203 +	0x00, 0x60, 0x30, 0x7e, 0xdb, 0xdb, 0x7e, 0x06, 0x03, 0x1c, 0x06, 0x03, 0x1f, 0x03, 0x06, 0x1c, 0x00, 0x1e, 0x33, 0x33,
  12.204 +	0x33,
  12.205 +	0x33, 0x33, 0x33, 0x00, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x00, 0x3f, 0x00,
  12.206 +	0x06,
  12.207 +	0x0c, 0x18, 0x0c, 0x06, 0x00, 0x3f, 0x00, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x00, 0x3f, 0x00, 0x70, 0xd8, 0xd8, 0x18, 0x18,
  12.208 +	0x18,
  12.209 +	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x1b, 0x0e, 0x0c, 0x0c, 0x00, 0x3f, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x6e,
  12.210 +	0x3b,
  12.211 +	0x00, 0x6e, 0x3b, 0x00, 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
  12.212 +	0x00,
  12.213 +	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xf0, 0x30, 0x30, 0x30, 0x37, 0x36, 0x3c, 0x38, 0x1e, 0x36, 0x36, 0x36,
  12.214 +	0x36,
  12.215 +	0x00, 0x00, 0x00, 0x0e, 0x18, 0x0c, 0x06, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00,
  12.216 +	0x00,
  12.217 +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  12.218 +};
  12.219 +
  12.220 +static void calcColors(const int colorNum, int & lo, int & hi, int & out)
  12.221 +{
  12.222 +	int redLo, redHi, greenLo, greenHi, blueLo, blueHi;
  12.223 +
  12.224 +	if (colorNum == 0 || colorNum == 1 || colorNum == 2 || colorNum == 6) // white, red, yellow, or magenta
  12.225 +		redLo = (0xf) << systemRedShift, redHi = (0x1f) << systemRedShift;
  12.226 +	else
  12.227 +		redLo = redHi = 0;
  12.228 +
  12.229 +	if (colorNum == 0 || colorNum == 2 || colorNum == 3 || colorNum == 4) // white, yellow, green, or cyan
  12.230 +		greenLo = (0xf) << systemGreenShift, greenHi = (0x1f) << systemGreenShift;
  12.231 +	else
  12.232 +		greenLo = greenHi = 0;
  12.233 +
  12.234 +	if (colorNum == 0 || colorNum == 4 || colorNum == 5 || colorNum == 6) // white, cyan, blue, or magenta
  12.235 +		blueLo = (0xf) << systemBlueShift, blueHi = (0x1f) << systemBlueShift;
  12.236 +	else
  12.237 +		blueLo = blueHi = 0;
  12.238 +
  12.239 +	lo = redLo + greenLo + blueLo;
  12.240 +	hi = redHi + greenHi + blueHi;
  12.241 +
  12.242 +	if (colorNum == 7) // black
  12.243 +		out = 0xffffffff; // white border
  12.244 +	else
  12.245 +		out = 0;  // black border
  12.246 +}
  12.247 +
  12.248 +int lastColID = 0;
  12.249 +static void progressColorList(const char *& colorList, int & lo, int & hi, int & out)
  12.250 +{
  12.251 +	if (*colorList)
  12.252 +	{
  12.253 +		if (*colorList != lastColID)
  12.254 +		{
  12.255 +			calcColors((int)(*colorList)-1, lo, hi, out);
  12.256 +			lastColID = *colorList;
  12.257 +		}
  12.258 +		colorList++;
  12.259 +	}
  12.260 +	else
  12.261 +	{
  12.262 +		colorList = NULL;
  12.263 +	}
  12.264 +}
  12.265 +
  12.266 +static void drawTextInternal(u8 *screen, int pitch, int x, int y,
  12.267 +                             const char *string, bool trans, const char *colorList = NULL)
  12.268 +{
  12.269 +	if (colorList && !*colorList)
  12.270 +		colorList = NULL;
  12.271 +
  12.272 +	int loCol, hiCol, outCol;
  12.273 +	calcColors(textColor, loCol, hiCol, outCol);
  12.274 +
  12.275 +	lastColID = 0;
  12.276 +
  12.277 +	const static int xd [8] = {-1, 0, 1, 1, 1, 0, -1, -1};
  12.278 +	const static int yd [8] = {-1, -1, -1, 0, 1, 1, 1, 0};
  12.279 +
  12.280 +	screen += y*pitch;
  12.281 +	int inc = 2;
  12.282 +	switch (systemColorDepth)
  12.283 +	{
  12.284 +	case 24:
  12.285 +		inc = 3;
  12.286 +		break;
  12.287 +	case 32:
  12.288 +		inc = 4;
  12.289 +		break;
  12.290 +	}
  12.291 +	screen += x*inc;
  12.292 +
  12.293 +	int xpos = x;
  12.294 +	switch (systemColorDepth)
  12.295 +	{
  12.296 +	case 16:
  12.297 +	{
  12.298 +		while (*string)
  12.299 +		{
  12.300 +			char c   = *string++;
  12.301 +			u8 * scr = screen;
  12.302 +
  12.303 +			if (colorList)
  12.304 +				progressColorList(colorList, loCol, hiCol, outCol);
  12.305 +
  12.306 +			u16  mask = u16(~RGB_LOW_BITS_MASK);
  12.307 +			u16 *s = (u16 *)scr;
  12.308 +			for (int h = 0-1; h < 8+1; h++)
  12.309 +			{
  12.310 +				for (int w = 0-1; w < 8+1; w++, s++)
  12.311 +				{
  12.312 +					int on = (h < 0 || w < 0 || h >= 8 || w >= 8) ? 0 : (fontdata2[(c<<3)+h]>>w)&1;
  12.313 +
  12.314 +					int border = 0;
  12.315 +					if (outlinedText)
  12.316 +						for (int i = 0; i < 8; i++)
  12.317 +						{
  12.318 +							int h2 = h+yd[i], w2 = w+xd[i];
  12.319 +							border = (h2 < 0 || w2 < 0 || h2 >= 8 || w2 >= 8) ? 0 : (fontdata2[(c<<3)+h2]>>w2)&1;
  12.320 +							if (border)
  12.321 +								break;
  12.322 +						}
  12.323 +
  12.324 +					if (trans)
  12.325 +					{
  12.326 +						if (on)
  12.327 +							*s = loCol +
  12.328 +							     ((*s & mask) >>1);
  12.329 +						else if (border)
  12.330 +						{
  12.331 +							*s = outCol +
  12.332 +							     ((*s & mask) >>1);
  12.333 +						}
  12.334 +					}
  12.335 +					else
  12.336 +					{
  12.337 +						if (on)
  12.338 +							*s = hiCol;
  12.339 +						else if (border)
  12.340 +							*s = outCol;
  12.341 +					}
  12.342 +				}
  12.343 +				scr += pitch;
  12.344 +				s    = (u16 *)scr;
  12.345 +			}
  12.346 +			screen += inc*8;
  12.347 +
  12.348 +			xpos += 8;
  12.349 +			if (xpos+8 > pitch>>1) // cut off text at right boundary
  12.350 +				break;
  12.351 +		}
  12.352 +		break;
  12.353 +	}
  12.354 +	case 24: // TODO: verify this code's correctness
  12.355 +	{
  12.356 +		while (*string)
  12.357 +		{
  12.358 +			char c   = *string++;
  12.359 +			u8 * scr = screen;
  12.360 +
  12.361 +			if (colorList)
  12.362 +				progressColorList(colorList, loCol, hiCol, outCol);
  12.363 +
  12.364 +			int h, w;
  12.365 +			u8 *s = (u8 *)scr;
  12.366 +			for (h = 0-1; h < 8+1; h++)
  12.367 +			{
  12.368 +				for (w = 0-1; w < 8+1; w++, s++)
  12.369 +				{
  12.370 +					int on = (h < 0 || w < 0 || h >= 8 || w >= 8) ? 0 : (fontdata2[(c<<3)+h]>>w)&1;
  12.371 +
  12.372 +					int border = 0;
  12.373 +					if (outlinedText)
  12.374 +						for (int i = 0; i < 8; i++)
  12.375 +						{
  12.376 +							int h2 = h+yd[i], w2 = w+xd[i];
  12.377 +							border = (h2 < 0 || w2 < 0 || h2 >= 8 || w2 >= 8) ? 0 : (fontdata2[(c<<3)+h2]>>w2)&1;
  12.378 +							if (border)
  12.379 +								break;
  12.380 +						}
  12.381 +
  12.382 +					if (trans)
  12.383 +					{
  12.384 +						if (on)
  12.385 +						{
  12.386 +							u32 color = hiCol;
  12.387 +							*s     = ((color & 255)>>1)+(*s>>1);
  12.388 +							*(s+1) = (((color >> 8) & 255)>>1)+(*(s+1)>>1);
  12.389 +							*(s+2) = (((color >> 16) & 255)>>1)+(*(s+2)>>1);
  12.390 +						}
  12.391 +						else if (border)
  12.392 +						{
  12.393 +							u32 color = outCol;
  12.394 +							*s     = ((color & 255)>>1)+(*s>>1);
  12.395 +							*(s+1) = (((color >> 8) & 255)>>1)+(*(s+1)>>1);
  12.396 +							*(s+2) = (((color >> 16) & 255)>>1)+(*(s+2)>>1);
  12.397 +						}
  12.398 +					}
  12.399 +					else
  12.400 +					{
  12.401 +						if (on)
  12.402 +						{
  12.403 +							u32 color = hiCol;
  12.404 +							*s     = (color & 255);
  12.405 +							*(s+1) = (color >> 8) & 255;
  12.406 +							*(s+2) = (color >> 16) & 255;
  12.407 +						}
  12.408 +						else if (border)
  12.409 +						{
  12.410 +							u32 color = outCol;
  12.411 +							*s     = (color & 255);
  12.412 +							*(s+1) = (color >> 8) & 255;
  12.413 +							*(s+2) = (color >> 16) & 255;
  12.414 +						}
  12.415 +					}
  12.416 +				}
  12.417 +				scr += pitch;
  12.418 +				s    = (u8 *)scr;
  12.419 +			}
  12.420 +			screen += inc*8;
  12.421 +
  12.422 +			xpos += 8;
  12.423 +			if (xpos+8 > pitch/3) // cut off text at right boundary
  12.424 +				break;
  12.425 +		}
  12.426 +		break;
  12.427 +	}
  12.428 +	case 32:
  12.429 +	{
  12.430 +		while (*string)
  12.431 +		{
  12.432 +			char c   = *string++;
  12.433 +			u8 * scr = screen;
  12.434 +
  12.435 +			if (colorList)
  12.436 +				progressColorList(colorList, loCol, hiCol, outCol);
  12.437 +
  12.438 +			int  h, w;
  12.439 +			u32  mask = 0xfefefe;
  12.440 +			u32 *s    = (u32 *)scr;
  12.441 +			for (h = 0-1; h < 8+1; h++)
  12.442 +			{
  12.443 +				for (w = 0-1; w < 8+1; w++, s++)
  12.444 +				{
  12.445 +					int on = (h < 0 || w < 0 || h >= 8 || w >= 8) ? 0 : (fontdata2[(c<<3)+h]>>w)&1;
  12.446 +
  12.447 +					int border = 0;
  12.448 +					if (outlinedText)
  12.449 +						for (int i = 0; i < 8; i++)
  12.450 +						{
  12.451 +							int h2 = h+yd[i], w2 = w+xd[i];
  12.452 +							border = (h2 < 0 || w2 < 0 || h2 >= 8 || w2 >= 8) ? 0 : (fontdata2[(c<<3)+h2]>>w2)&1;
  12.453 +							if (border)
  12.454 +								break;
  12.455 +						}
  12.456 +
  12.457 +					if (trans)
  12.458 +					{
  12.459 +						if (on)
  12.460 +							*s = loCol +
  12.461 +							     ((*s & mask)>>1);
  12.462 +						else if (border)
  12.463 +						{
  12.464 +							*s = outCol +
  12.465 +							     ((*s & mask)>>1);
  12.466 +						}
  12.467 +					}
  12.468 +					else
  12.469 +					{
  12.470 +						if (on)
  12.471 +							*s = hiCol;
  12.472 +						else if (border)
  12.473 +							*s = outCol;
  12.474 +					}
  12.475 +				}
  12.476 +				scr += pitch;
  12.477 +				s    = (u32 *)scr;
  12.478 +			}
  12.479 +			screen += inc*8;
  12.480 +
  12.481 +			xpos += 8;
  12.482 +			if (xpos+8 > pitch>>2) // cut off text at right boundary
  12.483 +				break;
  12.484 +		}
  12.485 +		break;
  12.486 +	}
  12.487 +	}
  12.488 +}
  12.489 +
  12.490 +void drawText(u8 *screen, int pitch, int x, int y, const char *string, const char *colorList)
  12.491 +{
  12.492 +	drawTextInternal(screen, pitch, x, y, string, transparentText, colorList);
  12.493 +}
  12.494 +
  12.495 +void drawTextTransp(u8 *screen, int pitch, int x, int y, const char *string, const char *colorList)
  12.496 +{
  12.497 +	drawTextInternal(screen, pitch, x, y, string, true, colorList);
  12.498 +}
  12.499 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/common/Text.h	Sun Mar 04 14:33:52 2012 -0600
    13.3 @@ -0,0 +1,14 @@
    13.4 +#ifndef VBA_TEXT_H
    13.5 +#define VBA_TEXT_H
    13.6 +
    13.7 +#if _MSC_VER > 1000
    13.8 +#pragma once
    13.9 +#endif // _MSC_VER > 1000
   13.10 +
   13.11 +extern void drawText(u8 *, int, int, int, const char *, const char*cl = NULL);
   13.12 +extern void drawTextTransp(u8 *, int, int, int, const char *, const char*cl = NULL);
   13.13 +
   13.14 +extern bool outlinedText, transparentText;
   13.15 +extern int  textColor, textMethod;
   13.16 +
   13.17 +#endif // VBA_TEXT_H
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/common/Util.cpp	Sun Mar 04 14:33:52 2012 -0600
    14.3 @@ -0,0 +1,1400 @@
    14.4 +#include <cstdio>
    14.5 +#include <cstdlib>
    14.6 +#include <cstring>
    14.7 +#include <zlib.h>
    14.8 +
    14.9 +extern "C" {
   14.10 +#include <png.h>
   14.11 +}
   14.12 +
   14.13 +#if 0
   14.14 +#include "unrarlib.h"
   14.15 +#endif
   14.16 +
   14.17 +#include "unzip.h"
   14.18 +
   14.19 +#include "../NLS.h"
   14.20 +#include "System.h"
   14.21 +#include "Util.h"
   14.22 +#include "../gba/Flash.h"
   14.23 +#include "../gba/RTC.h"
   14.24 +
   14.25 +extern "C" {
   14.26 +#include "memgzio.h"
   14.27 +}
   14.28 +
   14.29 +#ifndef _MSC_VER
   14.30 +#define _stricmp strcasecmp
   14.31 +#endif // ! _MSC_VER
   14.32 +
   14.33 +extern int32 cpuSaveType;
   14.34 +
   14.35 +extern int systemColorDepth;
   14.36 +extern int systemRedShift;
   14.37 +extern int systemGreenShift;
   14.38 +extern int systemBlueShift;
   14.39 +
   14.40 +extern u16 systemColorMap16[0x10000];
   14.41 +extern u32 systemColorMap32[0x10000];
   14.42 +
   14.43 +static int	   (ZEXPORT *utilGzWriteFunc)(gzFile, voidp, unsigned int) = NULL;
   14.44 +static int	   (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int)  = NULL;
   14.45 +static int	   (ZEXPORT *utilGzCloseFunc)(gzFile) = NULL;
   14.46 +static z_off_t (ZEXPORT *utilGzSeekFunc)(gzFile, z_off_t, int) = NULL;
   14.47 +static z_off_t (ZEXPORT *utilGzTellFunc)(gzFile) = NULL;
   14.48 +
   14.49 +//Kludge to get it to compile in Linux, GCC cannot convert
   14.50 +//gzwrite function pointer to the type of utilGzWriteFunc
   14.51 +//due to void* and const void* differences
   14.52 +//--Felipe 
   14.53 +int gzWrite(gzFile file, void* buf, unsigned len){
   14.54 +	return gzwrite(file,buf,len);
   14.55 +}
   14.56 +
   14.57 +void utilPutDword(u8 *p, u32 value)
   14.58 +{
   14.59 +	*p++ = value & 255;
   14.60 +	*p++ = (value >> 8) & 255;
   14.61 +	*p++ = (value >> 16) & 255;
   14.62 +	*p	 = (value >> 24) & 255;
   14.63 +}
   14.64 +
   14.65 +void utilPutWord(u8 *p, u16 value)
   14.66 +{
   14.67 +	*p++ = value & 255;
   14.68 +	*p	 = (value >> 8) & 255;
   14.69 +}
   14.70 +
   14.71 +void utilWriteBMP(u8 *b, int w, int h, int dstDepth, u8 *pix)
   14.72 +{
   14.73 +	int sizeX = w;
   14.74 +	int sizeY = h;
   14.75 +
   14.76 +	switch (dstDepth > 0 ? dstDepth : systemColorDepth)
   14.77 +	{
   14.78 +	case 16:
   14.79 +	{
   14.80 +		u16 *p = (u16 *)(pix + (w + 2) * (h) * 2); // skip first black line
   14.81 +		for (int y = 0; y < sizeY; y++)
   14.82 +		{
   14.83 +			for (int x = 0; x < sizeX; x++)
   14.84 +			{
   14.85 +				u16 v = *p++;
   14.86 +
   14.87 +				*b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
   14.88 +				*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
   14.89 +				*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
   14.90 +			}
   14.91 +			p++; // skip black pixel for filters
   14.92 +			p++; // skip black pixel for filters
   14.93 +			p -= 2 * (w + 2);
   14.94 +		}
   14.95 +		break;
   14.96 +	}
   14.97 +	case 24:
   14.98 +	{
   14.99 +		u8 *pixU8 = (u8 *)pix + 3 * w * (h - 1);
  14.100 +		for (int y = 0; y < sizeY; y++)
  14.101 +		{
  14.102 +			for (int x = 0; x < sizeX; x++)
  14.103 +			{
  14.104 +				if (systemRedShift > systemBlueShift)
  14.105 +				{
  14.106 +					*b++ = *pixU8++; // B
  14.107 +					*b++ = *pixU8++; // G
  14.108 +					*b++ = *pixU8++; // R
  14.109 +				}
  14.110 +				else
  14.111 +				{
  14.112 +					int red	  = *pixU8++;
  14.113 +					int green = *pixU8++;
  14.114 +					int blue  = *pixU8++;
  14.115 +
  14.116 +					*b++ = blue;
  14.117 +					*b++ = green;
  14.118 +					*b++ = red;
  14.119 +				}
  14.120 +			}
  14.121 +			pixU8 -= 2 * 3 * w;
  14.122 +		}
  14.123 +		break;
  14.124 +	}
  14.125 +	case 32:
  14.126 +	{
  14.127 +		u32 *pixU32 = (u32 *)(pix + 4 * (w + 1) * (h));
  14.128 +		for (int y = 0; y < sizeY; y++)
  14.129 +		{
  14.130 +			for (int x = 0; x < sizeX; x++)
  14.131 +			{
  14.132 +				u32 v = *pixU32++;
  14.133 +
  14.134 +				*b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
  14.135 +				*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
  14.136 +				*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
  14.137 +			}
  14.138 +			pixU32++;
  14.139 +			pixU32 -= 2 * (w + 1);
  14.140 +		}
  14.141 +		break;
  14.142 +	}
  14.143 +	}
  14.144 +}
  14.145 +
  14.146 +bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix)
  14.147 +{
  14.148 +	u8 writeBuffer[256 * 3];
  14.149 +
  14.150 +	FILE *fp = fopen(fileName, "wb");
  14.151 +
  14.152 +	if (!fp)
  14.153 +	{
  14.154 +		systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName);
  14.155 +		return false;
  14.156 +	}
  14.157 +
  14.158 +	struct
  14.159 +	{
  14.160 +		u8 ident[2];
  14.161 +		u8 filesize[4];
  14.162 +		u8 reserved[4];
  14.163 +		u8 dataoffset[4];
  14.164 +		u8 headersize[4];
  14.165 +		u8 width[4];
  14.166 +		u8 height[4];
  14.167 +		u8 planes[2];
  14.168 +		u8 bitsperpixel[2];
  14.169 +		u8 compression[4];
  14.170 +		u8 datasize[4];
  14.171 +		u8 hres[4];
  14.172 +		u8 vres[4];
  14.173 +		u8 colors[4];
  14.174 +		u8 importantcolors[4];
  14.175 +		//    u8 pad[2];
  14.176 +	} bmpheader;
  14.177 +	memset(&bmpheader, 0, sizeof(bmpheader));
  14.178 +
  14.179 +	bmpheader.ident[0] = 'B';
  14.180 +	bmpheader.ident[1] = 'M';
  14.181 +
  14.182 +	u32 fsz = sizeof(bmpheader) + w * h * 3;
  14.183 +	utilPutDword(bmpheader.filesize, fsz);
  14.184 +	utilPutDword(bmpheader.dataoffset, 0x36);
  14.185 +	utilPutDword(bmpheader.headersize, 0x28);
  14.186 +	utilPutDword(bmpheader.width, w);
  14.187 +	utilPutDword(bmpheader.height, h);
  14.188 +	utilPutDword(bmpheader.planes, 1);
  14.189 +	utilPutDword(bmpheader.bitsperpixel, 24);
  14.190 +	utilPutDword(bmpheader.datasize, 3 * w * h);
  14.191 +
  14.192 +	fwrite(&bmpheader, 1, sizeof(bmpheader), fp);
  14.193 +
  14.194 +#if 0
  14.195 +	// FIXME: need sufficient buffer
  14.196 +	utilWriteBMP(writeBuffer, w, h, systemColorDepth, pix);
  14.197 +#else
  14.198 +	u8 *b = writeBuffer;
  14.199 +
  14.200 +	int sizeX = w;
  14.201 +	int sizeY = h;
  14.202 +
  14.203 +	switch (systemColorDepth)
  14.204 +	{
  14.205 +	case 16:
  14.206 +	{
  14.207 +		u16 *p = (u16 *)(pix + (w + 2) * (h) * 2); // skip first black line
  14.208 +		for (int y = 0; y < sizeY; y++)
  14.209 +		{
  14.210 +			for (int x = 0; x < sizeX; x++)
  14.211 +			{
  14.212 +				u16 v = *p++;
  14.213 +
  14.214 +				*b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
  14.215 +				*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
  14.216 +				*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
  14.217 +			}
  14.218 +			p++; // skip black pixel for filters
  14.219 +			p++; // skip black pixel for filters
  14.220 +			p -= 2 * (w + 2);
  14.221 +			fwrite(writeBuffer, 1, 3 * w, fp);
  14.222 +
  14.223 +			b = writeBuffer;
  14.224 +		}
  14.225 +		break;
  14.226 +	}
  14.227 +	case 24:
  14.228 +	{
  14.229 +		u8 *pixU8 = (u8 *)pix + 3 * w * (h - 1);
  14.230 +		for (int y = 0; y < sizeY; y++)
  14.231 +		{
  14.232 +			for (int x = 0; x < sizeX; x++)
  14.233 +			{
  14.234 +				if (systemRedShift > systemBlueShift)
  14.235 +				{
  14.236 +					*b++ = *pixU8++; // B
  14.237 +					*b++ = *pixU8++; // G
  14.238 +					*b++ = *pixU8++; // R
  14.239 +				}
  14.240 +				else
  14.241 +				{
  14.242 +					int red	  = *pixU8++;
  14.243 +					int green = *pixU8++;
  14.244 +					int blue  = *pixU8++;
  14.245 +
  14.246 +					*b++ = blue;
  14.247 +					*b++ = green;
  14.248 +					*b++ = red;
  14.249 +				}
  14.250 +			}
  14.251 +			pixU8 -= 2 * 3 * w;
  14.252 +			fwrite(writeBuffer, 1, 3 * w, fp);
  14.253 +
  14.254 +			b = writeBuffer;
  14.255 +		}
  14.256 +		break;
  14.257 +	}
  14.258 +	case 32:
  14.259 +	{
  14.260 +		u32 *pixU32 = (u32 *)(pix + 4 * (w + 1) * (h));
  14.261 +		for (int y = 0; y < sizeY; y++)
  14.262 +		{
  14.263 +			for (int x = 0; x < sizeX; x++)
  14.264 +			{
  14.265 +				u32 v = *pixU32++;
  14.266 +
  14.267 +				*b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
  14.268 +				*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
  14.269 +				*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
  14.270 +			}
  14.271 +			pixU32++;
  14.272 +			pixU32 -= 2 * (w + 1);
  14.273 +
  14.274 +			fwrite(writeBuffer, 1, 3 * w, fp);
  14.275 +
  14.276 +			b = writeBuffer;
  14.277 +		}
  14.278 +		break;
  14.279 +	}
  14.280 +	}
  14.281 +#endif
  14.282 +
  14.283 +	fclose(fp);
  14.284 +
  14.285 +	return true;
  14.286 +}
  14.287 +
  14.288 +bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix)
  14.289 +{
  14.290 +	u8 writeBuffer[256 * 3];
  14.291 +
  14.292 +	FILE *fp = fopen(fileName, "wb");
  14.293 +
  14.294 +	if (!fp)
  14.295 +	{
  14.296 +		systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName);
  14.297 +		return false;
  14.298 +	}
  14.299 +
  14.300 +	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
  14.301 +	                                              NULL,
  14.302 +	                                              NULL,
  14.303 +	                                              NULL);
  14.304 +	if (!png_ptr)
  14.305 +	{
  14.306 +		fclose(fp);
  14.307 +		return false;
  14.308 +	}
  14.309 +
  14.310 +	png_infop info_ptr = png_create_info_struct(png_ptr);
  14.311 +
  14.312 +	if (!info_ptr)
  14.313 +	{
  14.314 +		png_destroy_write_struct(&png_ptr, NULL);
  14.315 +		fclose(fp);
  14.316 +		return false;
  14.317 +	}
  14.318 +
  14.319 +	if (setjmp(png_ptr->jmpbuf))
  14.320 +	{
  14.321 +		png_destroy_write_struct(&png_ptr, NULL);
  14.322 +		fclose(fp);
  14.323 +		return false;
  14.324 +	}
  14.325 +
  14.326 +	png_init_io(png_ptr, fp);
  14.327 +
  14.328 +	png_set_IHDR(png_ptr,
  14.329 +	             info_ptr,
  14.330 +	             w,
  14.331 +	             h,
  14.332 +	             8,
  14.333 +	             PNG_COLOR_TYPE_RGB,
  14.334 +	             PNG_INTERLACE_NONE,
  14.335 +	             PNG_COMPRESSION_TYPE_DEFAULT,
  14.336 +	             PNG_FILTER_TYPE_DEFAULT);
  14.337 +
  14.338 +	png_write_info(png_ptr, info_ptr);
  14.339 +
  14.340 +	u8 *b = writeBuffer;
  14.341 +
  14.342 +	int sizeX = w;
  14.343 +	int sizeY = h;
  14.344 +
  14.345 +	switch (systemColorDepth)
  14.346 +	{
  14.347 +	case 16:
  14.348 +	{
  14.349 +		u16 *p = (u16 *)(pix + (w + 2) * 2); // skip first black line
  14.350 +		for (int y = 0; y < sizeY; y++)
  14.351 +		{
  14.352 +			for (int x = 0; x < sizeX; x++)
  14.353 +			{
  14.354 +				u16 v = *p++;
  14.355 +
  14.356 +				*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
  14.357 +				*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
  14.358 +				*b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
  14.359 +			}
  14.360 +			p++; // skip black pixel for filters
  14.361 +			p++; // skip black pixel for filters
  14.362 +			png_write_row(png_ptr, writeBuffer);
  14.363 +
  14.364 +			b = writeBuffer;
  14.365 +		}
  14.366 +		break;
  14.367 +	}
  14.368 +	case 24:
  14.369 +	{
  14.370 +		u8 *pixU8 = (u8 *)pix;
  14.371 +		for (int y = 0; y < sizeY; y++)
  14.372 +		{
  14.373 +			for (int x = 0; x < sizeX; x++)
  14.374 +			{
  14.375 +				if (systemRedShift < systemBlueShift)
  14.376 +				{
  14.377 +					*b++ = *pixU8++; // R
  14.378 +					*b++ = *pixU8++; // G
  14.379 +					*b++ = *pixU8++; // B
  14.380 +				}
  14.381 +				else
  14.382 +				{
  14.383 +					int blue  = *pixU8++;
  14.384 +					int green = *pixU8++;
  14.385 +					int red	  = *pixU8++;
  14.386 +
  14.387 +					*b++ = red;
  14.388 +					*b++ = green;
  14.389 +					*b++ = blue;
  14.390 +				}
  14.391 +			}
  14.392 +			png_write_row(png_ptr, writeBuffer);
  14.393 +
  14.394 +			b = writeBuffer;
  14.395 +		}
  14.396 +		break;
  14.397 +	}
  14.398 +	case 32:
  14.399 +	{
  14.400 +		u32 *pixU32 = (u32 *)(pix + 4 * (w + 1));
  14.401 +		for (int y = 0; y < sizeY; y++)
  14.402 +		{
  14.403 +			for (int x = 0; x < sizeX; x++)
  14.404 +			{
  14.405 +				u32 v = *pixU32++;
  14.406 +
  14.407 +				*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
  14.408 +				*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
  14.409 +				*b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
  14.410 +			}
  14.411 +			pixU32++;
  14.412 +
  14.413 +			png_write_row(png_ptr, writeBuffer);
  14.414 +
  14.415 +			b = writeBuffer;
  14.416 +		}
  14.417 +		break;
  14.418 +	}
  14.419 +	}
  14.420 +
  14.421 +	png_write_end(png_ptr, info_ptr);
  14.422 +
  14.423 +	png_destroy_write_struct(&png_ptr, &info_ptr);
  14.424 +
  14.425 +	fclose(fp);
  14.426 +
  14.427 +	return true;
  14.428 +}
  14.429 +
  14.430 +static int utilReadInt2(FILE *f)
  14.431 +{
  14.432 +	int res = 0;
  14.433 +	int c	= fgetc(f);
  14.434 +	if (c == EOF)
  14.435 +		return -1;
  14.436 +	res = c;
  14.437 +	c	= fgetc(f);
  14.438 +	if (c == EOF)
  14.439 +		return -1;
  14.440 +	return c + (res << 8);
  14.441 +}
  14.442 +
  14.443 +static int utilReadInt3(FILE *f)
  14.444 +{
  14.445 +	int res = 0;
  14.446 +	int c	= fgetc(f);
  14.447 +	if (c == EOF)
  14.448 +		return -1;
  14.449 +	res = c;
  14.450 +	c	= fgetc(f);
  14.451 +	if (c == EOF)
  14.452 +		return -1;
  14.453 +	res = c + (res << 8);
  14.454 +	c	= fgetc(f);
  14.455 +	if (c == EOF)
  14.456 +		return -1;
  14.457 +	return c + (res << 8);
  14.458 +}
  14.459 +
  14.460 +void utilApplyIPS(const char *ips, u8 * *r, int *s)
  14.461 +{
  14.462 +	// from the IPS spec at http://zerosoft.zophar.net/ips.htm
  14.463 +	FILE *f = fopen(ips, "rb");
  14.464 +	if (!f)
  14.465 +		return;
  14.466 +	u8 *rom	 = *r;
  14.467 +	int size = *s;
  14.468 +	if (fgetc(f) == 'P' &&
  14.469 +	    fgetc(f) == 'A' &&
  14.470 +	    fgetc(f) == 'T' &&
  14.471 +	    fgetc(f) == 'C' &&
  14.472 +	    fgetc(f) == 'H')
  14.473 +	{
  14.474 +		int b;
  14.475 +		int offset;
  14.476 +		int len;
  14.477 +		for (;; )
  14.478 +		{
  14.479 +			// read offset
  14.480 +			offset = utilReadInt3(f);
  14.481 +			// if offset == EOF, end of patch
  14.482 +			if (offset == 0x454f46)
  14.483 +				break;
  14.484 +			// read length
  14.485 +			len = utilReadInt2(f);
  14.486 +			if (!len)
  14.487 +			{
  14.488 +				// len == 0, RLE block
  14.489 +				len = utilReadInt2(f);
  14.490 +				// byte to fill
  14.491 +				int c = fgetc(f);
  14.492 +				if (c == -1)
  14.493 +					break;
  14.494 +				b = (u8)c;
  14.495 +			}
  14.496 +			else
  14.497 +				b = -1;
  14.498 +			// check if we need to reallocate our ROM
  14.499 +			if ((offset + len) >= size)
  14.500 +			{
  14.501 +				size *= 2;
  14.502 +				rom	  = (u8 *)realloc(rom, size);
  14.503 +				*r	  = rom;
  14.504 +				*s	  = size;
  14.505 +			}
  14.506 +			if (b == -1)
  14.507 +			{
  14.508 +				// normal block, just read the data
  14.509 +				if (fread(&rom[offset], 1, len, f) != (size_t)len)
  14.510 +					break;
  14.511 +			}
  14.512 +			else
  14.513 +			{
  14.514 +				// fill the region with the given byte
  14.515 +				while (len--)
  14.516 +				{
  14.517 +					rom[offset++] = b;
  14.518 +				}
  14.519 +			}
  14.520 +		}
  14.521 +	}
  14.522 +	// close the file
  14.523 +	fclose(f);
  14.524 +}
  14.525 +
  14.526 +extern bool8 cpuIsMultiBoot;
  14.527 +
  14.528 +bool utilIsGBAImage(const char *file)
  14.529 +{
  14.530 +	cpuIsMultiBoot = false;
  14.531 +	if (strlen(file) > 4)
  14.532 +	{
  14.533 +		const char *p = strrchr(file, '.');
  14.534 +
  14.535 +		if (p != NULL)
  14.536 +		{
  14.537 +			if (_stricmp(p, ".gba") == 0)
  14.538 +				return true;
  14.539 +			if (_stricmp(p, ".agb") == 0)
  14.540 +				return true;
  14.541 +			if (_stricmp(p, ".bin") == 0)
  14.542 +				return true;
  14.543 +			if (_stricmp(p, ".elf") == 0)
  14.544 +				return true;
  14.545 +			if (_stricmp(p, ".mb") == 0)
  14.546 +			{
  14.547 +				cpuIsMultiBoot = true;
  14.548 +				return true;
  14.549 +			}
  14.550 +		}
  14.551 +	}
  14.552 +
  14.553 +	return false;
  14.554 +}
  14.555 +
  14.556 +bool utilIsGBImage(const char *file)
  14.557 +{
  14.558 +	if (strlen(file) > 4)
  14.559 +	{
  14.560 +		const char *p = strrchr(file, '.');
  14.561 +
  14.562 +		if (p != NULL)
  14.563 +		{
  14.564 +			if (_stricmp(p, ".gb") == 0)
  14.565 +				return true;
  14.566 +			if (_stricmp(p, ".gbc") == 0)
  14.567 +				return true;
  14.568 +			if (_stricmp(p, ".cgb") == 0)
  14.569 +				return true;
  14.570 +			if (_stricmp(p, ".sgb") == 0)
  14.571 +				return true;
  14.572 +		}
  14.573 +	}
  14.574 +
  14.575 +	return false;
  14.576 +}
  14.577 +
  14.578 +bool utilIsGBABios(const char *file)
  14.579 +{
  14.580 +	if (strlen(file) > 4)
  14.581 +	{
  14.582 +		const char *p = strrchr(file, '.');
  14.583 +
  14.584 +		if (p != NULL)
  14.585 +		{
  14.586 +			if (_stricmp(p, ".gba") == 0)
  14.587 +				return true;
  14.588 +			if (_stricmp(p, ".agb") == 0)
  14.589 +				return true;
  14.590 +			if (_stricmp(p, ".bin") == 0)
  14.591 +				return true;
  14.592 +			if (_stricmp(p, ".bios") == 0)
  14.593 +				return true;
  14.594 +			if (_stricmp(p, ".rom") == 0)
  14.595 +				return true;
  14.596 +		}
  14.597 +	}
  14.598 +
  14.599 +	return false;
  14.600 +}
  14.601 +
  14.602 +bool utilIsGBBios(const char *file)
  14.603 +{
  14.604 +	if (strlen(file) > 4)
  14.605 +	{
  14.606 +		const char *p = strrchr(file, '.');
  14.607 +
  14.608 +		if (p != NULL)
  14.609 +		{
  14.610 +			if (_stricmp(p, ".gb") == 0)
  14.611 +				return true;
  14.612 +			if (_stricmp(p, ".bin") == 0)
  14.613 +				return true;
  14.614 +			if (_stricmp(p, ".bios") == 0)
  14.615 +				return true;
  14.616 +			if (_stricmp(p, ".rom") == 0)
  14.617 +				return true;
  14.618 +		}
  14.619 +	}
  14.620 +
  14.621 +	return false;
  14.622 +}
  14.623 +
  14.624 +bool utilIsELF(const char *file)
  14.625 +{
  14.626 +	if (strlen(file) > 4)
  14.627 +	{
  14.628 +		const char *p = strrchr(file, '.');
  14.629 +
  14.630 +		if (p != NULL)
  14.631 +		{
  14.632 +			if (_stricmp(p, ".elf") == 0)
  14.633 +				return true;
  14.634 +		}
  14.635 +	}
  14.636 +	return false;
  14.637 +}
  14.638 +
  14.639 +bool utilIsZipFile(const char *file)
  14.640 +{
  14.641 +	if (strlen(file) > 4)
  14.642 +	{
  14.643 +		const char *p = strrchr(file, '.');
  14.644 +
  14.645 +		if (p != NULL)
  14.646 +		{
  14.647 +			if (_stricmp(p, ".zip") == 0)
  14.648 +				return true;
  14.649 +		}
  14.650 +	}
  14.651 +
  14.652 +	return false;
  14.653 +}
  14.654 +
  14.655 +#if 0
  14.656 +bool utilIsRarFile(const char *file)
  14.657 +{
  14.658 +	if (strlen(file) > 4)
  14.659 +	{
  14.660 +		char *p = strrchr(file, '.');
  14.661 +
  14.662 +		if (p != NULL)
  14.663 +		{
  14.664 +			if (_stricmp(p, ".rar") == 0)
  14.665 +				return true;
  14.666 +		}
  14.667 +	}
  14.668 +
  14.669 +	return false;
  14.670 +}
  14.671 +
  14.672 +#endif
  14.673 +
  14.674 +bool utilIsGzipFile(const char *file)
  14.675 +{
  14.676 +	if (strlen(file) > 3)
  14.677 +	{
  14.678 +		const char *p = strrchr(file, '.');
  14.679 +
  14.680 +		if (p != NULL)
  14.681 +		{
  14.682 +			if (_stricmp(p, ".gz") == 0)
  14.683 +				return true;
  14.684 +			if (_stricmp(p, ".z") == 0)
  14.685 +				return true;
  14.686 +		}
  14.687 +	}
  14.688 +
  14.689 +	return false;
  14.690 +}
  14.691 +
  14.692 +void utilGetBaseName(const char *file, char *buffer)
  14.693 +{
  14.694 +	strcpy(buffer, file);
  14.695 +
  14.696 +	if (utilIsGzipFile(file))
  14.697 +	{
  14.698 +		char *p = strrchr(buffer, '.');
  14.699 +
  14.700 +		if (p)
  14.701 +			*p = 0;
  14.702 +	}
  14.703 +}
  14.704 +
  14.705 +IMAGE_TYPE utilFindType(const char *file)
  14.706 +{
  14.707 +	char buffer[2048];
  14.708 +
  14.709 +	if (utilIsZipFile(file))
  14.710 +	{
  14.711 +		unzFile unz = unzOpen(file);
  14.712 +
  14.713 +		if (unz == NULL)
  14.714 +		{
  14.715 +			systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file);
  14.716 +			return IMAGE_UNKNOWN;
  14.717 +		}
  14.718 +
  14.719 +		int r = unzGoToFirstFile(unz);
  14.720 +
  14.721 +		if (r != UNZ_OK)
  14.722 +		{
  14.723 +			unzClose(unz);
  14.724 +			systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file);
  14.725 +			return IMAGE_UNKNOWN;
  14.726 +		}
  14.727 +
  14.728 +		IMAGE_TYPE found = IMAGE_UNKNOWN;
  14.729 +
  14.730 +		unz_file_info info;
  14.731 +
  14.732 +		while (true)
  14.733 +		{
  14.734 +			r = unzGetCurrentFileInfo(unz,
  14.735 +			                          &info,
  14.736 +			                          buffer,
  14.737 +			                          sizeof(buffer),
  14.738 +			                          NULL,
  14.739 +			                          0,
  14.740 +			                          NULL,
  14.741 +			                          0);
  14.742 +
  14.743 +			if (r != UNZ_OK)
  14.744 +			{
  14.745 +				unzClose(unz);
  14.746 +				systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file);
  14.747 +				return IMAGE_UNKNOWN;
  14.748 +			}
  14.749 +
  14.750 +			if (utilIsGBAImage(buffer))
  14.751 +			{
  14.752 +				found = IMAGE_GBA;
  14.753 +				break;
  14.754 +			}
  14.755 +
  14.756 +			if (utilIsGBImage(buffer))
  14.757 +			{
  14.758 +				found = IMAGE_GB;
  14.759 +				break;
  14.760 +			}
  14.761 +
  14.762 +			r = unzGoToNextFile(unz);
  14.763 +
  14.764 +			if (r != UNZ_OK)
  14.765 +				break;
  14.766 +		}
  14.767 +		unzClose(unz);
  14.768 +
  14.769 +		if (found == IMAGE_UNKNOWN)
  14.770 +		{
  14.771 +			systemMessage(MSG_NO_IMAGE_ON_ZIP,
  14.772 +			              N_("No image found on ZIP file %s"), file);
  14.773 +			return found;
  14.774 +		}
  14.775 +		return found;
  14.776 +#if 0
  14.777 +	}
  14.778 +	else if (utilIsRarFile(file))
  14.779 +	{
  14.780 +		IMAGE_TYPE found = IMAGE_UNKNOWN;
  14.781 +
  14.782 +		ArchiveList_struct *rarList = NULL;
  14.783 +		if (urarlib_list((void *)file, (ArchiveList_struct *)&rarList))
  14.784 +		{
  14.785 +			ArchiveList_struct *p = rarList;
  14.786 +
  14.787 +			while (p)
  14.788 +			{
  14.789 +				if (utilIsGBAImage(p->item.Name))
  14.790 +				{
  14.791 +					found = IMAGE_GBA;
  14.792 +					break;
  14.793 +				}
  14.794 +
  14.795 +				if (utilIsGBImage(p->item.Name))
  14.796 +				{
  14.797 +					found = IMAGE_GB;
  14.798 +					break;
  14.799 +				}
  14.800 +				p = p->next;
  14.801 +			}
  14.802 +
  14.803 +			urarlib_freelist(rarList);
  14.804 +		}
  14.805 +		return found;
  14.806 +#endif
  14.807 +	}
  14.808 +	else
  14.809 +	{
  14.810 +		if (utilIsGzipFile(file))
  14.811 +			utilGetBaseName(file, buffer);
  14.812 +		else
  14.813 +			strcpy(buffer, file);
  14.814 +
  14.815 +		if (utilIsGBAImage(buffer))
  14.816 +			return IMAGE_GBA;
  14.817 +		if (utilIsGBImage(buffer))
  14.818 +			return IMAGE_GB;
  14.819 +	}
  14.820 +	return IMAGE_UNKNOWN;
  14.821 +}
  14.822 +
  14.823 +static int utilGetSize(int size)
  14.824 +{
  14.825 +	int res = 1;
  14.826 +	while (res < size)
  14.827 +		res <<= 1;
  14.828 +	return res;
  14.829 +}
  14.830 +
  14.831 +static u8 *utilLoadFromZip(const char *file,
  14.832 +                           bool (*accept)(const char *),
  14.833 +                           u8 *data,
  14.834 +                           int &size)
  14.835 +{
  14.836 +	char buffer[2048];
  14.837 +
  14.838 +	unzFile unz = unzOpen(file);
  14.839 +
  14.840 +	if (unz == NULL)
  14.841 +	{
  14.842 +		systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file);
  14.843 +		return NULL;
  14.844 +	}
  14.845 +	int r = unzGoToFirstFile(unz);
  14.846 +
  14.847 +	if (r != UNZ_OK)
  14.848 +	{
  14.849 +		unzClose(unz);
  14.850 +		systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file);
  14.851 +		return NULL;
  14.852 +	}
  14.853 +
  14.854 +	bool found = false;
  14.855 +
  14.856 +	unz_file_info info;
  14.857 +
  14.858 +	while (true)
  14.859 +	{
  14.860 +		r = unzGetCurrentFileInfo(unz,
  14.861 +		                          &info,
  14.862 +		                          buffer,
  14.863 +		                          sizeof(buffer),
  14.864 +		                          NULL,
  14.865 +		                          0,
  14.866 +		                          NULL,
  14.867 +		                          0);
  14.868 +
  14.869 +		if (r != UNZ_OK)
  14.870 +		{
  14.871 +			unzClose(unz);
  14.872 +			systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file);
  14.873 +			return NULL;
  14.874 +		}
  14.875 +
  14.876 +		if (accept(buffer))
  14.877 +		{
  14.878 +			found = true;
  14.879 +			break;
  14.880 +		}
  14.881 +
  14.882 +		r = unzGoToNextFile(unz);
  14.883 +
  14.884 +		if (r != UNZ_OK)
  14.885 +			break;
  14.886 +	}
  14.887 +
  14.888 +	if (!found)
  14.889 +	{
  14.890 +		unzClose(unz);
  14.891 +		systemMessage(MSG_NO_IMAGE_ON_ZIP,
  14.892 +		              N_("No image found on ZIP file %s"), file);
  14.893 +		return NULL;
  14.894 +	}
  14.895 +
  14.896 +	int fileSize = info.uncompressed_size;
  14.897 +	if (size == 0)
  14.898 +		size = fileSize;
  14.899 +	r = unzOpenCurrentFile(unz);
  14.900 +
  14.901 +	if (r != UNZ_OK)
  14.902 +	{
  14.903 +		unzClose(unz);
  14.904 +		systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), buffer);
  14.905 +		return NULL;
  14.906 +	}
  14.907 +
  14.908 +	u8 *image = data;
  14.909 +
  14.910 +	if (image == NULL)
  14.911 +	{
  14.912 +		image = (u8 *)malloc(utilGetSize(size));
  14.913 +		if (image == NULL)
  14.914 +		{
  14.915 +			unzCloseCurrentFile(unz);
  14.916 +			unzClose(unz);
  14.917 +			systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
  14.918 +			              "data");
  14.919 +			return NULL;
  14.920 +		}
  14.921 +		size = fileSize;
  14.922 +	}
  14.923 +	int read = fileSize <= size ? fileSize : size;
  14.924 +	r = unzReadCurrentFile(unz,
  14.925 +	                       image,
  14.926 +	                       read);
  14.927 +
  14.928 +	unzCloseCurrentFile(unz);
  14.929 +	unzClose(unz);
  14.930 +
  14.931 +	if (r != (int)read)
  14.932 +	{
  14.933 +		systemMessage(MSG_ERROR_READING_IMAGE,
  14.934 +		              N_("Error reading image %s"), buffer);
  14.935 +		if (data == NULL)
  14.936 +			free(image);
  14.937 +		return NULL;
  14.938 +	}
  14.939 +
  14.940 +	size = fileSize;
  14.941 +
  14.942 +	return image;
  14.943 +}
  14.944 +
  14.945 +static u8 *utilLoadGzipFile(const char *file,
  14.946 +                            bool (*accept)(const char *),
  14.947 +                            u8 *data,
  14.948 +                            int &size)
  14.949 +{
  14.950 +	FILE *f = fopen(file, "rb");
  14.951 +
  14.952 +	if (f == NULL)
  14.953 +	{
  14.954 +		systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file);
  14.955 +		return NULL;
  14.956 +	}
  14.957 +
  14.958 +	fseek(f, -4, SEEK_END);
  14.959 +	int fileSize = fgetc(f) | (fgetc(f) << 8) | (fgetc(f) << 16) | (fgetc(f) << 24);
  14.960 +	fclose(f);
  14.961 +	if (size == 0)
  14.962 +		size = fileSize;
  14.963 +
  14.964 +	gzFile gz = gzopen(file, "rb");
  14.965 +
  14.966 +	if (gz == NULL)
  14.967 +	{
  14.968 +		// should not happen, but who knows?
  14.969 +		systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file);
  14.970 +		return NULL;
  14.971 +	}
  14.972 +
  14.973 +	u8 *image = data;
  14.974 +
  14.975 +	if (image == NULL)
  14.976 +	{
  14.977 +		image = (u8 *)malloc(utilGetSize(size));
  14.978 +		if (image == NULL)
  14.979 +		{
  14.980 +			systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
  14.981 +			              "data");
  14.982 +			fclose(f);
  14.983 +			return NULL;
  14.984 +		}
  14.985 +		size = fileSize;
  14.986 +	}
  14.987 +	int read = fileSize <= size ? fileSize : size;
  14.988 +	int r	 = gzread(gz, image, read);
  14.989 +	gzclose(gz);
  14.990 +
  14.991 +	if (r != (int)read)
  14.992 +	{
  14.993 +		systemMessage(MSG_ERROR_READING_IMAGE,
  14.994 +		              N_("Error reading image %s"), file);
  14.995 +		if (data == NULL)
  14.996 +			free(image);
  14.997 +		return NULL;
  14.998 +	}
  14.999 +
 14.1000 +	size = fileSize;
 14.1001 +
 14.1002 +	return image;
 14.1003 +}
 14.1004 +
 14.1005 +#if 0
 14.1006 +static u8 *utilLoadRarFile(const char *file,
 14.1007 +                           bool (*accept)(const char *),
 14.1008 +                           u8 *data,
 14.1009 +                           int &size)
 14.1010 +{
 14.1011 +	char buffer[2048];
 14.1012 +
 14.1013 +	ArchiveList_struct *rarList = NULL;
 14.1014 +	if (urarlib_list((void *)file, (ArchiveList_struct *)&rarList))
 14.1015 +	{
 14.1016 +		ArchiveList_struct *p = rarList;
 14.1017 +
 14.1018 +		bool found = false;
 14.1019 +		while (p)
 14.1020 +		{
 14.1021 +			if (accept(p->item.Name))
 14.1022 +			{
 14.1023 +				strcpy(buffer, p->item.Name);
 14.1024 +				found = true;
 14.1025 +				break;
 14.1026 +			}
 14.1027 +			p = p->next;
 14.1028 +		}
 14.1029 +		if (found)
 14.1030 +		{
 14.1031 +			void *memory		= NULL;
 14.1032 +			unsigned long lsize = 0;
 14.1033 +			size = p->item.UnpSize;
 14.1034 +			int r = urarlib_get((void *)&memory, &lsize, buffer, (void *)file, "");
 14.1035 +			if (!r)
 14.1036 +			{
 14.1037 +				systemMessage(MSG_ERROR_READING_IMAGE,
 14.1038 +				              N_("Error reading image %s"), buffer);
 14.1039 +				urarlib_freelist(rarList);
 14.1040 +				return NULL;
 14.1041 +			}
 14.1042 +			u8 *image = (u8 *)memory;
 14.1043 +			if (data != NULL)
 14.1044 +			{
 14.1045 +				memcpy(image, data, size);
 14.1046 +			}
 14.1047 +			urarlib_freelist(rarList);
 14.1048 +			return image;
 14.1049 +		}
 14.1050 +		systemMessage(MSG_NO_IMAGE_ON_ZIP,
 14.1051 +		              N_("No image found on RAR file %s"), file);
 14.1052 +		urarlib_freelist(rarList);
 14.1053 +		return NULL;
 14.1054 +	}
 14.1055 +	// nothing found
 14.1056 +	return NULL;
 14.1057 +}
 14.1058 +
 14.1059 +#endif
 14.1060 +
 14.1061 +// the caller is responsible for caling free(return value) to release the memory
 14.1062 +u8 *utilLoad(const char *file,
 14.1063 +             bool (*accept)(const char *),
 14.1064 +             u8 *data,
 14.1065 +             int &size)
 14.1066 +{
 14.1067 +	if (utilIsZipFile(file))
 14.1068 +	{
 14.1069 +		return utilLoadFromZip(file, accept, data, size);
 14.1070 +	}
 14.1071 +	if (utilIsGzipFile(file))
 14.1072 +	{
 14.1073 +		return utilLoadGzipFile(file, accept, data, size);
 14.1074 +	}
 14.1075 +#if 0
 14.1076 +	if (utilIsRarFile(file))
 14.1077 +	{
 14.1078 +		return utilLoadRarFile(file, accept, data, size);
 14.1079 +	}
 14.1080 +#endif
 14.1081 +
 14.1082 +	u8 *image = data;
 14.1083 +
 14.1084 +	FILE *f = fopen(file, "rb");
 14.1085 +
 14.1086 +	if (!f)
 14.1087 +	{
 14.1088 +		systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file);
 14.1089 +		return NULL;
 14.1090 +	}
 14.1091 +
 14.1092 +	fseek(f, 0, SEEK_END);
 14.1093 +	int fileSize = ftell(f);
 14.1094 +	fseek(f, 0, SEEK_SET);
 14.1095 +	if (size == 0)
 14.1096 +		size = fileSize;
 14.1097 +
 14.1098 +	if (image == NULL)
 14.1099 +	{
 14.1100 +		image = (u8 *)malloc(utilGetSize(size));
 14.1101 +		if (image == NULL)
 14.1102 +		{
 14.1103 +			systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
 14.1104 +			              "data");
 14.1105 +			fclose(f);
 14.1106 +			return NULL;
 14.1107 +		}
 14.1108 +		size = fileSize;
 14.1109 +	}
 14.1110 +	int read = fileSize <= size ? fileSize : size;
 14.1111 +	int r	 = fread(image, 1, read, f);
 14.1112 +	fclose(f);
 14.1113 +
 14.1114 +	if (r != (int)read)
 14.1115 +	{
 14.1116 +		systemMessage(MSG_ERROR_READING_IMAGE,
 14.1117 +		              N_("Error reading image %s"), file);
 14.1118 +		if (data == NULL)
 14.1119 +			free(image);
 14.1120 +		return NULL;
 14.1121 +	}
 14.1122 +
 14.1123 +	size = fileSize;
 14.1124 +
 14.1125 +	return image;
 14.1126 +}
 14.1127 +
 14.1128 +void utilWriteInt(gzFile gzFile, int32 i)
 14.1129 +{
 14.1130 +	utilGzWrite(gzFile, &i, sizeof(int32));
 14.1131 +}
 14.1132 +
 14.1133 +int32 utilReadInt(gzFile gzFile)
 14.1134 +{
 14.1135 +	int32 i = 0;
 14.1136 +	utilGzRead(gzFile, &i, sizeof(int32));
 14.1137 +	return i;
 14.1138 +}
 14.1139 +
 14.1140 +void utilReadData(gzFile gzFile, variable_desc *data)
 14.1141 +{
 14.1142 +	while (data->address)
 14.1143 +	{
 14.1144 +		utilGzRead(gzFile, data->address, data->size);
 14.1145 +		data++;
 14.1146 +	}
 14.1147 +}
 14.1148 +
 14.1149 +void utilWriteData(gzFile gzFile, variable_desc *data)
 14.1150 +{
 14.1151 +	while (data->address)
 14.1152 +	{
 14.1153 +		utilGzWrite(gzFile, data->address, data->size);
 14.1154 +		data++;
 14.1155 +	}
 14.1156 +}
 14.1157 +
 14.1158 +gzFile utilGzOpen(const char *file, const char *mode)
 14.1159 +{
 14.1160 +	utilGzWriteFunc = gzWrite;
 14.1161 +	utilGzReadFunc	= gzread;
 14.1162 +	utilGzCloseFunc = gzclose;
 14.1163 +	utilGzSeekFunc	= gzseek;
 14.1164 +	utilGzTellFunc	= gztell;
 14.1165 +
 14.1166 +	return gzopen(file, mode);
 14.1167 +}
 14.1168 +
 14.1169 +gzFile utilGzReopen(int id, const char *mode)
 14.1170 +{
 14.1171 +	utilGzWriteFunc = gzWrite;
 14.1172 +	utilGzReadFunc	= gzread;
 14.1173 +	utilGzCloseFunc = gzclose;
 14.1174 +	utilGzSeekFunc	= gzseek;
 14.1175 +	utilGzTellFunc	= gztell;
 14.1176 +
 14.1177 +	return gzdopen(id, mode);
 14.1178 +}
 14.1179 +
 14.1180 +gzFile utilMemGzOpen(char *memory, int available, char *mode)
 14.1181 +{
 14.1182 +	utilGzWriteFunc = memgzwrite;
 14.1183 +	utilGzReadFunc	= memgzread;
 14.1184 +	utilGzCloseFunc = memgzclose;
 14.1185 +	utilGzSeekFunc	= NULL;	// FIXME: not implemented...
 14.1186 +	utilGzTellFunc	= memtell;
 14.1187 +
 14.1188 +	return memgzopen(memory, available, mode);
 14.1189 +}
 14.1190 +
 14.1191 +int utilGzWrite(gzFile file, voidp buffer, unsigned int len)
 14.1192 +{
 14.1193 +	return utilGzWriteFunc(file, buffer, len);
 14.1194 +}
 14.1195 +
 14.1196 +int utilGzRead(gzFile file, voidp buffer, unsigned int len)
 14.1197 +{
 14.1198 +	return utilGzReadFunc(file, buffer, len);
 14.1199 +}
 14.1200 +
 14.1201 +int utilGzClose(gzFile file)
 14.1202 +{
 14.1203 +	return utilGzCloseFunc(file);
 14.1204 +}
 14.1205 +
 14.1206 +z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence)
 14.1207 +{
 14.1208 +	return utilGzSeekFunc(file, offset, whence);
 14.1209 +}
 14.1210 +
 14.1211 +z_off_t utilGzTell(gzFile file)
 14.1212 +{
 14.1213 +	return utilGzTellFunc(file);
 14.1214 +}
 14.1215 +
 14.1216 +void utilGBAFindSave(const u8 *data, const int size)
 14.1217 +{
 14.1218 +	u32 *p		   = (u32 *)data;
 14.1219 +	u32 *end	   = (u32 *)(data + size);
 14.1220 +	int	 saveType  = 0;
 14.1221 +	int	 flashSize = 0x10000;
 14.1222 +	bool rtcFound  = false;
 14.1223 +
 14.1224 +	while (p  < end)
 14.1225 +	{
 14.1226 +		u32 d = READ32LE(p);
 14.1227 +
 14.1228 +		if (d == 0x52504545)
 14.1229 +		{
 14.1230 +			if (memcmp(p, "EEPROM_", 7) == 0)
 14.1231 +			{
 14.1232 +				if (saveType == 0)
 14.1233 +					saveType = 1;
 14.1234 +			}
 14.1235 +		}
 14.1236 +		else if (d == 0x4D415253)
 14.1237 +		{
 14.1238 +			if (memcmp(p, "SRAM_", 5) == 0)
 14.1239 +			{
 14.1240 +				if (saveType == 0)
 14.1241 +					saveType = 2;
 14.1242 +			}
 14.1243 +		}
 14.1244 +		else if (d == 0x53414C46)
 14.1245 +		{
 14.1246 +			if (memcmp(p, "FLASH1M_", 8) == 0)
 14.1247 +			{
 14.1248 +				if (saveType == 0)
 14.1249 +				{
 14.1250 +					saveType  = 3;
 14.1251 +					flashSize = 0x20000;
 14.1252 +				}
 14.1253 +			}
 14.1254 +			else if (memcmp(p, "FLASH", 5) == 0)
 14.1255 +			{
 14.1256 +				if (saveType == 0)
 14.1257 +				{
 14.1258 +					saveType  = 3;
 14.1259 +					flashSize = 0x10000;
 14.1260 +				}
 14.1261 +			}
 14.1262 +		}
 14.1263 +		else if (d == 0x52494953)
 14.1264 +		{
 14.1265 +			if (memcmp(p, "SIIRTC_V", 8) == 0)
 14.1266 +				rtcFound = true;
 14.1267 +		}
 14.1268 +		p++;
 14.1269 +	}
 14.1270 +	// if no matches found, then set it to NONE
 14.1271 +	if (saveType == 0)
 14.1272 +	{
 14.1273 +		saveType = 5;
 14.1274 +	}
 14.1275 +	rtcEnable(rtcFound);
 14.1276 +	cpuSaveType = saveType;
 14.1277 +	flashSetSize(flashSize);
 14.1278 +}
 14.1279 +
 14.1280 +void utilUpdateSystemColorMaps()
 14.1281 +{
 14.1282 +	switch (systemColorDepth)
 14.1283 +	{
 14.1284 +	case 16:
 14.1285 +	{
 14.1286 +		for (int i = 0; i < 0x10000; i++)
 14.1287 +		{
 14.1288 +			systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
 14.1289 +			                      (((i & 0x3e0) >> 5) << systemGreenShift) |
 14.1290 +			                      (((i & 0x7c00) >> 10) << systemBlueShift);
 14.1291 +		}
 14.1292 +		break;
 14.1293 +	}
 14.1294 +	case 24:
 14.1295 +	case 32:
 14.1296 +	{
 14.1297 +		for (int i = 0; i < 0x10000; i++)
 14.1298 +		{
 14.1299 +			systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
 14.1300 +			                      (((i & 0x3e0) >> 5) << systemGreenShift) |
 14.1301 +			                      (((i & 0x7c00) >> 10) << systemBlueShift);
 14.1302 +		}
 14.1303 +		break;
 14.1304 +	}
 14.1305 +	}
 14.1306 +}
 14.1307 +
 14.1308 +//// BIOS stuff
 14.1309 +// systemType uses the same enum values as gbEmulatorType does
 14.1310 +
 14.1311 +bool utilLoadBIOS(u8 *bios, const char *biosFileName, int systemType)
 14.1312 +{
 14.1313 +	if (bios == NULL || strlen(biosFileName) == 0)
 14.1314 +		return false;
 14.1315 +
 14.1316 +	if (systemType == 4)
 14.1317 +	{
 14.1318 +		int biosSize = 0x4000;
 14.1319 +		if (utilLoad(biosFileName, utilIsGBABios, bios, biosSize))
 14.1320 +		{
 14.1321 +			if (biosSize == 0x4000)
 14.1322 +				return true;
 14.1323 +		}
 14.1324 +	}
 14.1325 +	else
 14.1326 +	{
 14.1327 +		int biosSize = 0x100;
 14.1328 +		if (utilLoad(biosFileName, utilIsGBBios, bios, biosSize))
 14.1329 +		{
 14.1330 +			if (biosSize == 0x100)
 14.1331 +				return true;
 14.1332 +		}
 14.1333 +	}
 14.1334 +
 14.1335 +	return false;
 14.1336 +}
 14.1337 +
 14.1338 +bool utilCheckBIOS(const char *biosFileName, int systemType)
 14.1339 +{
 14.1340 +	if (strlen(biosFileName) == 0)
 14.1341 +		return false;
 14.1342 +
 14.1343 +	u8 * tempBIOS = (u8 *)malloc(systemType == 4 ? 0x4000 : 0x100);
 14.1344 +	bool result	  = utilLoadBIOS(tempBIOS, biosFileName, systemType);
 14.1345 +	free(tempBIOS);
 14.1346 +
 14.1347 +	return result;
 14.1348 +}
 14.1349 +
 14.1350 +#if 0
 14.1351 +// returns the checksum of the BIOS that will be loaded after the next restart
 14.1352 +u16 utilCalcBIOSChecksum(const u8 *bios, int systemType)
 14.1353 +{
 14.1354 +	u32	biosChecksum = 0;
 14.1355 +	if (bios)
 14.1356 +	{
 14.1357 +		int biosSize	= (systemType == 4 ? 0x4000 : 0x100);
 14.1358 +		const u16 *data = reinterpret_cast<const u16 *>(bios);
 14.1359 +		for (int i = biosSize; i > 0; i -= 2)
 14.1360 +			biosChecksum += *data++;
 14.1361 +	}
 14.1362 +
 14.1363 +	while ((biosChecksum >> 16) & 0xFFFF)
 14.1364 +		biosChecksum = (biosChecksum &0xFFFF) + ((biosChecksum >> 16) & 0xFFFF);
 14.1365 +
 14.1366 +	return biosChecksum & 0xFFFF;
 14.1367 +}
 14.1368 +#else
 14.1369 +// returns the checksum of the BIOS that will be loaded after the next restart
 14.1370 +u16 utilCalcBIOSChecksum(const u8 *bios, int systemType)
 14.1371 +{
 14.1372 +	u32	biosChecksum = 0;
 14.1373 +	if (bios)
 14.1374 +	{
 14.1375 +		int biosSize	= (systemType == 4 ? 0x4000 : 0x100);
 14.1376 +		const u32 *data = reinterpret_cast<const u32 *>(bios);
 14.1377 +		for (int i = biosSize; i > 0; i -= 4)
 14.1378 +			biosChecksum += *data++;
 14.1379 +	}
 14.1380 +
 14.1381 +	return biosChecksum & 0xFFFF;
 14.1382 +}
 14.1383 +#endif
 14.1384 +
 14.1385 +// returns the checksum of the BIOS file
 14.1386 +u16 utilCalcBIOSFileChecksum(const char *biosFileName, int systemType)
 14.1387 +{
 14.1388 +	if (strlen(biosFileName) == 0)
 14.1389 +		return 0;
 14.1390 +
 14.1391 +	u16		  biosChecksum = 0;
 14.1392 +	const int biosSize	   = (systemType == 4 ? 0x4000 : 0x100);
 14.1393 +	u8 *	  tempBIOS	   = (u8 *)malloc(biosSize);
 14.1394 +	bool	  hasBIOS	   = utilLoadBIOS(tempBIOS, biosFileName, systemType);
 14.1395 +	if (hasBIOS)
 14.1396 +	{
 14.1397 +		biosChecksum = utilCalcBIOSChecksum(tempBIOS, systemType);
 14.1398 +	}
 14.1399 +	free(tempBIOS);
 14.1400 +
 14.1401 +	return biosChecksum;
 14.1402 +}
 14.1403 +
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/common/Util.h	Sun Mar 04 14:33:52 2012 -0600
    15.3 @@ -0,0 +1,64 @@
    15.4 +#ifndef VBA_UTIL_H
    15.5 +#define VBA_UTIL_H
    15.6 +
    15.7 +#if _MSC_VER > 1000
    15.8 +#pragma once
    15.9 +#endif // _MSC_VER > 1000
   15.10 +
   15.11 +#include "zlib.h"
   15.12 +#include "../Port.h"
   15.13 +
   15.14 +enum IMAGE_TYPE
   15.15 +{
   15.16 +	IMAGE_UNKNOWN = -1,
   15.17 +	IMAGE_GBA	  = 0,
   15.18 +	IMAGE_GB	  = 1
   15.19 +};
   15.20 +
   15.21 +// save game
   15.22 +
   15.23 +typedef struct
   15.24 +{
   15.25 +	void *address;
   15.26 +	int	  size;
   15.27 +} variable_desc;
   15.28 +
   15.29 +extern void utilWriteBMP(u8 *out, int w, int h, int dstDepth, u8 *in);
   15.30 +extern bool utilWriteBMPFile(const char *, int, int, u8 *);
   15.31 +extern bool utilWritePNGFile(const char *, int, int, u8 *);
   15.32 +extern void utilApplyIPS(const char *ips, u8 * *rom, int *size);
   15.33 +extern bool utilIsGBAImage(const char *);
   15.34 +extern bool utilIsGBABios(const char *file);
   15.35 +extern bool utilIsELF(const char *file);
   15.36 +extern bool utilIsGBImage(const char *);
   15.37 +extern bool utilIsGBBios(const char *file);
   15.38 +extern bool utilIsZipFile(const char *);
   15.39 +extern bool utilIsGzipFile(const char *);
   15.40 +extern bool utilIsRarFile(const char *);
   15.41 +extern void utilGetBaseName(const char *, char *);
   15.42 +extern IMAGE_TYPE utilFindType(const char *);
   15.43 +extern u8 *	 utilLoad(const char *, bool (*)(const char *), u8 *, int &);
   15.44 +extern void	 utilPutDword(u8 *, u32);
   15.45 +extern void	 utilPutWord(u8 *, u16);
   15.46 +extern void	 utilWriteData(gzFile, variable_desc *);
   15.47 +extern void	 utilReadData(gzFile, variable_desc *);
   15.48 +extern int32 utilReadInt(gzFile);
   15.49 +extern void	 utilWriteInt(gzFile, int32);
   15.50 +extern gzFile utilGzOpen(const char *file, const char *mode);
   15.51 +extern gzFile utilGzReopen(int id, const char *mode);
   15.52 +extern gzFile utilMemGzOpen(char *memory, int available, char *mode);
   15.53 +extern int utilGzWrite(gzFile file, voidp buffer, unsigned int len);
   15.54 +extern int utilGzRead(gzFile file, voidp buffer, unsigned int len);
   15.55 +extern int utilGzClose(gzFile file);
   15.56 +extern z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence);
   15.57 +extern z_off_t utilGzTell(gzFile file);
   15.58 +extern void utilGBAFindSave(const u8 *, const int);
   15.59 +extern void utilUpdateSystemColorMaps();
   15.60 +extern bool utilLoadBIOS(u8 *bios, const char *biosFileName, int systemType);
   15.61 +extern bool utilCheckBIOS(const char *biosFileName, int systemType);
   15.62 +extern u16 utilCalcBIOSChecksum(const u8 *bios, int systemType);
   15.63 +extern u16 utilCalcBIOSFileChecksum(const char *biosFileName, int systemType);
   15.64 +
   15.65 +extern int gzWrite(gzFile file, void* buf, unsigned len);
   15.66 +
   15.67 +#endif // VBA_UTIL_H
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/common/inputGlobal.h	Sun Mar 04 14:33:52 2012 -0600
    16.3 @@ -0,0 +1,48 @@
    16.4 +#ifndef VBA_INPUT_GLOBAL_H
    16.5 +#define VBA_INPUT_GLOBAL_H
    16.6 +
    16.7 +#if _MSC_VER > 1000
    16.8 +#pragma once
    16.9 +#endif // _MSC_VER > 1000
   16.10 +
   16.11 +enum
   16.12 +{
   16.13 +	KEY_BUTTON_A, KEY_BUTTON_B,
   16.14 +	KEY_BUTTON_SELECT, KEY_BUTTON_START,
   16.15 +	KEY_RIGHT, KEY_LEFT,
   16.16 +	KEY_UP, KEY_DOWN,
   16.17 +	KEY_BUTTON_R, KEY_BUTTON_L,
   16.18 +	KEY_BUTTON_SPEED, KEY_BUTTON_CAPTURE,
   16.19 +	KEY_BUTTON_GS
   16.20 +};
   16.21 +
   16.22 +#define BUTTON_MASK_A                    (0x0001)
   16.23 +#define BUTTON_MASK_B                    (0x0002)
   16.24 +#define BUTTON_MASK_SELECT               (0x0004)
   16.25 +#define BUTTON_MASK_START                (0x0008)
   16.26 +#define BUTTON_MASK_RIGHT                (0x0010)
   16.27 +#define BUTTON_MASK_LEFT                 (0x0020)
   16.28 +#define BUTTON_MASK_UP                   (0x0040)
   16.29 +#define BUTTON_MASK_DOWN                 (0x0080)
   16.30 +#define BUTTON_MASK_R                    (0x0100)
   16.31 +#define BUTTON_MASK_L                    (0x0200)
   16.32 +#define BUTTON_GB_MASK                   (BUTTON_MASK_A|BUTTON_MASK_B|BUTTON_MASK_SELECT|BUTTON_MASK_START| \
   16.33 +                                          BUTTON_MASK_RIGHT|BUTTON_MASK_LEFT|BUTTON_MASK_UP|BUTTON_MASK_DOWN)
   16.34 +#define BUTTON_GBA_ONLY                  (BUTTON_MASK_R|BUTTON_MASK_L)
   16.35 +#define BUTTON_REGULAR_MASK              (BUTTON_GB_MASK|BUTTON_GBA_ONLY)
   16.36 +#define BUTTON_MASK_OLD_RESET            (0x0400)
   16.37 +#define BUTTON_MASK_NEW_RESET            (0x0800)
   16.38 +#define BUTTON_MASK_LEFT_MOTION          (0x1000)
   16.39 +#define BUTTON_MASK_RIGHT_MOTION         (0x2000)
   16.40 +#define BUTTON_MASK_DOWN_MOTION          (0x4000)
   16.41 +#define BUTTON_MASK_UP_MOTION            (0x8000)
   16.42 +#define BUTTON_MOTION_MASK               (BUTTON_MASK_LEFT_MOTION|BUTTON_MASK_RIGHT_MOTION|BUTTON_MASK_DOWN_MOTION| \
   16.43 +                                          BUTTON_MASK_UP_MOTION)
   16.44 +#define BUTTON_RECORDINGONLY_MASK        (BUTTON_MASK_OLD_RESET|BUTTON_MASK_NEW_RESET|BUTTON_MOTION_MASK)
   16.45 +#define BUTTON_REGULAR_RECORDING_MASK	 (BUTTON_REGULAR_MASK|BUTTON_RECORDINGONLY_MASK)
   16.46 +#define BUTTON_MASK_SPEED                (0x040000)
   16.47 +#define BUTTON_MASK_CAPTURE              (0x080000)
   16.48 +#define BUTTON_MASK_GAMESHARK            (0x100000)
   16.49 +#define BUTTON_NONRECORDINGONLY_MASK     (BUTTON_MASK_SPEED|BUTTON_MASK_CAPTURE|BUTTON_MASK_GAMESHARK)
   16.50 +
   16.51 +#endif // VBA_INPUT_GLOBAL_H
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/common/lua-engine.cpp	Sun Mar 04 14:33:52 2012 -0600
    17.3 @@ -0,0 +1,5102 @@
    17.4 +#include <cstdio>
    17.5 +#include <cstdlib>
    17.6 +#include <malloc.h>
    17.7 +#include <string>
    17.8 +#include <cassert>
    17.9 +#include <cctype>
   17.10 +#include <cmath>
   17.11 +#include <ctime>
   17.12 +
   17.13 +#include <vector>
   17.14 +#include <map>
   17.15 +#include <string>
   17.16 +#include <algorithm>
   17.17 +
   17.18 +using namespace std;
   17.19 +
   17.20 +#ifdef __linux
   17.21 +	#include <unistd.h> // for unlink
   17.22 +	#include <sys/types.h>
   17.23 +	#include <sys/wait.h>
   17.24 +#endif
   17.25 +#if (defined(WIN32) && !defined(SDL))
   17.26 +	#include <direct.h>
   17.27 +	#include "../win32/stdafx.h"
   17.28 +	#include "../win32/Input.h"
   17.29 +	#include "../win32/MainWnd.h"
   17.30 +	#include "../win32/VBA.h"
   17.31 +	#include "../win32/LuaOpenDialog.h"
   17.32 +#else
   17.33 +	#define stricmp strcasecmp
   17.34 +	#define strnicmp strncasecmp
   17.35 +#endif
   17.36 +
   17.37 +#include "../Port.h"
   17.38 +#include "System.h"
   17.39 +#include "movie.h"
   17.40 +#include "../gba/GBA.h"
   17.41 +#include "../gba/GBAGlobals.h"
   17.42 +#include "../gb/GB.h"
   17.43 +#include "../gb/gbGlobals.h"
   17.44 +#include "../gba/GBASound.h"
   17.45 +
   17.46 +#ifdef _WIN32
   17.47 +#include "../win32/Sound.h"
   17.48 +//#include "../win32/WinMiscUtil.h"
   17.49 +extern CString winGetSavestateFilename(const CString &LogicalRomName, int nID);
   17.50 +#else
   17.51 +#endif
   17.52 +
   17.53 +extern "C"
   17.54 +{
   17.55 +#include "../lua/src/lua.h"
   17.56 +#include "../lua/src/lauxlib.h"
   17.57 +#include "../lua/src/lualib.h"
   17.58 +#include "../lua/src/lstate.h"
   17.59 +}
   17.60 +#include "vbalua.h"
   17.61 +
   17.62 +#include "../SFMT/SFMT.c"
   17.63 +
   17.64 +static void (*info_print)(int uid, const char *str);
   17.65 +static void (*info_onstart)(int uid);
   17.66 +static void (*info_onstop)(int uid);
   17.67 +static int	info_uid;
   17.68 +
   17.69 +#ifndef countof
   17.70 +	#define countof(a)  (sizeof(a) / sizeof(a[0]))
   17.71 +#endif
   17.72 +
   17.73 +static lua_State *LUA;
   17.74 +
   17.75 +// Are we running any code right now?
   17.76 +static char *luaScriptName = NULL;
   17.77 +
   17.78 +// Are we running any code right now?
   17.79 +static bool8 luaRunning = false;
   17.80 +
   17.81 +// True at the frame boundary, false otherwise.
   17.82 +static bool8 frameBoundary = false;
   17.83 +
   17.84 +// The execution speed we're running at.
   17.85 +static enum { SPEED_NORMAL, SPEED_NOTHROTTLE, SPEED_TURBO, SPEED_MAXIMUM } speedmode = SPEED_NORMAL;
   17.86 +
   17.87 +// Rerecord count skip mode
   17.88 +static bool8 skipRerecords = false;
   17.89 +
   17.90 +// Used by the registry to find our functions
   17.91 +static const char *frameAdvanceThread = "VBA.FrameAdvance";
   17.92 +static const char *guiCallbackTable	  = "VBA.GUI";
   17.93 +
   17.94 +// True if there's a thread waiting to run after a run of frame-advance.
   17.95 +static bool8 frameAdvanceWaiting = false;
   17.96 +
   17.97 +// We save our pause status in the case of a natural death.
   17.98 +//static bool8 wasPaused = false;
   17.99 +
  17.100 +// Transparency strength. 255=opaque, 0=so transparent it's invisible
  17.101 +static int transparencyModifier = 255;
  17.102 +
  17.103 +// Our joypads.
  17.104 +static uint32 lua_joypads[4];
  17.105 +static uint8  lua_joypads_used = 0;
  17.106 +
  17.107 +static bool8  gui_used = false;
  17.108 +static uint8 *gui_data = NULL;          // BGRA
  17.109 +
  17.110 +// Protects Lua calls from going nuts.
  17.111 +// We set this to a big number like 1000 and decrement it
  17.112 +// over time. The script gets knifed once this reaches zero.
  17.113 +static int numTries;
  17.114 +
  17.115 +// number of registered memory functions (1 per hooked byte)
  17.116 +static unsigned int numMemHooks;
  17.117 +
  17.118 +// Look in inputglobal.h for macros named like BUTTON_MASK_UP to determine the order.
  17.119 +static const char *button_mappings[] = {
  17.120 +	"A", "B", "select", "start", "right", "left", "up", "down", "R", "L"
  17.121 +};
  17.122 +
  17.123 +#ifdef _MSC_VER
  17.124 +	#define snprintf _snprintf
  17.125 +	#define vscprintf _vscprintf
  17.126 +#else
  17.127 +	#define stricmp strcasecmp
  17.128 +	#define strnicmp strncasecmp
  17.129 +	#define __forceinline __attribute__((always_inline))
  17.130 +#endif
  17.131 +
  17.132 +static const char *luaCallIDStrings[] =
  17.133 +{
  17.134 +	"CALL_BEFOREEMULATION",
  17.135 +	"CALL_AFTEREMULATION",
  17.136 +	"CALL_BEFOREEXIT"
  17.137 +};
  17.138 +
  17.139 +//make sure we have the right number of strings
  17.140 +CTASSERT(sizeof(luaCallIDStrings) / sizeof(*luaCallIDStrings) == LUACALL_COUNT)
  17.141 +
  17.142 +static const char *luaMemHookTypeStrings [] =
  17.143 +{
  17.144 +	"MEMHOOK_WRITE",
  17.145 +	"MEMHOOK_READ",
  17.146 +	"MEMHOOK_EXEC",
  17.147 +
  17.148 +	"MEMHOOK_WRITE_SUB",
  17.149 +	"MEMHOOK_READ_SUB",
  17.150 +	"MEMHOOK_EXEC_SUB",
  17.151 +};
  17.152 +
  17.153 +//make sure we have the right number of strings
  17.154 +CTASSERT(sizeof(luaMemHookTypeStrings) / sizeof(*luaMemHookTypeStrings) ==  LUAMEMHOOK_COUNT)
  17.155 +
  17.156 +static char *rawToCString(lua_State * L, int idx = 0);
  17.157 +static const char *toCString(lua_State *L, int idx = 0);
  17.158 +
  17.159 +// GBA memory I/O functions copied from win32/MemoryViewerDlg.cpp
  17.160 +static inline u8 CPUReadByteQuick(u32 addr)
  17.161 +{
  17.162 +	return ::map[addr >> 24].address[addr & ::map[addr >> 24].mask];
  17.163 +}
  17.164 +
  17.165 +static inline void CPUWriteByteQuick(u32 addr, u8 b)
  17.166 +{
  17.167 +	::map[addr >> 24].address[addr & ::map[addr >> 24].mask] = b;
  17.168 +}
  17.169 +
  17.170 +static inline u16 CPUReadHalfWordQuick(u32 addr)
  17.171 +{
  17.172 +	return *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]);
  17.173 +}
  17.174 +
  17.175 +static inline void CPUWriteHalfWordQuick(u32 addr, u16 b)
  17.176 +{
  17.177 +	*((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b;
  17.178 +}
  17.179 +
  17.180 +static inline u32 CPUReadMemoryQuick(u32 addr)
  17.181 +{
  17.182 +	return *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]);
  17.183 +}
  17.184 +
  17.185 +static inline void CPUWriteMemoryQuick(u32 addr, u32 b)
  17.186 +{
  17.187 +	*((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b;
  17.188 +}
  17.189 +
  17.190 +// GB
  17.191 +static inline u8 gbReadMemoryQuick8(u16 addr)
  17.192 +{
  17.193 +	return gbReadMemoryQuick(addr);
  17.194 +}
  17.195 +
  17.196 +static inline void gbWriteMemoryQuick8(u16 addr, u8 b)
  17.197 +{
  17.198 +	gbWriteMemoryQuick(addr, b);
  17.199 +}
  17.200 +
  17.201 +static inline u16 gbReadMemoryQuick16(u16 addr)
  17.202 +{
  17.203 +	return (gbReadMemoryQuick(addr + 1) << 8) | gbReadMemoryQuick(addr);
  17.204 +}
  17.205 +
  17.206 +static inline void gbWriteMemoryQuick16(u16 addr, u16 b)
  17.207 +{
  17.208 +	gbWriteMemoryQuick(addr, b & 0xff);
  17.209 +	gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff);
  17.210 +}
  17.211 +
  17.212 +static inline u32 gbReadMemoryQuick32(u16 addr)
  17.213 +{
  17.214 +	return (gbReadMemoryQuick(addr + 3) << 24) |
  17.215 +	       (gbReadMemoryQuick(addr + 2) << 16) |
  17.216 +	       (gbReadMemoryQuick(addr + 1) << 8) |
  17.217 +	       gbReadMemoryQuick(addr);
  17.218 +}
  17.219 +
  17.220 +static inline void gbWriteMemoryQuick32(u16 addr, u32 b)
  17.221 +{
  17.222 +	gbWriteMemoryQuick(addr, b & 0xff);
  17.223 +	gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff);
  17.224 +	gbWriteMemoryQuick(addr + 2, (b >> 16) & 0xff);
  17.225 +	gbWriteMemoryQuick(addr + 1, (b >> 24) & 0xff);
  17.226 +}
  17.227 +
  17.228 +static inline u8 gbReadROMQuick8(u32 addr)
  17.229 +{
  17.230 +	return gbReadROMQuick(addr & gbRomSizeMask);
  17.231 +}
  17.232 +
  17.233 +static inline u8 gbReadROMQuick16(u32 addr)
  17.234 +{
  17.235 +	return (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | gbReadROMQuick(addr & gbRomSizeMask);
  17.236 +}
  17.237 +
  17.238 +static inline u8 gbReadROMQuick32(u32 addr)
  17.239 +{
  17.240 +	return (gbReadROMQuick(addr+3 & gbRomSizeMask) << 24) |
  17.241 +	       (gbReadROMQuick(addr+2 & gbRomSizeMask) << 16) |
  17.242 +	       (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) |
  17.243 +	       gbReadROMQuick(addr & gbRomSizeMask);
  17.244 +}
  17.245 +
  17.246 +typedef void (*GetColorFunc)(const uint8 *, uint8 *, uint8 *, uint8 *);
  17.247 +typedef void (*SetColorFunc)(uint8 *, uint8, uint8, uint8);
  17.248 +
  17.249 +static void getColor16(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
  17.250 +{
  17.251 +	u16 v = *(const uint16 *)s;
  17.252 +	*r = ((v >> systemBlueShift) & 0x001f) << 3;
  17.253 +	*g = ((v >> systemGreenShift) & 0x001f) << 3;
  17.254 +	*b = ((v >> systemRedShift) & 0x001f) << 3;
  17.255 +}
  17.256 +
  17.257 +static void getColor24(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
  17.258 +{
  17.259 +	if (systemRedShift > systemBlueShift)
  17.260 +		*b = s[0], *g = s[1], *r = s[2];
  17.261 +	else
  17.262 +		*r = s[0], *g = s[1], *b = s[2];
  17.263 +}
  17.264 +
  17.265 +static void getColor32(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
  17.266 +{
  17.267 +	u32 v = *(const uint32 *)s;
  17.268 +	*b = ((v >> systemBlueShift) & 0x001f) << 3;
  17.269 +	*g = ((v >> systemGreenShift) & 0x001f) << 3;
  17.270 +	*r = ((v >> systemRedShift) & 0x001f) << 3;
  17.271 +}
  17.272 +
  17.273 +static void setColor16(uint8 *s, uint8 r, uint8 g, uint8 b)
  17.274 +{
  17.275 +	*(uint16 *)s = ((b >> 3) & 0x01f) <<
  17.276 +	               systemBlueShift |
  17.277 +	               ((g >> 3) & 0x01f) <<
  17.278 +	               systemGreenShift |
  17.279 +	               ((r >> 3) & 0x01f) <<
  17.280 +	               systemRedShift;
  17.281 +}
  17.282 +
  17.283 +static void setColor24(uint8 *s, uint8 r, uint8 g, uint8 b)
  17.284 +{
  17.285 +	if (systemRedShift > systemBlueShift)
  17.286 +		s[0] = b, s[1] = g, s[2] = r;
  17.287 +	else
  17.288 +		s[0] = r, s[1] = g, s[2] = b;
  17.289 +}
  17.290 +
  17.291 +static void setColor32(uint8 *s, uint8 r, uint8 g, uint8 b)
  17.292 +{
  17.293 +	*(uint32 *)s = ((b >> 3) & 0x01f) <<
  17.294 +	               systemBlueShift |
  17.295 +	               ((g >> 3) & 0x01f) <<
  17.296 +	               systemGreenShift |
  17.297 +	               ((r >> 3) & 0x01f) <<
  17.298 +	               systemRedShift;
  17.299 +}
  17.300 +
  17.301 +static bool getColorIOFunc(int depth, GetColorFunc *getColor, SetColorFunc *setColor)
  17.302 +{
  17.303 +	switch (depth)
  17.304 +	{
  17.305 +	case 16:
  17.306 +		if (getColor)
  17.307 +			*getColor = getColor16;
  17.308 +		if (setColor)
  17.309 +			*setColor = setColor16;
  17.310 +		return true;
  17.311 +	case 24:
  17.312 +		if (getColor)
  17.313 +			*getColor = getColor24;
  17.314 +		if (setColor)
  17.315 +			*setColor = setColor24;
  17.316 +		return true;
  17.317 +	case 32:
  17.318 +		if (getColor)
  17.319 +			*getColor = getColor32;
  17.320 +		if (setColor)
  17.321 +			*setColor = setColor32;
  17.322 +		return true;
  17.323 +	default:
  17.324 +		return false;
  17.325 +	}
  17.326 +}
  17.327 +
  17.328 +/**
  17.329 + * Resets emulator speed / pause states after script exit.
  17.330 + */
  17.331 +static void VBALuaOnStop(void)
  17.332 +{
  17.333 +	luaRunning		 = false;
  17.334 +	lua_joypads_used = 0;
  17.335 +	gui_used		 = false;
  17.336 +	//if (wasPaused)
  17.337 +	//	systemSetPause(true);
  17.338 +}
  17.339 +
  17.340 +/**
  17.341 + * Asks Lua if it wants control of the emulator's speed.
  17.342 + * Returns 0 if no, 1 if yes. If yes, we also tamper with the
  17.343 + * IPPU's settings for speed ourselves, so the calling code
  17.344 + * need not do anything.
  17.345 + */
  17.346 +int VBALuaSpeed(void)
  17.347 +{
  17.348 +	if (!LUA || !luaRunning)
  17.349 +		return 0;
  17.350 +
  17.351 +	//printf("%d\n", speedmode);
  17.352 +	switch (speedmode)
  17.353 +	{
  17.354 +	/*
  17.355 +	   case SPEED_NORMAL:
  17.356 +	    return 0;
  17.357 +	   case SPEED_NOTHROTTLE:
  17.358 +	    IPPU.RenderThisFrame = true;
  17.359 +	    return 1;
  17.360 +
  17.361 +	   case SPEED_TURBO:
  17.362 +	    IPPU.SkippedFrames++;
  17.363 +	    if (IPPU.SkippedFrames >= 40) {
  17.364 +	        IPPU.SkippedFrames = 0;
  17.365 +	        IPPU.RenderThisFrame = true;
  17.366 +	    }
  17.367 +	    else
  17.368 +	        IPPU.RenderThisFrame = false;
  17.369 +	    return 1;
  17.370 +
  17.371 +	   // In mode 3, SkippedFrames is set to zero so that the frame
  17.372 +	   // skipping code doesn't try anything funny.
  17.373 +	   case SPEED_MAXIMUM:
  17.374 +	    IPPU.SkippedFrames=0;
  17.375 +	    IPPU.RenderThisFrame = false;
  17.376 +	    return 1;
  17.377 +	 */
  17.378 +	case 0: // FIXME: to get rid of the warning
  17.379 +	default:
  17.380 +		assert(false);
  17.381 +		return 0;
  17.382 +	}
  17.383 +}
  17.384 +
  17.385 +///////////////////////////
  17.386 +// vba.speedmode(string mode)
  17.387 +//
  17.388 +//   Takes control of the emulation speed
  17.389 +//   of the system. Normal is normal speed (60fps, 50 for PAL),
  17.390 +//   nothrottle disables speed control but renders every frame,
  17.391 +//   turbo renders only a few frames in order to speed up emulation,
  17.392 +
  17.393 +//   maximum renders no frames
  17.394 +static int vba_speedmode(lua_State *L)
  17.395 +{
  17.396 +	const char *mode = luaL_checkstring(L, 1);
  17.397 +
  17.398 +	if (strcasecmp(mode, "normal") == 0)
  17.399 +	{
  17.400 +		speedmode = SPEED_NORMAL;
  17.401 +	}
  17.402 +	else if (strcasecmp(mode, "nothrottle") == 0)
  17.403 +	{
  17.404 +		speedmode = SPEED_NOTHROTTLE;
  17.405 +	}
  17.406 +	else if (strcasecmp(mode, "turbo") == 0)
  17.407 +	{
  17.408 +		speedmode = SPEED_TURBO;
  17.409 +	}
  17.410 +	else if (strcasecmp(mode, "maximum") == 0)
  17.411 +	{
  17.412 +		speedmode = SPEED_MAXIMUM;
  17.413 +	}
  17.414 +	else
  17.415 +		luaL_error(L, "Invalid mode %s to vba.speedmode", mode);
  17.416 +
  17.417 +	//printf("new speed mode:  %d\n", speedmode);
  17.418 +	return 0;
  17.419 +}
  17.420 +
  17.421 +// vba.frameadvnace()
  17.422 +//
  17.423 +//  Executes a frame advance. Occurs by yielding the coroutine, then re-running
  17.424 +
  17.425 +//  when we break out.
  17.426 +static int vba_frameadvance(lua_State *L)
  17.427 +{
  17.428 +	// We're going to sleep for a frame-advance. Take notes.
  17.429 +	if (frameAdvanceWaiting)
  17.430 +		return luaL_error(L, "can't call vba.frameadvance() from here");
  17.431 +
  17.432 +	frameAdvanceWaiting = true;
  17.433 +
  17.434 +	// Don't do this! The user won't like us sending their emulator out of control!
  17.435 +	//	Settings.FrameAdvance = true;
  17.436 +	// Now we can yield to the main
  17.437 +	return lua_yield(L, 0);
  17.438 +
  17.439 +	// It's actually rather disappointing...
  17.440 +}
  17.441 +
  17.442 +// vba.pause()
  17.443 +//
  17.444 +//  Pauses the emulator, function "waits" until the user unpauses.
  17.445 +//  This function MAY be called from a non-frame boundary, but the frame
  17.446 +
  17.447 +//  finishes executing anwyays. In this case, the function returns immediately.
  17.448 +static int vba_pause(lua_State *L)
  17.449 +{
  17.450 +	systemSetPause(true);
  17.451 +	speedmode = SPEED_NORMAL;
  17.452 +
  17.453 +	// Return control if we're midway through a frame. We can't pause here.
  17.454 +	if (frameAdvanceWaiting)
  17.455 +	{
  17.456 +		return 0;
  17.457 +	}
  17.458 +
  17.459 +	// If it's on a frame boundary, we also yield.
  17.460 +	frameAdvanceWaiting = true;
  17.461 +	return lua_yield(L, 0);
  17.462 +}
  17.463 +
  17.464 +static int vba_registerbefore(lua_State *L)
  17.465 +{
  17.466 +	if (!lua_isnil(L, 1))
  17.467 +		luaL_checktype(L, 1, LUA_TFUNCTION);
  17.468 +	lua_settop(L, 1);
  17.469 +	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]);
  17.470 +	lua_insert(L, 1);
  17.471 +	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]);
  17.472 +
  17.473 +	//StopScriptIfFinished(luaStateToUIDMap[L]);
  17.474 +	return 1;
  17.475 +}
  17.476 +
  17.477 +static int vba_registerafter(lua_State *L)
  17.478 +{
  17.479 +	if (!lua_isnil(L, 1))
  17.480 +		luaL_checktype(L, 1, LUA_TFUNCTION);
  17.481 +	lua_settop(L, 1);
  17.482 +	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]);
  17.483 +	lua_insert(L, 1);
  17.484 +	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]);
  17.485 +
  17.486 +	//StopScriptIfFinished(luaStateToUIDMap[L]);
  17.487 +	return 1;
  17.488 +}
  17.489 +
  17.490 +static int vba_registerexit(lua_State *L)
  17.491 +{
  17.492 +	if (!lua_isnil(L, 1))
  17.493 +		luaL_checktype(L, 1, LUA_TFUNCTION);
  17.494 +	lua_settop(L, 1);
  17.495 +	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
  17.496 +	lua_insert(L, 1);
  17.497 +	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
  17.498 +
  17.499 +	//StopScriptIfFinished(luaStateToUIDMap[L]);
  17.500 +	return 1;
  17.501 +}
  17.502 +
  17.503 +static inline bool isalphaorunderscore(char c)
  17.504 +{
  17.505 +	return isalpha(c) || c == '_';
  17.506 +}
  17.507 +
  17.508 +static std::vector<const void *> s_tableAddressStack; // prevents infinite recursion of a table within a table (when cycle is
  17.509 +                                                      // found, print something like table:parent)
  17.510 +static std::vector<const void *> s_metacallStack; // prevents infinite recursion if something's __tostring returns another table
  17.511 +                                                  // that contains that something (when cycle is found, print the inner result
  17.512 +                                                  // without using __tostring)
  17.513 +
  17.514 +#define APPENDPRINT { int _n = snprintf(ptr, remaining,
  17.515 +#define END ); if (_n >= 0) { ptr += _n; remaining -= _n; } else { remaining = 0; } }
  17.516 +static void toCStringConverter(lua_State *L, int i, char * &ptr, int &remaining)
  17.517 +{
  17.518 +    if (remaining <= 0)
  17.519 +		return;
  17.520 +
  17.521 +    const char *str = ptr; // for debugging
  17.522 +
  17.523 +    // if there is a __tostring metamethod then call it
  17.524 +    int usedMeta = luaL_callmeta(L, i, "__tostring");
  17.525 +    if (usedMeta)
  17.526 +    {
  17.527 +        std::vector<const void *>::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L, i));
  17.528 +        if (foundCycleIter != s_metacallStack.end())
  17.529 +        {
  17.530 +            lua_pop(L, 1);
  17.531 +            usedMeta = false;
  17.532 +		}
  17.533 +        else
  17.534 +        {
  17.535 +            s_metacallStack.push_back(lua_topointer(L, i));
  17.536 +            i = lua_gettop(L);
  17.537 +		}
  17.538 +	}
  17.539 +
  17.540 +    switch (lua_type(L, i))
  17.541 +    {
  17.542 +	case LUA_TNONE:
  17.543 +		break;
  17.544 +	case LUA_TNIL:
  17.545 +		APPENDPRINT "nil" END break;
  17.546 +	case LUA_TBOOLEAN:
  17.547 +		APPENDPRINT lua_toboolean(L, i) ? "true" : "false" END break;
  17.548 +	case LUA_TSTRING : APPENDPRINT "%s", lua_tostring(L, i) END break;
  17.549 +	case LUA_TNUMBER:
  17.550 +		APPENDPRINT "%.12Lg", lua_tonumber(L, i) END break;
  17.551 +	case LUA_TFUNCTION:
  17.552 +		if ((L->base + i - 1)->value.gc->cl.c.isC)
  17.553 +		{
  17.554 +		    //lua_CFunction func = lua_tocfunction(L, i);
  17.555 +		    //std::map<lua_CFunction, const char*>::iterator iter = s_cFuncInfoMap.find(func);
  17.556 +		    //if(iter == s_cFuncInfoMap.end())
  17.557 +		    goto defcase;
  17.558 +		    //APPENDPRINT "function(%s)", iter->second END
  17.559 +		}
  17.560 +		else
  17.561 +		{
  17.562 +		    APPENDPRINT "function(" END
  17.563 +		    Proto * p = (L->base + i - 1)->value.gc->cl.l.p;
  17.564 +		    int numParams = p->numparams + (p->is_vararg ? 1 : 0);
  17.565 +		    for (int n = 0; n < p->numparams; n++)
  17.566 +		    {
  17.567 +		        APPENDPRINT "%s", getstr(p->locvars[n].varname) END
  17.568 +		        if (n != numParams - 1)
  17.569 +					APPENDPRINT "," END
  17.570 +					}
  17.571 +					if (p->is_vararg)
  17.572 +						APPENDPRINT "..." END
  17.573 +						APPENDPRINT ")" END
  17.574 +						}
  17.575 +						break;
  17.576 +defcase: default:
  17.577 +				APPENDPRINT "%s:%p", luaL_typename(L, i), lua_topointer(L, i) END break;
  17.578 +			case LUA_TTABLE:
  17.579 +				{
  17.580 +				    // first make sure there's enough stack space
  17.581 +				    if (!lua_checkstack(L, 4))
  17.582 +				    {
  17.583 +				        // note that even if lua_checkstack never returns false,
  17.584 +				        // that doesn't mean we didn't need to call it,
  17.585 +				        // because calling it retrieves stack space past LUA_MINSTACK
  17.586 +				        goto defcase;
  17.587 +					}
  17.588 +
  17.589 +				    std::vector<const void *>::const_iterator foundCycleIter =
  17.590 +				        std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L, i));
  17.591 +				    if (foundCycleIter != s_tableAddressStack.end())
  17.592 +				    {
  17.593 +				        int parentNum = s_tableAddressStack.end() - foundCycleIter;
  17.594 +				        if (parentNum > 1)
  17.595 +							APPENDPRINT "%s:parent^%d", luaL_typename(L, i), parentNum END
  17.596 +							else
  17.597 +								APPENDPRINT "%s:parent", luaL_typename(L, i) END
  17.598 +								}
  17.599 +								else
  17.600 +								{
  17.601 +								    s_tableAddressStack.push_back(lua_topointer(L, i));
  17.602 +								    struct Scope { ~Scope(){ s_tableAddressStack. pop_back(); } } scope;
  17.603 +
  17.604 +								    APPENDPRINT "{" END
  17.605 +
  17.606 +								               lua_pushnil(L); // first key
  17.607 +								    int		   keyIndex = lua_gettop(L);
  17.608 +								    int		   valueIndex = keyIndex + 1;
  17.609 +								    bool	   first = true;
  17.610 +								    bool	   skipKey = true; // true if we're still in the "array part" of the table
  17.611 +								    lua_Number arrayIndex = (lua_Number)0;
  17.612 +								    while (lua_next(L, i))
  17.613 +								    {
  17.614 +								        if (first)
  17.615 +											first = false;
  17.616 +								        else
  17.617 +											APPENDPRINT ", " END
  17.618 +											if (skipKey)
  17.619 +											{
  17.620 +											    arrayIndex += (lua_Number)1;
  17.621 +											    bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
  17.622 +											    skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex);
  17.623 +											}
  17.624 +								        if (!skipKey)
  17.625 +								        {
  17.626 +								            bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
  17.627 +								            bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex)));
  17.628 +								            if (invalidLuaIdentifier)
  17.629 +												if (keyIsString)
  17.630 +													APPENDPRINT "['" END
  17.631 +													else
  17.632 +														APPENDPRINT "[" END
  17.633 +
  17.634 +														toCStringConverter(L, keyIndex, ptr, remaining);
  17.635 +								            // key
  17.636 +
  17.637 +								            if (invalidLuaIdentifier)
  17.638 +												if (keyIsString)
  17.639 +													APPENDPRINT "']=" END
  17.640 +													else
  17.641 +														APPENDPRINT "]=" END
  17.642 +														else
  17.643 +															APPENDPRINT "=" END
  17.644 +															}
  17.645 +
  17.646 +															bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING);
  17.647 +								            if (valueIsString)
  17.648 +												APPENDPRINT "'" END
  17.649 +
  17.650 +												toCStringConverter(L, valueIndex, ptr, remaining);  // value
  17.651 +
  17.652 +								            if (valueIsString)
  17.653 +												APPENDPRINT "'" END
  17.654 +
  17.655 +												lua_pop(L, 1);
  17.656 +
  17.657 +								            if (remaining <= 0)
  17.658 +								            {
  17.659 +								                lua_settop(L, keyIndex - 1); // stack might not be clean yet if we're breaking
  17.660 +								                                             // early
  17.661 +								                break;
  17.662 +											}
  17.663 +										}
  17.664 +								        APPENDPRINT "}" END
  17.665 +									}
  17.666 +								}
  17.667 +				        break;
  17.668 +					}
  17.669 +
  17.670 +				    if (usedMeta)
  17.671 +				    {
  17.672 +				        s_metacallStack.pop_back();
  17.673 +				        lua_pop(L, 1);
  17.674 +					}
  17.675 +				}
  17.676 +
  17.677 +				static const int s_tempStrMaxLen = 64 * 1024;
  17.678 +				static char s_tempStr [s_tempStrMaxLen];
  17.679 +
  17.680 +				static char *rawToCString(lua_State *L, int idx)
  17.681 +				{
  17.682 +				    int a = idx > 0 ? idx : 1;
  17.683 +				    int n = idx > 0 ? idx : lua_gettop(L);
  17.684 +
  17.685 +				    char *ptr = s_tempStr;
  17.686 +				    *ptr = 0;
  17.687 +
  17.688 +				    int remaining = s_tempStrMaxLen;
  17.689 +				    for (int i = a; i <= n; i++)
  17.690 +				    {
  17.691 +				        toCStringConverter(L, i, ptr, remaining);
  17.692 +				        if (i != n)
  17.693 +							APPENDPRINT " " END
  17.694 +							}
  17.695 +
  17.696 +							if (remaining < 3)
  17.697 +							{
  17.698 +							    while (remaining < 6)
  17.699 +									remaining++, ptr--;
  17.700 +							    APPENDPRINT "..." END
  17.701 +							}
  17.702 +				        APPENDPRINT "\r\n" END
  17.703 +				        // the trailing newline is so print() can avoid having to do wasteful things to print its newline
  17.704 +				        // (string copying would be wasteful and calling info.print() twice can be extremely slow)
  17.705 +				        // at the cost of functions that don't want the newline needing to trim off the last two characters
  17.706 +				        // (which is a very fast operation and thus acceptable in this case)
  17.707 +
  17.708 +				        return s_tempStr;
  17.709 +					}
  17.710 +#undef APPENDPRINT
  17.711 +#undef END
  17.712 +
  17.713 +// replacement for luaB_tostring() that is able to show the contents of tables (and formats numbers better, and show function
  17.714 +// prototypes)
  17.715 +// can be called directly from lua via tostring(), assuming tostring hasn't been reassigned
  17.716 +				    static int tostring(lua_State *L)
  17.717 +				    {
  17.718 +				        char *str = rawToCString(L);
  17.719 +				        str[strlen(str) - 2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's
  17.720 +				                                  // task)
  17.721 +				        lua_pushstring(L, str);
  17.722 +				        return 1;
  17.723 +					}
  17.724 +
  17.725 +// like rawToCString, but will check if the global Lua function tostring()
  17.726 +// has been replaced with a custom function, and call that instead if so
  17.727 +				    static const char *toCString(lua_State *L, int idx)
  17.728 +				    {
  17.729 +				        int a = idx > 0 ? idx : 1;
  17.730 +				        int n = idx > 0 ? idx : lua_gettop(L);
  17.731 +				        lua_getglobal(L, "tostring");
  17.732 +				        lua_CFunction cf = lua_tocfunction(L, -1);
  17.733 +				        if (cf == tostring || lua_isnil(L, -1)) // optimization: if using our own C tostring function, we can
  17.734 +				                                                // bypass the call through Lua and all the string object
  17.735 +				                                                // allocation that would entail
  17.736 +				        {
  17.737 +				            lua_pop(L, 1);
  17.738 +				            return rawToCString(L, idx);
  17.739 +						}
  17.740 +				        else // if the user overrided the tostring function, we have to actually call it and store the
  17.741 +				             // temporarily allocated string it returns
  17.742 +				        {
  17.743 +				            lua_pushstring(L, "");
  17.744 +				            for (int i = a; i <= n; i++)
  17.745 +				            {
  17.746 +				                lua_pushvalue(L, -2); // function to be called
  17.747 +				                lua_pushvalue(L, i); // value to print
  17.748 +				                lua_call(L, 1, 1);
  17.749 +				                if (lua_tostring(L, -1) == NULL)
  17.750 +									luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print"));
  17.751 +				                lua_pushstring(L, (i < n) ? " " : "\r\n");
  17.752 +				                lua_concat(L, 3);
  17.753 +							}
  17.754 +				            const char *str = lua_tostring(L, -1);
  17.755 +				            strncpy(s_tempStr, str, s_tempStrMaxLen);
  17.756 +				            s_tempStr[s_tempStrMaxLen - 1] = 0;
  17.757 +				            lua_pop(L, 2);
  17.758 +				            return s_tempStr;
  17.759 +						}
  17.760 +					}
  17.761 +
  17.762 +// replacement for luaB_print() that goes to the appropriate textbox instead of stdout
  17.763 +				    static int print(lua_State *L)
  17.764 +				    {
  17.765 +				        const char *str = toCString(L);
  17.766 +
  17.767 +				        int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread];
  17.768 +				        //LuaContextInfo& info = GetCurrentInfo();
  17.769 +
  17.770 +				        if (info_print)
  17.771 +							info_print(uid, str);
  17.772 +				        else
  17.773 +							puts(str);
  17.774 +
  17.775 +				        //worry(L, 100);
  17.776 +				        return 0;
  17.777 +					}
  17.778 +
  17.779 +				    static int printerror(lua_State *L, int idx)
  17.780 +				    {
  17.781 +				        lua_checkstack(L, lua_gettop(L) + 4);
  17.782 +
  17.783 +				        if (idx < 0)
  17.784 +							idx = lua_gettop(L) + 1 + idx;
  17.785 +
  17.786 +				        const char *str = rawToCString(L, idx);
  17.787 +
  17.788 +				        int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread];
  17.789 +				        //LuaContextInfo& info = GetCurrentInfo();
  17.790 +
  17.791 +				        if (info_print)
  17.792 +							info_print(uid, str);
  17.793 +				        else
  17.794 +							fputs(str, stderr);
  17.795 +
  17.796 +				        //worry(L, 100);
  17.797 +				        return 0;
  17.798 +					}
  17.799 +
  17.800 +// vba.message(string msg)
  17.801 +//
  17.802 +//  Displays the given message on the screen.
  17.803 +				    static int vba_message(lua_State *L)
  17.804 +				    {
  17.805 +				        const char *msg = luaL_checkstring(L, 1);
  17.806 +				        systemScreenMessage(msg);
  17.807 +
  17.808 +				        return 0;
  17.809 +					}
  17.810 +
  17.811 +// provides an easy way to copy a table from Lua
  17.812 +// (simple assignment only makes an alias, but sometimes an independent table is desired)
  17.813 +// currently this function only performs a shallow copy,
  17.814 +// but I think it should be changed to do a deep copy (possibly of configurable depth?)
  17.815 +// that maintains the internal table reference structure
  17.816 +				    static int copytable(lua_State *L)
  17.817 +				    {
  17.818 +				        int origIndex = 1; // we only care about the first argument
  17.819 +				        int origType = lua_type(L, origIndex);
  17.820 +				        if (origType == LUA_TNIL)
  17.821 +				        {
  17.822 +				            lua_pushnil(L);
  17.823 +				            return 1;
  17.824 +						}
  17.825 +				        if (origType != LUA_TTABLE)
  17.826 +				        {
  17.827 +				            luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE));
  17.828 +				            lua_pushnil(L);
  17.829 +				            return 1;
  17.830 +						}
  17.831 +
  17.832 +				        lua_createtable(L, lua_objlen(L, 1), 0);
  17.833 +				        int copyIndex = lua_gettop(L);
  17.834 +
  17.835 +				        lua_pushnil(L); // first key
  17.836 +				        int keyIndex = lua_gettop(L);
  17.837 +				        int valueIndex = keyIndex + 1;
  17.838 +
  17.839 +				        while (lua_next(L, origIndex))
  17.840 +				        {
  17.841 +				            lua_pushvalue(L, keyIndex);
  17.842 +				            lua_pushvalue(L, valueIndex);
  17.843 +				            lua_rawset(L, copyIndex); // copytable[key] = value
  17.844 +				            lua_pop(L, 1);
  17.845 +						}
  17.846 +
  17.847 +				        // copy the reference to the metatable as well, if any
  17.848 +				        if (lua_getmetatable(L, origIndex))
  17.849 +							lua_setmetatable(L, copyIndex);
  17.850 +
  17.851 +				        return 1; // return the new table
  17.852 +					}
  17.853 +
  17.854 +// because print traditionally shows the address of tables,
  17.855 +// and the print function I provide instead shows the contents of tables,
  17.856 +// I also provide this function
  17.857 +// (otherwise there would be no way to see a table's address, AFAICT)
  17.858 +				    static int addressof(lua_State *L)
  17.859 +				    {
  17.860 +				        const void *ptr = lua_topointer(L, -1);
  17.861 +				        lua_pushinteger(L, (lua_Integer)ptr);
  17.862 +				        return 1;
  17.863 +					}
  17.864 +
  17.865 +				    struct registerPointerMap
  17.866 +				    {
  17.867 +				        const char *  registerName;
  17.868 +				        unsigned int *pointer;
  17.869 +				        int dataSize;
  17.870 +					};
  17.871 +
  17.872 +#define RPM_ENTRY(name, var) \
  17.873 +	{ name, (unsigned int *)&var, sizeof(var) \
  17.874 +	} \
  17.875 +	,
  17.876 +
  17.877 +				    extern gbRegister AF;
  17.878 +				    extern gbRegister BC;
  17.879 +				    extern gbRegister DE;
  17.880 +				    extern gbRegister HL;
  17.881 +				    extern gbRegister SP;
  17.882 +				    extern gbRegister PC;
  17.883 +				    extern u16 IFF;
  17.884 +
  17.885 +				    registerPointerMap regPointerMap [] = {
  17.886 +				        // gba registers
  17.887 +				        RPM_ENTRY("r0",	  reg[0].I)
  17.888 +				        RPM_ENTRY("r1",	  reg[1].I)
  17.889 +				        RPM_ENTRY("r2",	  reg[2].I)
  17.890 +				        RPM_ENTRY("r3",	  reg[3].I)
  17.891 +				        RPM_ENTRY("r4",	  reg[4].I)
  17.892 +				        RPM_ENTRY("r5",	  reg[5].I)
  17.893 +				        RPM_ENTRY("r6",	  reg[6].I)
  17.894 +				        RPM_ENTRY("r7",	  reg[7].I)
  17.895 +				        RPM_ENTRY("r8",	  reg[8].I)
  17.896 +				        RPM_ENTRY("r9",	  reg[9].I)
  17.897 +				        RPM_ENTRY("r10",  reg[10].I)
  17.898 +				        RPM_ENTRY("r11",  reg[11].I)
  17.899 +				        RPM_ENTRY("r12",  reg[12].I)
  17.900 +				        RPM_ENTRY("r13",  reg[13].I)
  17.901 +				        RPM_ENTRY("r14",  reg[14].I)
  17.902 +				        RPM_ENTRY("r15",  reg[15].I)
  17.903 +				        RPM_ENTRY("cpsr", reg[16].I)
  17.904 +				        RPM_ENTRY("spsr", reg[17].I)
  17.905 +				        // gb registers
  17.906 +				        RPM_ENTRY("a",	  AF.B.B1)
  17.907 +				        RPM_ENTRY("f",	  AF.B.B0)
  17.908 +				        RPM_ENTRY("b",	  BC.B.B1)
  17.909 +				        RPM_ENTRY("c",	  BC.B.B0)
  17.910 +				        RPM_ENTRY("d",	  DE.B.B1)
  17.911 +				        RPM_ENTRY("e",	  DE.B.B0)
  17.912 +				        RPM_ENTRY("h",	  HL.B.B1)
  17.913 +				        RPM_ENTRY("l",	  HL.B.B0)
  17.914 +				        RPM_ENTRY("af",	  AF.W)
  17.915 +				        RPM_ENTRY("bc",	  BC.W)
  17.916 +				        RPM_ENTRY("de",	  DE.W)
  17.917 +				        RPM_ENTRY("hl",	  HL.W)
  17.918 +				        RPM_ENTRY("sp",	  SP.W)
  17.919 +				        RPM_ENTRY("pc",	  PC.W)
  17.920 +				        {}
  17.921 +					};
  17.922 +
  17.923 +				    struct cpuToRegisterMap
  17.924 +				    {
  17.925 +				        const char *cpuName;
  17.926 +				        registerPointerMap *rpmap;
  17.927 +					}
  17.928 +				    cpuToRegisterMaps [] =
  17.929 +				    {
  17.930 +				        { "", regPointerMap },
  17.931 +					};
  17.932 +
  17.933 +//DEFINE_LUA_FUNCTION(memory_getregister, "cpu_dot_registername_string")
  17.934 +				    static int memory_getregister(lua_State *L)
  17.935 +				    {
  17.936 +				        const char *qualifiedRegisterName = luaL_checkstring(L, 1);
  17.937 +				        lua_settop(L, 0);
  17.938 +				        for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++)
  17.939 +				        {
  17.940 +				            cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
  17.941 +				            int cpuNameLen		  = strlen(ctrm.cpuName);
  17.942 +				            if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen))
  17.943 +				            {
  17.944 +				                qualifiedRegisterName += cpuNameLen;
  17.945 +				                for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
  17.946 +				                {
  17.947 +				                    registerPointerMap rpm = ctrm.rpmap[reg];
  17.948 +				                    if (!stricmp(qualifiedRegisterName, rpm.registerName))
  17.949 +				                    {
  17.950 +				                        switch (rpm.dataSize)
  17.951 +				                        {
  17.952 +										default:
  17.953 +										case 1:
  17.954 +											lua_pushinteger(L, *(unsigned char *)rpm.pointer); break;
  17.955 +										case 2:
  17.956 +											lua_pushinteger(L, *(unsigned short *)rpm.pointer); break;
  17.957 +										case 4:
  17.958 +											lua_pushinteger(L, *(unsigned long *)rpm.pointer); break;
  17.959 +										}
  17.960 +				                        return 1;
  17.961 +									}
  17.962 +								}
  17.963 +				                lua_pushnil(L);
  17.964 +				                return 1;
  17.965 +							}
  17.966 +						}
  17.967 +				        lua_pushnil(L);
  17.968 +				        return 1;
  17.969 +					}
  17.970 +
  17.971 +//DEFINE_LUA_FUNCTION(memory_setregister, "cpu_dot_registername_string,value")
  17.972 +				    static int memory_setregister(lua_State *L)
  17.973 +				    {
  17.974 +				        const char *  qualifiedRegisterName = luaL_checkstring(L, 1);
  17.975 +				        unsigned long value = (unsigned long)(luaL_checkinteger(L, 2));
  17.976 +				        lua_settop(L, 0);
  17.977 +				        for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++)
  17.978 +				        {
  17.979 +				            cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
  17.980 +				            int cpuNameLen		  = strlen(ctrm.cpuName);
  17.981 +				            if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen))
  17.982 +				            {
  17.983 +				                qualifiedRegisterName += cpuNameLen;
  17.984 +				                for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
  17.985 +				                {
  17.986 +				                    registerPointerMap rpm = ctrm.rpmap[reg];
  17.987 +				                    if (!stricmp(qualifiedRegisterName, rpm.registerName))
  17.988 +				                    {
  17.989 +				                        switch (rpm.dataSize)
  17.990 +				                        {
  17.991 +										default:
  17.992 +										case 1:
  17.993 +											*(unsigned char *)rpm.pointer = (unsigned char)(value & 0xFF); break;
  17.994 +										case 2:
  17.995 +											*(unsigned short *)rpm.pointer = (unsigned short)(value & 0xFFFF); break;
  17.996 +										case 4:
  17.997 +											*(unsigned long *)rpm.pointer = value; break;
  17.998 +										}
  17.999 +				                        return 0;
 17.1000 +									}
 17.1001 +								}
 17.1002 +				                return 0;
 17.1003 +							}
 17.1004 +						}
 17.1005 +				        return 0;
 17.1006 +					}
 17.1007 +
 17.1008 +				    void HandleCallbackError(lua_State *L)
 17.1009 +				    {
 17.1010 +				        if (L->errfunc || L->errorJmp)
 17.1011 +							luaL_error(L, "%s", lua_tostring(L, -1));
 17.1012 +				        else
 17.1013 +				        {
 17.1014 +				            lua_pushnil(LUA);
 17.1015 +				            lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
 17.1016 +
 17.1017 +				            // Error?
 17.1018 +//#if (defined(WIN32) && !defined(SDL))
 17.1019 +//		info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer();
 17.1020 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua run error", MB_OK | MB_ICONSTOP);
 17.1021 +//#else
 17.1022 +//		fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(LUA, -1));
 17.1023 +//#endif
 17.1024 +				            printerror(LUA, -1);
 17.1025 +				            VBALuaStop();
 17.1026 +						}
 17.1027 +					}
 17.1028 +
 17.1029 +				    void CallRegisteredLuaFunctions(LuaCallID calltype)
 17.1030 +				    {
 17.1031 +				        assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT);
 17.1032 +
 17.1033 +				        const char *idstring = luaCallIDStrings[calltype];
 17.1034 +
 17.1035 +				        if (!LUA)
 17.1036 +							return;
 17.1037 +
 17.1038 +				        lua_settop(LUA, 0);
 17.1039 +				        lua_getfield(LUA, LUA_REGISTRYINDEX, idstring);
 17.1040 +
 17.1041 +				        int errorcode = 0;
 17.1042 +				        if (lua_isfunction(LUA, -1))
 17.1043 +				        {
 17.1044 +				            errorcode = lua_pcall(LUA, 0, 0, 0);
 17.1045 +				            if (errorcode)
 17.1046 +								HandleCallbackError(LUA);
 17.1047 +						}
 17.1048 +				        else
 17.1049 +				        {
 17.1050 +				            lua_pop(LUA, 1);
 17.1051 +						}
 17.1052 +					}
 17.1053 +
 17.1054 +// the purpose of this structure is to provide a way of
 17.1055 +// QUICKLY determining whether a memory address range has a hook associated with it,
 17.1056 +// with a bias toward fast rejection because the majority of addresses will not be hooked.
 17.1057 +// (it must not use any part of Lua or perform any per-script operations,
 17.1058 +//  otherwise it would definitely be too slow.)
 17.1059 +// calculating the regions when a hook is added/removed may be slow,
 17.1060 +// but this is an intentional tradeoff to obtain a high speed of checking during later execution
 17.1061 +				    struct TieredRegion
 17.1062 +				    {
 17.1063 +				        template<unsigned int maxGap>
 17.1064 +				        struct Region
 17.1065 +				        {
 17.1066 +				            struct Island
 17.1067 +				            {
 17.1068 +				                unsigned int	   start;
 17.1069 +				                unsigned int	   end;
 17.1070 +				                __forceinline bool Contains(unsigned int address, int size) const { return address < end && address + size > start; }
 17.1071 +							};
 17.1072 +				            std::vector<Island> islands;
 17.1073 +
 17.1074 +				            void Calculate(const std::vector<unsigned int> &bytes)
 17.1075 +				            {
 17.1076 +				                islands. clear();
 17.1077 +
 17.1078 +				                unsigned int lastEnd = ~0;
 17.1079 +
 17.1080 +				                std::vector<unsigned int>::const_iterator iter = bytes.begin();
 17.1081 +				                std::vector<unsigned int>::const_iterator end  = bytes.end();
 17.1082 +				                for (; iter != end; ++iter)
 17.1083 +				                {
 17.1084 +				                    unsigned int addr = *iter;
 17.1085 +				                    if (addr < lastEnd || addr > lastEnd + (long long)maxGap)
 17.1086 +				                    {
 17.1087 +				                        islands. push_back(Island());
 17.1088 +				                        islands. back().start = addr;
 17.1089 +									}
 17.1090 +				                    islands.back(). end = addr + 1;
 17.1091 +				                    lastEnd = addr + 1;
 17.1092 +								}
 17.1093 +							}
 17.1094 +
 17.1095 +				            bool Contains(unsigned int address, int size) const
 17.1096 +				            {
 17.1097 +				                for (size_t i = 0; i != islands.size(); ++i)
 17.1098 +				                {
 17.1099 +				                    if (islands[i].Contains(address, size))
 17.1100 +										return true;
 17.1101 +								}
 17.1102 +				                return false;
 17.1103 +							}
 17.1104 +						};
 17.1105 +
 17.1106 +				        Region<0xFFFFFFFF> broad;
 17.1107 +				        Region<0x1000>	   mid;
 17.1108 +				        Region<0>		   narrow;
 17.1109 +
 17.1110 +				        void Calculate(std::vector<unsigned int> &bytes)
 17.1111 +				        {
 17.1112 +				            std:: sort(bytes.begin(), bytes.end());
 17.1113 +
 17.1114 +				            broad.	Calculate(bytes);
 17.1115 +				            mid.	Calculate(bytes);
 17.1116 +				            narrow. Calculate(bytes);
 17.1117 +						}
 17.1118 +
 17.1119 +				        TieredRegion()
 17.1120 +				        {
 17.1121 +				            std::vector <unsigned int> temp;
 17.1122 +				            Calculate(temp);
 17.1123 +						}
 17.1124 +
 17.1125 +				        __forceinline int NotEmpty()
 17.1126 +				        {
 17.1127 +				            return broad.islands.size();
 17.1128 +						}
 17.1129 +
 17.1130 +				        // note: it is illegal to call this if NotEmpty() returns 0
 17.1131 +				        __forceinline bool Contains(unsigned int address, int size)
 17.1132 +				        {
 17.1133 +				            return broad.islands[0].Contains(address, size) &&
 17.1134 +				                   mid.Contains(address, size) &&
 17.1135 +				                   narrow.Contains(address, size);
 17.1136 +						}
 17.1137 +					};
 17.1138 +				    TieredRegion hookedRegions [LUAMEMHOOK_COUNT];
 17.1139 +
 17.1140 +				    static void CalculateMemHookRegions(LuaMemHookType hookType)
 17.1141 +				    {
 17.1142 +				        std::vector<unsigned int> hookedBytes;
 17.1143 +//	std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin();
 17.1144 +//	std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end();
 17.1145 +//	while(iter != end)
 17.1146 +//	{
 17.1147 +//		LuaContextInfo& info = *iter->second;
 17.1148 +				        if (/*info.*/ numMemHooks)
 17.1149 +				        {
 17.1150 +				            lua_State *L = LUA /*info.L*/;
 17.1151 +				            if (L)
 17.1152 +				            {
 17.1153 +				                lua_settop(L, 0);
 17.1154 +				                lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
 17.1155 +				                lua_pushnil(L);
 17.1156 +				                while (lua_next(L, -2))
 17.1157 +				                {
 17.1158 +				                    if (lua_isfunction(L, -1))
 17.1159 +				                    {
 17.1160 +				                        unsigned int addr = lua_tointeger(L, -2);
 17.1161 +				                        hookedBytes.push_back(addr);
 17.1162 +									}
 17.1163 +				                    lua_pop(L, 1);
 17.1164 +								}
 17.1165 +				                lua_settop(L, 0);
 17.1166 +							}
 17.1167 +						}
 17.1168 +//		++iter;
 17.1169 +//	}
 17.1170 +				        hookedRegions[hookType].Calculate(hookedBytes);
 17.1171 +					}
 17.1172 +
 17.1173 +				    static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
 17.1174 +				    {
 17.1175 +//	std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin();
 17.1176 +//	std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end();
 17.1177 +//	while(iter != end)
 17.1178 +//	{
 17.1179 +//		LuaContextInfo& info = *iter->second;
 17.1180 +				        if (/*info.*/ numMemHooks)
 17.1181 +				        {
 17.1182 +				            lua_State *L = LUA /*info.L*/;
 17.1183 +				            if (L /* && !info.panic*/)
 17.1184 +				            {
 17.1185 +#ifdef USE_INFO_STACK
 17.1186 +				                infoStack.insert(infoStack.begin(), &info);
 17.1187 +				                struct Scope { ~Scope(){ infoStack. erase(infoStack.begin()); } } scope;
 17.1188 +#endif
 17.1189 +				                lua_settop(L, 0);
 17.1190 +				                lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
 17.1191 +				                for (int i = address; i != address + size; i++)
 17.1192 +				                {
 17.1193 +				                    lua_rawgeti(L, -1, i);
 17.1194 +				                    if (lua_isfunction(L, -1))
 17.1195 +				                    {
 17.1196 +				                        bool wasRunning = (luaRunning != 0) /*info.running*/;
 17.1197 +				                        luaRunning /*info.running*/ = true;
 17.1198 +				                        //RefreshScriptSpeedStatus();
 17.1199 +				                        lua_pushinteger(L, address);
 17.1200 +				                        lua_pushinteger(L, size);
 17.1201 +				                        int errorcode = lua_pcall(L, 2, 0, 0);
 17.1202 +				                        luaRunning /*info.running*/ = wasRunning;
 17.1203 +				                        //RefreshScriptSpeedStatus();
 17.1204 +				                        if (errorcode)
 17.1205 +				                        {
 17.1206 +				                            HandleCallbackError(L);
 17.1207 +				                            //int uid = iter->first;
 17.1208 +				                            //HandleCallbackError(L,info,uid,true);
 17.1209 +										}
 17.1210 +				                        break;
 17.1211 +									}
 17.1212 +				                    else
 17.1213 +				                    {
 17.1214 +				                        lua_pop(L, 1);
 17.1215 +									}
 17.1216 +								}
 17.1217 +				                lua_settop(L, 0);
 17.1218 +							}
 17.1219 +						}
 17.1220 +//		++iter;
 17.1221 +//	}
 17.1222 +					}
 17.1223 +
 17.1224 +				    void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
 17.1225 +				    {
 17.1226 +				        // performance critical! (called VERY frequently)
 17.1227 +				        // I suggest timing a large number of calls to this function in Release if you change anything in here,
 17.1228 +				        // before and after, because even the most innocent change can make it become 30% to 400% slower.
 17.1229 +				        // a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set.
 17.1230 +				        // (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter
 17.1231 +				        // case)
 17.1232 +				        if (hookedRegions[hookType].NotEmpty())
 17.1233 +				        {
 17.1234 +				            //if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000))
 17.1235 +				            //	address |= 0xFF0000; // account for mirroring of RAM
 17.1236 +				            if (hookedRegions[hookType].Contains(address, size))
 17.1237 +								CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType);  // something has hooked this
 17.1238 +				                                                                                    // specific address
 17.1239 +						}
 17.1240 +					}
 17.1241 +
 17.1242 +				    static int memory_registerHook(lua_State *L, LuaMemHookType hookType, int defaultSize)
 17.1243 +				    {
 17.1244 +				        // get first argument: address
 17.1245 +				        unsigned int addr = luaL_checkinteger(L, 1);
 17.1246 +				        //if((addr & ~0xFFFFFF) == ~0xFFFFFF)
 17.1247 +				        //	addr &= 0xFFFFFF;
 17.1248 +
 17.1249 +				        // get optional second argument: size
 17.1250 +				        int size	= defaultSize;
 17.1251 +				        int funcIdx = 2;
 17.1252 +				        if (lua_isnumber(L, 2))
 17.1253 +				        {
 17.1254 +				            size = luaL_checkinteger(L, 2);
 17.1255 +				            if (size < 0)
 17.1256 +				            {
 17.1257 +				                size  = -size;
 17.1258 +				                addr -= size;
 17.1259 +							}
 17.1260 +				            funcIdx++;
 17.1261 +						}
 17.1262 +
 17.1263 +				        // check last argument: callback function
 17.1264 +				        bool clearing = lua_isnil(L, funcIdx);
 17.1265 +				        if (!clearing)
 17.1266 +							luaL_checktype(L, funcIdx, LUA_TFUNCTION);
 17.1267 +				        lua_settop(L, funcIdx);
 17.1268 +
 17.1269 +				        // get the address-to-callback table for this hook type of the current script
 17.1270 +				        lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
 17.1271 +
 17.1272 +				        // count how many callback functions we'll be displacing
 17.1273 +				        int numFuncsAfter  = clearing ? 0 : size;
 17.1274 +				        int numFuncsBefore = 0;
 17.1275 +				        for (unsigned int i = addr; i != addr + size; i++)
 17.1276 +				        {
 17.1277 +				            lua_rawgeti(L, -1, i);
 17.1278 +				            if (lua_isfunction(L, -1))
 17.1279 +								numFuncsBefore++;
 17.1280 +				            lua_pop(L, 1);
 17.1281 +						}
 17.1282 +
 17.1283 +				        // put the callback function in the address slots
 17.1284 +				        for (unsigned int i = addr; i != addr + size; i++)
 17.1285 +				        {
 17.1286 +				            lua_pushvalue(L, -2);
 17.1287 +				            lua_rawseti(L, -2, i);
 17.1288 +						}
 17.1289 +
 17.1290 +				        // adjust the count of active hooks
 17.1291 +				        //LuaContextInfo& info = GetCurrentInfo();
 17.1292 +				        /*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore;
 17.1293 +
 17.1294 +				        // re-cache regions of hooked memory across all scripts
 17.1295 +				        CalculateMemHookRegions(hookType);
 17.1296 +
 17.1297 +				        //StopScriptIfFinished(luaStateToUIDMap[L]);
 17.1298 +				        return 0;
 17.1299 +					}
 17.1300 +
 17.1301 +				    LuaMemHookType MatchHookTypeToCPU(lua_State *L, LuaMemHookType hookType)
 17.1302 +				    {
 17.1303 +				        int cpuID = 0;
 17.1304 +
 17.1305 +				        int cpunameIndex = 0;
 17.1306 +				        if (lua_type(L, 2) == LUA_TSTRING)
 17.1307 +							cpunameIndex = 2;
 17.1308 +				        else if (lua_type(L, 3) == LUA_TSTRING)
 17.1309 +							cpunameIndex = 3;
 17.1310 +
 17.1311 +				        if (cpunameIndex)
 17.1312 +				        {
 17.1313 +				            const char *cpuName = lua_tostring(L, cpunameIndex);
 17.1314 +				            if (!stricmp(cpuName, "sub"))
 17.1315 +								cpuID = 1;
 17.1316 +				            lua_remove(L, cpunameIndex);
 17.1317 +						}
 17.1318 +
 17.1319 +				        switch (cpuID)
 17.1320 +				        {
 17.1321 +						case 0:
 17.1322 +							return hookType;
 17.1323 +
 17.1324 +						case 1:
 17.1325 +							switch (hookType)
 17.1326 +							{
 17.1327 +							case LUAMEMHOOK_WRITE:
 17.1328 +								return LUAMEMHOOK_WRITE_SUB;
 17.1329 +							case LUAMEMHOOK_READ:
 17.1330 +								return LUAMEMHOOK_READ_SUB;
 17.1331 +							case LUAMEMHOOK_EXEC:
 17.1332 +								return LUAMEMHOOK_EXEC_SUB;
 17.1333 +							}
 17.1334 +						}
 17.1335 +				        return hookType;
 17.1336 +					}
 17.1337 +
 17.1338 +				    static int memory_registerwrite(lua_State *L)
 17.1339 +				    {
 17.1340 +				        return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_WRITE), 1);
 17.1341 +					}
 17.1342 +
 17.1343 +				    static int memory_registerread(lua_State *L)
 17.1344 +				    {
 17.1345 +				        return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_READ), 1);
 17.1346 +					}
 17.1347 +
 17.1348 +				    static int memory_registerexec(lua_State *L)
 17.1349 +				    {
 17.1350 +				        return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_EXEC), 1);
 17.1351 +					}
 17.1352 +
 17.1353 +//int vba.lagcount
 17.1354 +//
 17.1355 +
 17.1356 +//Returns the lagcounter variable
 17.1357 +				    static int vba_getlagcount(lua_State *L)
 17.1358 +				    {
 17.1359 +				        lua_pushinteger(L, systemCounters.lagCount);
 17.1360 +				        return 1;
 17.1361 +					}
 17.1362 +
 17.1363 +//int vba.lagged
 17.1364 +//
 17.1365 +//Returns true if the current frame is a lag frame
 17.1366 +				    static int vba_lagged(lua_State *L)
 17.1367 +				    {
 17.1368 +				        lua_pushboolean(L, systemCounters.laggedLast);
 17.1369 +				        return 1;
 17.1370 +					}
 17.1371 +
 17.1372 +// boolean vba.emulating()
 17.1373 +				    int vba_emulating(lua_State *L)
 17.1374 +				    {
 17.1375 +				        lua_pushboolean(L, systemIsEmulating());
 17.1376 +				        return 1;
 17.1377 +					}
 17.1378 +
 17.1379 +				    int movie_isactive(lua_State *L)
 17.1380 +				    {
 17.1381 +				        lua_pushboolean(L, VBAMovieActive());
 17.1382 +				        return 1;
 17.1383 +					}
 17.1384 +
 17.1385 +				    int movie_isrecording(lua_State *L)
 17.1386 +				    {
 17.1387 +				        lua_pushboolean(L, VBAMovieRecording());
 17.1388 +				        return 1;
 17.1389 +					}
 17.1390 +
 17.1391 +				    int movie_isplaying(lua_State *L)
 17.1392 +				    {
 17.1393 +				        lua_pushboolean(L, VBAMoviePlaying());
 17.1394 +				        return 1;
 17.1395 +					}
 17.1396 +
 17.1397 +				    int movie_getlength(lua_State *L)
 17.1398 +				    {
 17.1399 +				        if (VBAMovieActive())
 17.1400 +							lua_pushinteger(L, VBAMovieGetLength());
 17.1401 +				        else
 17.1402 +							lua_pushinteger(L, 0);
 17.1403 +				        return 1;
 17.1404 +					}
 17.1405 +
 17.1406 +				    static int memory_readbyte(lua_State *L)
 17.1407 +				    {
 17.1408 +				        u32 addr;
 17.1409 +				        u8	val;
 17.1410 +
 17.1411 +				        addr = luaL_checkinteger(L, 1);
 17.1412 +				        if (systemIsRunningGBA())
 17.1413 +				        {
 17.1414 +				            val = CPUReadByteQuick(addr);
 17.1415 +						}
 17.1416 +				        else
 17.1417 +				        {
 17.1418 +				            val = gbReadMemoryQuick8(addr);
 17.1419 +						}
 17.1420 +
 17.1421 +				        lua_pushinteger(L, val);
 17.1422 +				        return 1;
 17.1423 +					}
 17.1424 +
 17.1425 +				    static int memory_readbytesigned(lua_State *L)
 17.1426 +				    {
 17.1427 +				        u32 addr;
 17.1428 +				        s8	val;
 17.1429 +
 17.1430 +				        addr = luaL_checkinteger(L, 1);
 17.1431 +				        if (systemIsRunningGBA())
 17.1432 +				        {
 17.1433 +				            val = (s8) CPUReadByteQuick(addr);
 17.1434 +						}
 17.1435 +				        else
 17.1436 +				        {
 17.1437 +				            val = (s8) gbReadMemoryQuick8(addr);
 17.1438 +						}
 17.1439 +
 17.1440 +				        lua_pushinteger(L, val);
 17.1441 +				        return 1;
 17.1442 +					}
 17.1443 +
 17.1444 +				    static int memory_readword(lua_State *L)
 17.1445 +				    {
 17.1446 +				        u32 addr;
 17.1447 +				        u16 val;
 17.1448 +
 17.1449 +				        addr = luaL_checkinteger(L, 1);
 17.1450 +				        if (systemIsRunningGBA())
 17.1451 +				        {
 17.1452 +				            val = CPUReadHalfWordQuick(addr);
 17.1453 +						}
 17.1454 +				        else
 17.1455 +				        {
 17.1456 +				            val = gbReadMemoryQuick16(addr & 0x0000FFFF);
 17.1457 +						}
 17.1458 +
 17.1459 +				        lua_pushinteger(L, val);
 17.1460 +				        return 1;
 17.1461 +					}
 17.1462 +
 17.1463 +				    static int memory_readwordsigned(lua_State *L)
 17.1464 +				    {
 17.1465 +				        u32 addr;
 17.1466 +				        s16 val;
 17.1467 +
 17.1468 +				        addr = luaL_checkinteger(L, 1);
 17.1469 +				        if (systemIsRunningGBA())
 17.1470 +				        {
 17.1471 +				            val = (s16) CPUReadHalfWordQuick(addr);
 17.1472 +						}
 17.1473 +				        else
 17.1474 +				        {
 17.1475 +				            val = (s16) gbReadMemoryQuick16(addr);
 17.1476 +						}
 17.1477 +
 17.1478 +				        lua_pushinteger(L, val);
 17.1479 +				        return 1;
 17.1480 +					}
 17.1481 +
 17.1482 +				    static int memory_readdword(lua_State *L)
 17.1483 +				    {
 17.1484 +				        u32 addr;
 17.1485 +				        u32 val;
 17.1486 +
 17.1487 +				        addr = luaL_checkinteger(L, 1);
 17.1488 +				        if (systemIsRunningGBA())
 17.1489 +				        {
 17.1490 +				            val = CPUReadMemoryQuick(addr);
 17.1491 +						}
 17.1492 +				        else
 17.1493 +				        {
 17.1494 +				            val = gbReadMemoryQuick32(addr & 0x0000FFFF);
 17.1495 +						}
 17.1496 +
 17.1497 +				        // lua_pushinteger doesn't work properly for 32bit system, does it?
 17.1498 +				        if (val >= 0x80000000 && sizeof(int) <= 4)
 17.1499 +							lua_pushnumber(L, val);
 17.1500 +				        else
 17.1501 +							lua_pushinteger(L, val);
 17.1502 +				        return 1;
 17.1503 +					}
 17.1504 +
 17.1505 +				    static int memory_readdwordsigned(lua_State *L)
 17.1506 +				    {
 17.1507 +				        u32 addr;
 17.1508 +				        s32 val;
 17.1509 +
 17.1510 +				        addr = luaL_checkinteger(L, 1);
 17.1511 +				        if (systemIsRunningGBA())
 17.1512 +				        {
 17.1513 +				            val = (s32) CPUReadMemoryQuick(addr);
 17.1514 +						}
 17.1515 +				        else
 17.1516 +				        {
 17.1517 +				            val = (s32) gbReadMemoryQuick32(addr);
 17.1518 +						}
 17.1519 +
 17.1520 +				        lua_pushinteger(L, val);
 17.1521 +				        return 1;
 17.1522 +					}
 17.1523 +
 17.1524 +				    static int memory_readbyterange(lua_State *L)
 17.1525 +				    {
 17.1526 +				        uint32 address = luaL_checkinteger(L, 1);
 17.1527 +				        int	   length  = luaL_checkinteger(L, 2);
 17.1528 +
 17.1529 +				        if (length < 0)
 17.1530 +				        {
 17.1531 +				            address += length;
 17.1532 +				            length	 = -length;
 17.1533 +						}
 17.1534 +
 17.1535 +				        // push the array
 17.1536 +				        lua_createtable(L, abs(length), 0);
 17.1537 +
 17.1538 +				        // put all the values into the (1-based) array
 17.1539 +				        for (int a = address, n = 1; n <= length; a++, n++)
 17.1540 +				        {
 17.1541 +				            unsigned char value;
 17.1542 +
 17.1543 +				            if (systemIsRunningGBA())
 17.1544 +				            {
 17.1545 +				                value = CPUReadByteQuick(a);
 17.1546 +							}
 17.1547 +				            else
 17.1548 +				            {
 17.1549 +				                value = gbReadMemoryQuick8(a);
 17.1550 +							}
 17.1551 +
 17.1552 +				            lua_pushinteger(L, value);
 17.1553 +				            lua_rawseti(L, -2, n);
 17.1554 +						}
 17.1555 +
 17.1556 +				        return 1;
 17.1557 +					}
 17.1558 +
 17.1559 +				    static int memory_writebyte(lua_State *L)
 17.1560 +				    {
 17.1561 +				        u32 addr;
 17.1562 +				        int val;
 17.1563 +
 17.1564 +				        addr = luaL_checkinteger(L, 1);
 17.1565 +				        val	 = luaL_checkinteger(L, 2);
 17.1566 +				        if (systemIsRunningGBA())
 17.1567 +				        {
 17.1568 +				            CPUWriteByteQuick(addr, val);
 17.1569 +						}
 17.1570 +				        else
 17.1571 +				        {
 17.1572 +				            gbWriteMemoryQuick8(addr, val);
 17.1573 +						}
 17.1574 +
 17.1575 +				        CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
 17.1576 +				        return 0;
 17.1577 +					}
 17.1578 +
 17.1579 +				    static int memory_writeword(lua_State *L)
 17.1580 +				    {
 17.1581 +				        u32 addr;
 17.1582 +				        int val;
 17.1583 +
 17.1584 +				        addr = luaL_checkinteger(L, 1);
 17.1585 +				        val	 = luaL_checkinteger(L, 2);
 17.1586 +				        if (systemIsRunningGBA())
 17.1587 +				        {
 17.1588 +				            CPUWriteHalfWordQuick(addr, val);
 17.1589 +						}
 17.1590 +				        else
 17.1591 +				        {
 17.1592 +				            gbWriteMemoryQuick16(addr, val);
 17.1593 +						}
 17.1594 +
 17.1595 +				        CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
 17.1596 +				        return 0;
 17.1597 +					}
 17.1598 +
 17.1599 +				    static int memory_writedword(lua_State *L)
 17.1600 +				    {
 17.1601 +				        u32 addr;
 17.1602 +				        int val;
 17.1603 +
 17.1604 +				        addr = luaL_checkinteger(L, 1);
 17.1605 +				        val	 = luaL_checkinteger(L, 2);
 17.1606 +				        if (systemIsRunningGBA())
 17.1607 +				        {
 17.1608 +				            CPUWriteMemoryQuick(addr, val);
 17.1609 +						}
 17.1610 +				        else
 17.1611 +				        {
 17.1612 +				            gbWriteMemoryQuick32(addr, val);
 17.1613 +						}
 17.1614 +
 17.1615 +				        CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
 17.1616 +				        return 0;
 17.1617 +					}
 17.1618 +
 17.1619 +				    static int memory_gbromreadbyte(lua_State *L)
 17.1620 +				    {
 17.1621 +				        u32 addr;
 17.1622 +				        u8	val;
 17.1623 +
 17.1624 +				        addr = luaL_checkinteger(L, 1);
 17.1625 +				        if (systemIsRunningGBA())
 17.1626 +				        {
 17.1627 +							lua_pushnil(L);
 17.1628 +							return 1;
 17.1629 +						}
 17.1630 +				        else
 17.1631 +				        {
 17.1632 +				            val = gbReadROMQuick8(addr);
 17.1633 +						}
 17.1634 +
 17.1635 +				        lua_pushinteger(L, val);
 17.1636 +				        return 1;
 17.1637 +					}
 17.1638 +
 17.1639 +				    static int memory_gbromreadbytesigned(lua_State *L)
 17.1640 +				    {
 17.1641 +				        u32 addr;
 17.1642 +				        s8	val;
 17.1643 +
 17.1644 +				        addr = luaL_checkinteger(L, 1);
 17.1645 +				        if (systemIsRunningGBA())
 17.1646 +				        {
 17.1647 +				            lua_pushnil(L);
 17.1648 +							return 1;
 17.1649 +						}
 17.1650 +				        else
 17.1651 +				        {
 17.1652 +				            val = (s8) gbReadROMQuick8(addr);
 17.1653 +						}
 17.1654 +
 17.1655 +				        lua_pushinteger(L, val);
 17.1656 +				        return 1;
 17.1657 +					}
 17.1658 +
 17.1659 +				    static int memory_gbromreadword(lua_State *L)
 17.1660 +				    {
 17.1661 +				        u32 addr;
 17.1662 +				        u16 val;
 17.1663 +
 17.1664 +				        addr = luaL_checkinteger(L, 1);
 17.1665 +				        if (systemIsRunningGBA())
 17.1666 +				        {
 17.1667 +				            lua_pushnil(L);
 17.1668 +							return 1;
 17.1669 +						}
 17.1670 +				        else
 17.1671 +				        {
 17.1672 +				            val = gbReadROMQuick16(addr);
 17.1673 +						}
 17.1674 +
 17.1675 +				        lua_pushinteger(L, val);
 17.1676 +				        return 1;
 17.1677 +					}
 17.1678 +
 17.1679 +				    static int memory_gbromreadwordsigned(lua_State *L)
 17.1680 +				    {
 17.1681 +				        u32 addr;
 17.1682 +				        s16 val;
 17.1683 +
 17.1684 +				        addr = luaL_checkinteger(L, 1);
 17.1685 +				        if (systemIsRunningGBA())
 17.1686 +				        {
 17.1687 +				            lua_pushnil(L);
 17.1688 +							return 1;
 17.1689 +						}
 17.1690 +				        else
 17.1691 +				        {
 17.1692 +				            val = (s16) gbReadROMQuick16(addr);
 17.1693 +						}
 17.1694 +
 17.1695 +				        lua_pushinteger(L, val);
 17.1696 +				        return 1;
 17.1697 +					}
 17.1698 +
 17.1699 +				    static int memory_gbromreaddword(lua_State *L)
 17.1700 +				    {
 17.1701 +				        u32 addr;
 17.1702 +				        u32 val;
 17.1703 +
 17.1704 +				        addr = luaL_checkinteger(L, 1);
 17.1705 +				        if (systemIsRunningGBA())
 17.1706 +				        {
 17.1707 +				            lua_pushnil(L);
 17.1708 +							return 1;
 17.1709 +						}
 17.1710 +				        else
 17.1711 +				        {
 17.1712 +				            val = gbReadROMQuick32(addr);
 17.1713 +						}
 17.1714 +
 17.1715 +				        // lua_pushinteger doesn't work properly for 32bit system, does it?
 17.1716 +				        if (val >= 0x80000000 && sizeof(int) <= 4)
 17.1717 +							lua_pushnumber(L, val);
 17.1718 +				        else
 17.1719 +							lua_pushinteger(L, val);
 17.1720 +				        return 1;
 17.1721 +					}
 17.1722 +
 17.1723 +				    static int memory_gbromreaddwordsigned(lua_State *L)
 17.1724 +				    {
 17.1725 +				        u32 addr;
 17.1726 +				        s32 val;
 17.1727 +
 17.1728 +				        addr = luaL_checkinteger(L, 1);
 17.1729 +				        if (systemIsRunningGBA())
 17.1730 +				        {
 17.1731 +				            lua_pushnil(L);
 17.1732 +							return 1;
 17.1733 +						}
 17.1734 +				        else
 17.1735 +				        {
 17.1736 +				            val = (s32) gbReadROMQuick32(addr);
 17.1737 +						}
 17.1738 +
 17.1739 +				        lua_pushinteger(L, val);
 17.1740 +				        return 1;
 17.1741 +					}
 17.1742 +
 17.1743 +				    static int memory_gbromreadbyterange(lua_State *L)
 17.1744 +				    {
 17.1745 +				        uint32 address = luaL_checkinteger(L, 1);
 17.1746 +				        int	   length  = luaL_checkinteger(L, 2);
 17.1747 +
 17.1748 +				        if (length < 0)
 17.1749 +				        {
 17.1750 +				            address += length;
 17.1751 +				            length	 = -length;
 17.1752 +						}
 17.1753 +
 17.1754 +				        // push the array
 17.1755 +				        lua_createtable(L, abs(length), 0);
 17.1756 +
 17.1757 +				        // put all the values into the (1-based) array
 17.1758 +				        for (int a = address, n = 1; n <= length; a++, n++)
 17.1759 +				        {
 17.1760 +				            unsigned char value;
 17.1761 +
 17.1762 +				            if (systemIsRunningGBA())
 17.1763 +				            {
 17.1764 +				                lua_pushnil(L);
 17.1765 +								return 1;
 17.1766 +							}
 17.1767 +				            else
 17.1768 +				            {
 17.1769 +				                value = gbReadROMQuick8(a);
 17.1770 +							}
 17.1771 +
 17.1772 +				            lua_pushinteger(L, value);
 17.1773 +				            lua_rawseti(L, -2, n);
 17.1774 +						}
 17.1775 +
 17.1776 +				        return 1;
 17.1777 +					}
 17.1778 +
 17.1779 +// table joypad.get(int which = 1)
 17.1780 +//
 17.1781 +//  Reads the joypads as inputted by the user.
 17.1782 +				    static int joy_get_internal(lua_State *L, bool reportUp, bool reportDown)
 17.1783 +				    {
 17.1784 +				        // Reads the joypads as inputted by the user
 17.1785 +				        int which = luaL_checkinteger(L, 1);
 17.1786 +
 17.1787 +				        if (which < 0 || which > 4)
 17.1788 +				        {
 17.1789 +				            luaL_error(L, "Invalid input port (valid range 0-4, specified %d)", which);
 17.1790 +						}
 17.1791 +
 17.1792 +				        uint32 buttons = systemGetOriginalJoypad(which - 1, false);
 17.1793 +
 17.1794 +				        lua_newtable(L);
 17.1795 +
 17.1796 +				        int i;
 17.1797 +				        for (i = 0; i < 10; i++)
 17.1798 +				        {
 17.1799 +				            bool pressed = (buttons & (1 << i)) != 0;
 17.1800 +				            if ((pressed && reportDown) || (!pressed && reportUp))
 17.1801 +				            {
 17.1802 +				                lua_pushboolean(L, pressed);
 17.1803 +				                lua_setfield(L, -2, button_mappings[i]);
 17.1804 +							}
 17.1805 +						}
 17.1806 +
 17.1807 +				        return 1;
 17.1808 +					}
 17.1809 +
 17.1810 +// joypad.get(which)
 17.1811 +// returns a table of every game button,
 17.1812 +// true meaning currently-held and false meaning not-currently-held
 17.1813 +// (as of last frame boundary)
 17.1814 +// this WILL read input from a currently-playing movie
 17.1815 +				    static int joypad_get(lua_State *L)
 17.1816 +				    {
 17.1817 +				        return joy_get_internal(L, true, true);
 17.1818 +					}
 17.1819 +
 17.1820 +// joypad.getdown(which)
 17.1821 +// returns a table of every game button that is currently held
 17.1822 +				    static int joypad_getdown(lua_State *L)
 17.1823 +				    {
 17.1824 +				        return joy_get_internal(L, false, true);
 17.1825 +					}
 17.1826 +
 17.1827 +// joypad.getup(which)
 17.1828 +// returns a table of every game button that is not currently held
 17.1829 +				    static int joypad_getup(lua_State *L)
 17.1830 +				    {
 17.1831 +				        return joy_get_internal(L, true, false);
 17.1832 +					}
 17.1833 +
 17.1834 +// joypad.set(int which, table buttons)
 17.1835 +//
 17.1836 +//   Sets the given buttons to be pressed during the next
 17.1837 +//   frame advance. The table should have the right
 17.1838 +
 17.1839 +//   keys (no pun intended) set.
 17.1840 +				    static int joypad_set(lua_State *L)
 17.1841 +				    {
 17.1842 +				        // Which joypad we're tampering with
 17.1843 +				        int which = luaL_checkinteger(L, 1);
 17.1844 +				        if (which < 0 || which > 4)
 17.1845 +				        {
 17.1846 +				            luaL_error(L, "Invalid output port (valid range 0-4, specified %d)", which);
 17.1847 +						}
 17.1848 +
 17.1849 +				        if (which == 0)
 17.1850 +							which = systemGetDefaultJoypad();
 17.1851 +
 17.1852 +				        // And the table of buttons.
 17.1853 +				        luaL_checktype(L, 2, LUA_TTABLE);
 17.1854 +
 17.1855 +				        // Set up for taking control of the indicated controller
 17.1856 +				        lua_joypads_used	  |= 1 << (which - 1);
 17.1857 +				        lua_joypads[which - 1] = 0;
 17.1858 +
 17.1859 +				        for (int i = 0; i < 10; i++)
 17.1860 +				        {
 17.1861 +				            const char *name = button_mappings[i];
 17.1862 +				            lua_getfield(L, 2, name);
 17.1863 +				            if (!lua_isnil(L, -1))
 17.1864 +				            {
 17.1865 +				                bool pressed = lua_toboolean(L, -1) != 0;
 17.1866 +				                if (pressed)
 17.1867 +									lua_joypads[which - 1] |= 1 << i;
 17.1868 +				                else
 17.1869 +									lua_joypads[which - 1] &= ~(1 << i);
 17.1870 +							}
 17.1871 +				            lua_pop(L, 1);
 17.1872 +						}
 17.1873 +
 17.1874 +				        return 0;
 17.1875 +					}
 17.1876 +
 17.1877 +// Helper function to convert a savestate object to the filename it represents.
 17.1878 +				    static const char *savestateobj2filename(lua_State *L, int offset)
 17.1879 +				    {
 17.1880 +				        // First we get the metatable of the indicated object
 17.1881 +				        int result = lua_getmetatable(L, offset);
 17.1882 +
 17.1883 +				        if (!result)
 17.1884 +							luaL_error(L, "object not a savestate object");
 17.1885 +
 17.1886 +				        // Also check that the type entry is set
 17.1887 +				        lua_getfield(L, -1, "__metatable");
 17.1888 +				        if (strcmp(lua_tostring(L, -1), "vba Savestate") != 0)
 17.1889 +							luaL_error(L, "object not a savestate object");
 17.1890 +				        lua_pop(L, 1);
 17.1891 +
 17.1892 +				        // Now, get the field we want
 17.1893 +				        lua_getfield(L, -1, "filename");
 17.1894 +
 17.1895 +				        // Return it
 17.1896 +				        return lua_tostring(L, -1);
 17.1897 +					}
 17.1898 +
 17.1899 +// Helper function for garbage collection.
 17.1900 +				    static int savestate_gc(lua_State *L)
 17.1901 +				    {
 17.1902 +				        // The object we're collecting is on top of the stack
 17.1903 +				        lua_getmetatable(L, 1);
 17.1904 +
 17.1905 +				        // Get the filename
 17.1906 +				        const char *filename;
 17.1907 +				        lua_getfield(L, -1, "filename");
 17.1908 +				        filename = lua_tostring(L, -1);
 17.1909 +
 17.1910 +				        // Delete the file
 17.1911 +				        remove(filename);
 17.1912 +
 17.1913 +				        // We exit, and the garbage collector takes care of the rest.
 17.1914 +				        // Edit: Visual Studio needs a return value anyway, so returns 0.
 17.1915 +				        return 0;
 17.1916 +					}
 17.1917 +
 17.1918 +// object savestate.create(int which = nil)
 17.1919 +//
 17.1920 +//  Creates an object used for savestates.
 17.1921 +//  The object can be associated with a player-accessible savestate
 17.1922 +
 17.1923 +//  ("which" between 1 and 12) or not (which == nil).
 17.1924 +				    static int savestate_create(lua_State *L)
 17.1925 +				    {
 17.1926 +				        int which = -1;
 17.1927 +				        if (lua_gettop(L) >= 1)
 17.1928 +				        {
 17.1929 +				            which = luaL_checkinteger(L, 1);
 17.1930 +				            if (which < 1 || which > 12)
 17.1931 +				            {
 17.1932 +				                luaL_error(L, "invalid player's savestate %d", which);
 17.1933 +							}
 17.1934 +						}
 17.1935 +
 17.1936 +				        char stateName[2048];
 17.1937 +
 17.1938 +				        if (which > 0)
 17.1939 +				        {
 17.1940 +				            // Find an appropriate filename. This is OS specific, unfortunately.
 17.1941 +#if (defined(WIN32) && !defined(SDL))
 17.1942 +				            CString stateName = winGetSavestateFilename(theApp.gameFilename, which);
 17.1943 +#else
 17.1944 +				            extern char saveDir[2048];
 17.1945 +				            extern char filename[2048];
 17.1946 +				            extern char *sdlGetFilename(char *name);
 17.1947 +
 17.1948 +				            if (saveDir[0])
 17.1949 +								sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename), which);
 17.1950 +				            else
 17.1951 +								sprintf(stateName, "%s%d.sgm", filename, which);
 17.1952 +#endif
 17.1953 +						}
 17.1954 +				        else
 17.1955 +				        {
 17.1956 +				            char *stateNameTemp = tempnam(NULL, "snlua");
 17.1957 +				            strcpy(stateName, stateNameTemp);
 17.1958 +				            if (stateNameTemp)
 17.1959 +								free(stateNameTemp);
 17.1960 +						}
 17.1961 +
 17.1962 +				        // Our "object". We don't care about the type, we just need the memory and GC services.
 17.1963 +				        lua_newuserdata(L, 1);
 17.1964 +
 17.1965 +				        // The metatable we use, protected from Lua and contains garbage collection info and stuff.
 17.1966 +				        lua_newtable(L);
 17.1967 +
 17.1968 +				        // First, we must protect it
 17.1969 +				        lua_pushstring(L, "vba Savestate");
 17.1970 +				        lua_setfield(L, -2, "__metatable");
 17.1971 +
 17.1972 +				        // Now we need to save the file itself.
 17.1973 +				        lua_pushstring(L, stateName);
 17.1974 +				        lua_setfield(L, -2, "filename");
 17.1975 +
 17.1976 +				        // If it's an anonymous savestate, we must delete the file from disk should it be gargage collected
 17.1977 +				        if (which < 0)
 17.1978 +				        {
 17.1979 +				            lua_pushcfunction(L, savestate_gc);
 17.1980 +				            lua_setfield(L, -2, "__gc");
 17.1981 +						}
 17.1982 +
 17.1983 +				        // Set the metatable
 17.1984 +				        lua_setmetatable(L, -2);
 17.1985 +
 17.1986 +				        // Awesome. Return the object
 17.1987 +				        return 1;
 17.1988 +					}
 17.1989 +
 17.1990 +// savestate.save(object state)
 17.1991 +//
 17.1992 +
 17.1993 +//   Saves a state to the given object.
 17.1994 +				    static int savestate_save(lua_State *L)
 17.1995 +				    {
 17.1996 +				        const char *filename = savestateobj2filename(L, 1);
 17.1997 +
 17.1998 +				        //	printf("saving %s\n", filename);
 17.1999 +				        // Save states are very expensive. They take time.
 17.2000 +				        numTries--;
 17.2001 +
 17.2002 +				        bool8 retvalue = theEmulator.emuWriteState ? theEmulator.emuWriteState(filename) : false;
 17.2003 +				        if (!retvalue)
 17.2004 +				        {
 17.2005 +				            // Uh oh
 17.2006 +				            luaL_error(L, "savestate failed");
 17.2007 +						}
 17.2008 +
 17.2009 +				        return 0;
 17.2010 +					}
 17.2011 +
 17.2012 +// savestate.load(object state)
 17.2013 +//
 17.2014 +
 17.2015 +//   Loads the given state
 17.2016 +				    static int savestate_load(lua_State *L)
 17.2017 +				    {
 17.2018 +				        const char *filename = savestateobj2filename(L, 1);
 17.2019 +
 17.2020 +				        numTries--;
 17.2021 +
 17.2022 +				        //	printf("loading %s\n", filename);
 17.2023 +				        bool8 retvalue = theEmulator.emuReadState ? theEmulator.emuReadState(filename) : false;
 17.2024 +				        if (!retvalue)
 17.2025 +				        {
 17.2026 +				            // Uh oh
 17.2027 +				            luaL_error(L, "loadstate failed");
 17.2028 +						}
 17.2029 +
 17.2030 +				        return 0;
 17.2031 +					}
 17.2032 +
 17.2033 +// int vba.framecount()
 17.2034 +//
 17.2035 +
 17.2036 +//   Gets the frame counter for the movie, or the number of frames since last reset.
 17.2037 +				    int vba_framecount(lua_State *L)
 17.2038 +				    {
 17.2039 +				        if (!VBAMovieActive())
 17.2040 +				        {
 17.2041 +				            lua_pushinteger(L, systemCounters.frameCount);
 17.2042 +						}
 17.2043 +				        else
 17.2044 +				        {
 17.2045 +				            lua_pushinteger(L, VBAMovieGetFrameCounter());
 17.2046 +						}
 17.2047 +
 17.2048 +				        return 1;
 17.2049 +					}
 17.2050 +
 17.2051 +//string movie.getauthor
 17.2052 +//
 17.2053 +
 17.2054 +// returns author info field of .vbm file
 17.2055 +				    int movie_getauthor(lua_State *L)
 17.2056 +				    {
 17.2057 +				        if (!VBAMovieActive())
 17.2058 +				        {
 17.2059 +				            //lua_pushnil(L);
 17.2060 +				            lua_pushstring(L, "");
 17.2061 +				            return 1;
 17.2062 +						}
 17.2063 +
 17.2064 +				        lua_pushstring(L, VBAMovieGetAuthorInfo().c_str());
 17.2065 +				        return 1;
 17.2066 +					}
 17.2067 +
 17.2068 +//string movie.filename
 17.2069 +				    int movie_getfilename(lua_State *L)
 17.2070 +				    {
 17.2071 +				        if (!VBAMovieActive())
 17.2072 +				        {
 17.2073 +				            //lua_pushnil(L);
 17.2074 +				            lua_pushstring(L, "");
 17.2075 +				            return 1;
 17.2076 +						}
 17.2077 +
 17.2078 +				        lua_pushstring(L, VBAMovieGetFilename().c_str());
 17.2079 +				        return 1;
 17.2080 +					}
 17.2081 +
 17.2082 +// string movie.mode()
 17.2083 +//
 17.2084 +
 17.2085 +//   "record", "playback" or nil
 17.2086 +				    int movie_getmode(lua_State *L)
 17.2087 +				    {
 17.2088 +				        assert(!VBAMovieLoading());
 17.2089 +				        if (!VBAMovieActive())
 17.2090 +				        {
 17.2091 +				            lua_pushnil(L);
 17.2092 +				            return 1;
 17.2093 +						}
 17.2094 +
 17.2095 +				        if (VBAMovieRecording())
 17.2096 +							lua_pushstring(L, "record");
 17.2097 +				        else
 17.2098 +							lua_pushstring(L, "playback");
 17.2099 +				        return 1;
 17.2100 +					}
 17.2101 +
 17.2102 +				    static int movie_rerecordcount(lua_State *L)
 17.2103 +				    {
 17.2104 +				        if (VBAMovieActive())
 17.2105 +							lua_pushinteger(L, VBAMovieGetRerecordCount());
 17.2106 +				        else
 17.2107 +							lua_pushinteger(L, 0);
 17.2108 +				        return 1;
 17.2109 +					}
 17.2110 +
 17.2111 +				    static int movie_setrerecordcount(lua_State *L)
 17.2112 +				    {
 17.2113 +				        if (VBAMovieActive())
 17.2114 +							VBAMovieSetRerecordCount(luaL_checkinteger(L, 1));
 17.2115 +				        return 0;
 17.2116 +					}
 17.2117 +
 17.2118 +				    static int movie_rerecordcounting(lua_State *L)
 17.2119 +				    {
 17.2120 +				        if (lua_gettop(L) == 0)
 17.2121 +							luaL_error(L, "no parameters specified");
 17.2122 +
 17.2123 +				        skipRerecords = lua_toboolean(L, 1);
 17.2124 +				        return 0;
 17.2125 +					}
 17.2126 +
 17.2127 +// movie.stop()
 17.2128 +//
 17.2129 +
 17.2130 +//   Stops movie playback/recording. Bombs out if movie is not running.
 17.2131 +				    static int movie_stop(lua_State *L)
 17.2132 +				    {
 17.2133 +				        if (!VBAMovieActive())
 17.2134 +							luaL_error(L, "no movie");
 17.2135 +
 17.2136 +				        VBAMovieStop(false);
 17.2137 +				        return 0;
 17.2138 +					}
 17.2139 +
 17.2140 +#define LUA_SCREEN_WIDTH    256
 17.2141 +#define LUA_SCREEN_HEIGHT   239
 17.2142 +
 17.2143 +// Common code by the gui library: make sure the screen array is ready
 17.2144 +				    static void gui_prepare(void)
 17.2145 +				    {
 17.2146 +				        if (!gui_data)
 17.2147 +							gui_data = (uint8 *)malloc(LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4);
 17.2148 +				        if (!gui_used)
 17.2149 +							memset(gui_data, 0, LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4);
 17.2150 +				        gui_used = true;
 17.2151 +					}
 17.2152 +
 17.2153 +// pixform for lua graphics
 17.2154 +#define BUILD_PIXEL_ARGB8888(A, R, G, B)    (((int)(A) << 24) | ((int)(R) << 16) | ((int)(G) << 8) | (int)(B))
 17.2155 +#define DECOMPOSE_PIXEL_ARGB8888(PIX, A, R, G, B) \
 17.2156 +	{                                             \
 17.2157 +		(A) = ((PIX) >> 24) & 0xff;               \
 17.2158 +		(R) = ((PIX) >> 16) & 0xff;               \
 17.2159 +		(G) = ((PIX) >> 8) & 0xff;                \
 17.2160 +		(B) = (PIX) & 0xff;                       \
 17.2161 +	}
 17.2162 +#define LUA_BUILD_PIXEL     BUILD_PIXEL_ARGB8888
 17.2163 +#define LUA_DECOMPOSE_PIXEL DECOMPOSE_PIXEL_ARGB8888
 17.2164 +#define LUA_PIXEL_A(PIX) (((PIX) >> 24) & 0xff)
 17.2165 +#define LUA_PIXEL_R(PIX) (((PIX) >> 16) & 0xff)
 17.2166 +#define LUA_PIXEL_G(PIX) (((PIX) >> 8) & 0xff)
 17.2167 +#define LUA_PIXEL_B(PIX) ((PIX) & 0xff)
 17.2168 +
 17.2169 +				    template<class T>
 17.2170 +				    static void swap(T &one, T &two)
 17.2171 +				    {
 17.2172 +				        T temp = one;
 17.2173 +				        one = two;
 17.2174 +				        two = temp;
 17.2175 +					}
 17.2176 +
 17.2177 +// write a pixel to buffer
 17.2178 +				    static inline void blend32(uint32 *dstPixel, uint32 colour)
 17.2179 +				    {
 17.2180 +				        uint8 *dst = (uint8 *)dstPixel;
 17.2181 +				        int	   a, r, g, b;
 17.2182 +				        LUA_DECOMPOSE_PIXEL(colour, a, r, g, b);
 17.2183 +
 17.2184 +				        if (a == 255 || dst[3] == 0)
 17.2185 +				        {
 17.2186 +				            // direct copy
 17.2187 +				            *(uint32 *) (dst) = colour;
 17.2188 +						}
 17.2189 +				        else if (a == 0)
 17.2190 +				        {
 17.2191 +				            // do not copy
 17.2192 +						}
 17.2193 +				        else
 17.2194 +				        {
 17.2195 +				            // alpha-blending
 17.2196 +				            int a_dst = ((255 - a) * dst[3] + 128) / 255;
 17.2197 +				            int a_new = a + a_dst;
 17.2198 +
 17.2199 +				            dst[0] = (uint8) (((dst[0] * a_dst + b * a) + (a_new / 2)) / a_new);
 17.2200 +				            dst[1] = (uint8) (((dst[1] * a_dst + g * a) + (a_new / 2)) / a_new);
 17.2201 +				            dst[2] = (uint8) (((dst[2] * a_dst + r * a) + (a_new / 2)) / a_new);
 17.2202 +				            dst[3] = (uint8) a_new;
 17.2203 +						}
 17.2204 +					}
 17.2205 +
 17.2206 +// check if a pixel is in the lua canvas
 17.2207 +				    static inline bool gui_check_boundary(int x, int y)
 17.2208 +				    {
 17.2209 +				        return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT);
 17.2210 +					}
 17.2211 +
 17.2212 +// check if any part of a box is in the lua canvas
 17.2213 +				    static inline bool gui_checkbox(int x1, int y1, int x2, int y2)
 17.2214 +				    {
 17.2215 +				        if ((x1 <  0 && x2 <  0)
 17.2216 +				            || (x1 >= LUA_SCREEN_WIDTH && x2 >= LUA_SCREEN_WIDTH)
 17.2217 +				            || (y1 <  0 && y2 <  0)
 17.2218 +				            || (y1 >= LUA_SCREEN_HEIGHT && y2 >= LUA_SCREEN_HEIGHT))
 17.2219 +							return false;
 17.2220 +				        return true;
 17.2221 +					}
 17.2222 +
 17.2223 +// write a pixel to gui_data (do not check boundaries for speedup)
 17.2224 +				    static inline void gui_drawpixel_fast(int x, int y, uint32 colour)
 17.2225 +				    {
 17.2226 +				        //gui_prepare();
 17.2227 +				        blend32((uint32 *) &gui_data[(y * LUA_SCREEN_WIDTH + x) * 4], colour);
 17.2228 +					}
 17.2229 +
 17.2230 +// write a pixel to gui_data (check boundaries)
 17.2231 +				    static inline void gui_drawpixel_internal(int x, int y, uint32 colour)
 17.2232 +				    {
 17.2233 +				        //gui_prepare();
 17.2234 +				        if (gui_check_boundary(x, y))
 17.2235 +							gui_drawpixel_fast(x, y, colour);
 17.2236 +					}
 17.2237 +
 17.2238 +// draw a line on gui_data (checks boundaries)
 17.2239 +				    static void gui_drawline_internal(int x1, int y1, int x2, int y2, bool lastPixel, uint32 colour)
 17.2240 +				    {
 17.2241 +				        //gui_prepare();
 17.2242 +				        // Note: New version of Bresenham's Line Algorithm
 17.2243 +				        //
 17.2244 +				        //
 17.2245 +				        // http://groups.google.co.jp/group/rec.games.roguelike.development/browse_thread/thread/345f4c42c3b25858/29e07a3af3a450e6?show_docid=29e07a3af3a450e6
 17.2246 +				        int swappedx = 0;
 17.2247 +				        int swappedy = 0;
 17.2248 +
 17.2249 +				        int xtemp = x1 - x2;
 17.2250 +				        int ytemp = y1 - y2;
 17.2251 +				        if (xtemp == 0 && ytemp == 0)
 17.2252 +				        {
 17.2253 +				            gui_drawpixel_internal(x1, y1, colour);
 17.2254 +				            return;
 17.2255 +						}
 17.2256 +
 17.2257 +				        if (xtemp < 0)
 17.2258 +				        {
 17.2259 +				            xtemp	 = -xtemp;
 17.2260 +				            swappedx = 1;
 17.2261 +						}
 17.2262 +
 17.2263 +				        if (ytemp < 0)
 17.2264 +				        {
 17.2265 +				            ytemp	 = -ytemp;
 17.2266 +				            swappedy = 1;
 17.2267 +						}
 17.2268 +
 17.2269 +				        int delta_x = xtemp << 1;
 17.2270 +				        int delta_y = ytemp << 1;
 17.2271 +
 17.2272 +				        signed char ix = x1 > x2 ? 1 : -1;
 17.2273 +				        signed char iy = y1 > y2 ? 1 : -1;
 17.2274 +
 17.2275 +				        if (lastPixel)
 17.2276 +							gui_drawpixel_internal(x2, y2, colour);
 17.2277 +
 17.2278 +				        if (delta_x >= delta_y)
 17.2279 +				        {
 17.2280 +				            int error = delta_y - (delta_x >> 1);
 17.2281 +
 17.2282 +				            while (x2 != x1)
 17.2283 +				            {
 17.2284 +				                if (error == 0 && !swappedx)
 17.2285 +									gui_drawpixel_internal(x2 + ix, y2, colour);
 17.2286 +				                if (error >= 0)
 17.2287 +				                {
 17.2288 +				                    if (error || (ix > 0))
 17.2289 +				                    {
 17.2290 +				                        y2	  += iy;
 17.2291 +				                        error -= delta_x;
 17.2292 +									}
 17.2293 +								}
 17.2294 +
 17.2295 +				                x2 += ix;
 17.2296 +				                gui_drawpixel_internal(x2, y2, colour);
 17.2297 +				                if (error == 0 && swappedx)
 17.2298 +									gui_drawpixel_internal(x2, y2 + iy, colour);
 17.2299 +				                error += delta_y;
 17.2300 +							}
 17.2301 +						}
 17.2302 +				        else
 17.2303 +				        {
 17.2304 +				            int error = delta_x - (delta_y >> 1);
 17.2305 +
 17.2306 +				            while (y2 != y1)
 17.2307 +				            {
 17.2308 +				                if (error == 0 && !swappedy)
 17.2309 +									gui_drawpixel_internal(x2, y2 + iy, colour);
 17.2310 +				                if (error >= 0)
 17.2311 +				                {
 17.2312 +				                    if (error || (iy > 0))
 17.2313 +				                    {
 17.2314 +				                        x2	  += ix;
 17.2315 +				                        error -= delta_y;
 17.2316 +									}
 17.2317 +								}
 17.2318 +
 17.2319 +				                y2 += iy;
 17.2320 +				                gui_drawpixel_internal(x2, y2, colour);
 17.2321 +				                if (error == 0 && swappedy)
 17.2322 +									gui_drawpixel_internal(x2 + ix, y2, colour);
 17.2323 +				                error += delta_x;
 17.2324 +							}
 17.2325 +						}
 17.2326 +					}
 17.2327 +
 17.2328 +// draw a rect on gui_data
 17.2329 +				    static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
 17.2330 +				    {
 17.2331 +				        if (x1 > x2)
 17.2332 +							std::swap(x1, x2);
 17.2333 +				        if (y1 > y2)
 17.2334 +							std::swap(y1, y2);
 17.2335 +				        if (x1 < 0)
 17.2336 +							x1 = -1;
 17.2337 +				        if (y1 < 0)
 17.2338 +							y1 = -1;
 17.2339 +				        if (x2 >= LUA_SCREEN_WIDTH)
 17.2340 +							x2 = LUA_SCREEN_WIDTH;
 17.2341 +				        if (y2 >= LUA_SCREEN_HEIGHT)
 17.2342 +							y2 = LUA_SCREEN_HEIGHT;
 17.2343 +
 17.2344 +				        if (!gui_checkbox(x1, y1, x2, y2))
 17.2345 +							return;
 17.2346 +
 17.2347 +				        //gui_prepare();
 17.2348 +				        gui_drawline_internal(x1, y1, x2, y1, true, colour);
 17.2349 +				        gui_drawline_internal(x1, y2, x2, y2, true, colour);
 17.2350 +				        gui_drawline_internal(x1, y1, x1, y2, true, colour);
 17.2351 +				        gui_drawline_internal(x2, y1, x2, y2, true, colour);
 17.2352 +					}
 17.2353 +
 17.2354 +// draw a circle on gui_data
 17.2355 +				    static void gui_drawcircle_internal(int x0, int y0, int radius, uint32 colour)
 17.2356 +				    {
 17.2357 +				        //gui_prepare();
 17.2358 +				        if (radius < 0)
 17.2359 +							radius = -radius;
 17.2360 +				        if (radius == 0)
 17.2361 +							return;
 17.2362 +				        if (radius == 1)
 17.2363 +				        {
 17.2364 +				            gui_drawpixel_internal(x0, y0, colour);
 17.2365 +				            return;
 17.2366 +						}
 17.2367 +
 17.2368 +				        // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
 17.2369 +				        int f	  = 1 - radius;
 17.2370 +				        int ddF_x = 1;
 17.2371 +				        int ddF_y = -2 * radius;
 17.2372 +				        int x	  = 0;
 17.2373 +				        int y	  = radius;
 17.2374 +
 17.2375 +				        if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius))
 17.2376 +							return;
 17.2377 +
 17.2378 +				        gui_drawpixel_internal(x0, y0 + radius, colour);
 17.2379 +				        gui_drawpixel_internal(x0, y0 - radius, colour);
 17.2380 +				        gui_drawpixel_internal(x0 + radius, y0, colour);
 17.2381 +				        gui_drawpixel_internal(x0 - radius, y0, colour);
 17.2382 +
 17.2383 +				        // same pixel shouldn't be drawed twice,
 17.2384 +				        // because each pixel has opacity.
 17.2385 +				        // so now the routine gets ugly.
 17.2386 +				        while (true)
 17.2387 +				        {
 17.2388 +				            assert(ddF_x == 2 * x + 1);
 17.2389 +				            assert(ddF_y == -2 * y);
 17.2390 +				            assert(f == x * x + y * y - radius * radius + 2 * x - y + 1);
 17.2391 +				            if (f >= 0)
 17.2392 +				            {
 17.2393 +				                y--;
 17.2394 +				                ddF_y += 2;
 17.2395 +				                f	  += ddF_y;
 17.2396 +							}
 17.2397 +
 17.2398 +				            x++;
 17.2399 +				            ddF_x += 2;
 17.2400 +				            f	  += ddF_x;
 17.2401 +				            if (x < y)
 17.2402 +				            {
 17.2403 +				                gui_drawpixel_internal(x0 + x, y0 + y, colour);
 17.2404 +				                gui_drawpixel_internal(x0 - x, y0 + y, colour);
 17.2405 +				                gui_drawpixel_internal(x0 + x, y0 - y, colour);
 17.2406 +				                gui_drawpixel_internal(x0 - x, y0 - y, colour);
 17.2407 +				                gui_drawpixel_internal(x0 + y, y0 + x, colour);
 17.2408 +				                gui_drawpixel_internal(x0 - y, y0 + x, colour);
 17.2409 +				                gui_drawpixel_internal(x0 + y, y0 - x, colour);
 17.2410 +				                gui_drawpixel_internal(x0 - y, y0 - x, colour);
 17.2411 +							}
 17.2412 +				            else if (x == y)
 17.2413 +				            {
 17.2414 +				                gui_drawpixel_internal(x0 + x, y0 + y, colour);
 17.2415 +				                gui_drawpixel_internal(x0 - x, y0 + y, colour);
 17.2416 +				                gui_drawpixel_internal(x0 + x, y0 - y, colour);
 17.2417 +				                gui_drawpixel_internal(x0 - x, y0 - y, colour);
 17.2418 +				                break;
 17.2419 +							}
 17.2420 +				            else
 17.2421 +								break;
 17.2422 +						}
 17.2423 +					}
 17.2424 +
 17.2425 +// draw fill rect on gui_data
 17.2426 +				    static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
 17.2427 +				    {
 17.2428 +				        if (x1 > x2)
 17.2429 +							std::swap(x1, x2);
 17.2430 +				        if (y1 > y2)
 17.2431 +							std::swap(y1, y2);
 17.2432 +				        if (x1 < 0)
 17.2433 +							x1 = 0;
 17.2434 +				        if (y1 < 0)
 17.2435 +							y1 = 0;
 17.2436 +				        if (x2 >= LUA_SCREEN_WIDTH)
 17.2437 +							x2 = LUA_SCREEN_WIDTH - 1;
 17.2438 +				        if (y2 >= LUA_SCREEN_HEIGHT)
 17.2439 +							y2 = LUA_SCREEN_HEIGHT - 1;
 17.2440 +
 17.2441 +				        //gui_prepare();
 17.2442 +				        int ix, iy;
 17.2443 +				        for (iy = y1; iy <= y2; iy++)
 17.2444 +				        {
 17.2445 +				            for (ix = x1; ix <= x2; ix++)
 17.2446 +				            {
 17.2447 +				                gui_drawpixel_fast(ix, iy, colour);
 17.2448 +							}
 17.2449 +						}
 17.2450 +					}
 17.2451 +
 17.2452 +// fill a circle on gui_data
 17.2453 +				    static void gui_fillcircle_internal(int x0, int y0, int radius, uint32 colour)
 17.2454 +				    {
 17.2455 +				        //gui_prepare();
 17.2456 +				        if (radius < 0)
 17.2457 +							radius = -radius;
 17.2458 +				        if (radius == 0)
 17.2459 +							return;
 17.2460 +				        if (radius == 1)
 17.2461 +				        {
 17.2462 +				            gui_drawpixel_internal(x0, y0, colour);
 17.2463 +				            return;
 17.2464 +						}
 17.2465 +
 17.2466 +				        // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
 17.2467 +				        int f	  = 1 - radius;
 17.2468 +				        int ddF_x = 1;
 17.2469 +				        int ddF_y = -2 * radius;
 17.2470 +				        int x	  = 0;
 17.2471 +				        int y	  = radius;
 17.2472 +
 17.2473 +				        if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius))
 17.2474 +							return;
 17.2475 +
 17.2476 +				        gui_drawline_internal(x0, y0 - radius, x0, y0 + radius, true, colour);
 17.2477 +
 17.2478 +				        while (true)
 17.2479 +				        {
 17.2480 +				            assert(ddF_x == 2 * x + 1);
 17.2481 +				            assert(ddF_y == -2 * y);
 17.2482 +				            assert(f == x * x + y * y - radius * radius + 2 * x - y + 1);
 17.2483 +				            if (f >= 0)
 17.2484 +				            {
 17.2485 +				                y--;
 17.2486 +				                ddF_y += 2;
 17.2487 +				                f	  += ddF_y;
 17.2488 +							}
 17.2489 +
 17.2490 +				            x++;
 17.2491 +				            ddF_x += 2;
 17.2492 +				            f	  += ddF_x;
 17.2493 +
 17.2494 +				            if (x < y)
 17.2495 +				            {
 17.2496 +				                gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour);
 17.2497 +				                gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour);
 17.2498 +				                if (f >= 0)
 17.2499 +				                {
 17.2500 +				                    gui_drawline_internal(x0 + y, y0 - x, x0 + y, y0 + x, true, colour);
 17.2501 +				                    gui_drawline_internal(x0 - y, y0 - x, x0 - y, y0 + x, true, colour);
 17.2502 +								}
 17.2503 +							}
 17.2504 +				            else if (x == y)
 17.2505 +				            {
 17.2506 +				                gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour);
 17.2507 +				                gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour);
 17.2508 +				                break;
 17.2509 +							}
 17.2510 +				            else
 17.2511 +								break;
 17.2512 +						}
 17.2513 +					}
 17.2514 +
 17.2515 +// Helper for a simple hex parser
 17.2516 +				    static int hex2int(lua_State *L, char c)
 17.2517 +				    {
 17.2518 +				        if (c >= '0' && c <= '9')
 17.2519 +							return c - '0';
 17.2520 +				        if (c >= 'a' && c <= 'f')
 17.2521 +							return c - 'a' + 10;
 17.2522 +				        if (c >= 'A' && c <= 'F')
 17.2523 +							return c - 'A' + 10;
 17.2524 +				        return luaL_error(L, "invalid hex in colour");
 17.2525 +					}
 17.2526 +
 17.2527 +				    static const struct ColorMapping
 17.2528 +				    {
 17.2529 +				        const char *name;
 17.2530 +				        int			value;
 17.2531 +					}
 17.2532 +				    s_colorMapping[] =
 17.2533 +				    {
 17.2534 +				        { "white",		0xFFFFFFFF		  },
 17.2535 +				        { "black",		0x000000FF		  },
 17.2536 +				        { "clear",		0x00000000		  },
 17.2537 +				        { "gray",		0x7F7F7FFF		  },
 17.2538 +				        { "grey",		0x7F7F7FFF		  },
 17.2539 +				        { "red",		0xFF0000FF		  },
 17.2540 +				        { "orange",		0xFF7F00FF		  },
 17.2541 +				        { "yellow",		0xFFFF00FF		  },
 17.2542 +				        { "chartreuse", 0x7FFF00FF		  },
 17.2543 +				        { "green",		0x00FF00FF		  },
 17.2544 +				        { "teal",		0x00FF7FFF		  },
 17.2545 +				        { "cyan",		0x00FFFFFF		  },
 17.2546 +				        { "blue",		0x0000FFFF		  },
 17.2547 +				        { "purple",		0x7F00FFFF		  },
 17.2548 +				        { "magenta",	0xFF00FFFF		  },
 17.2549 +					};
 17.2550 +
 17.2551 +/**
 17.2552 + * Converts an integer or a string on the stack at the given
 17.2553 + * offset to a RGB32 colour. Several encodings are supported.
 17.2554 + * The user may construct their own RGB value, given a simple colour name,
 17.2555 + * or an HTML-style "#09abcd" colour. 16 bit reduction doesn't occur at this time.
 17.2556 + */
 17.2557 +				    static inline bool str2colour(uint32 *colour, lua_State *L, const char *str)
 17.2558 +				    {
 17.2559 +				        if (str[0] == '#')
 17.2560 +				        {
 17.2561 +				            int color;
 17.2562 +				            sscanf(str + 1, "%X", &color);
 17.2563 +
 17.2564 +				            int len		= strlen(str + 1);
 17.2565 +				            int missing = max(0, 8 - len);
 17.2566 +				            color <<= missing << 2;
 17.2567 +				            if (missing >= 2)
 17.2568 +								color |= 0xFF;
 17.2569 +				            *colour = color;
 17.2570 +				            return true;
 17.2571 +						}
 17.2572 +				        else
 17.2573 +				        {
 17.2574 +				            if (!strnicmp(str, "rand", 4))
 17.2575 +				            {
 17.2576 +				                *colour = gen_rand32() | 0xFF; //((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) |
 17.2577 +				                                               // ((rand()*255/RAND_MAX) << 24) | 0xFF;
 17.2578 +				                return true;
 17.2579 +							}
 17.2580 +
 17.2581 +				            for (int i = 0; i < sizeof(s_colorMapping) / sizeof(*s_colorMapping); i++)
 17.2582 +				            {
 17.2583 +				                if (!stricmp(str, s_colorMapping[i].name))
 17.2584 +				                {
 17.2585 +				                    *colour = s_colorMapping[i].value;
 17.2586 +				                    return true;
 17.2587 +								}
 17.2588 +							}
 17.2589 +						}
 17.2590 +
 17.2591 +				        return false;
 17.2592 +					}
 17.2593 +
 17.2594 +				    static inline uint32 gui_getcolour_wrapped(lua_State *L, int offset, bool hasDefaultValue, uint32 defaultColour)
 17.2595 +				    {
 17.2596 +				        switch (lua_type(L, offset))
 17.2597 +				        {
 17.2598 +						case LUA_TSTRING:
 17.2599 +							{
 17.2600 +							    const char *str = lua_tostring(L, offset);
 17.2601 +							    uint32		colour;
 17.2602 +
 17.2603 +							    if (str2colour(&colour, L, str))
 17.2604 +									return colour;
 17.2605 +							    else
 17.2606 +							    {
 17.2607 +							        if (hasDefaultValue)
 17.2608 +										return defaultColour;
 17.2609 +							        else
 17.2610 +										return luaL_error(L, "unknown colour %s", str);
 17.2611 +								}
 17.2612 +							}
 17.2613 +
 17.2614 +						case LUA_TNUMBER:
 17.2615 +							{
 17.2616 +							    uint32 colour = (uint32) lua_tointeger(L, offset);
 17.2617 +							    return colour;
 17.2618 +							}
 17.2619 +
 17.2620 +						case LUA_TTABLE:
 17.2621 +							{
 17.2622 +							    int color = 0xFF;
 17.2623 +							    lua_pushnil(L); // first key
 17.2624 +							    int	 keyIndex	= lua_gettop(L);
 17.2625 +							    int	 valueIndex = keyIndex + 1;
 17.2626 +							    bool first		= true;
 17.2627 +							    while (lua_next(L, offset))
 17.2628 +							    {
 17.2629 +							        bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
 17.2630 +							        bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
 17.2631 +							        int	 key		 = keyIsString ? tolower(*lua_tostring(L, keyIndex)) : (keyIsNumber ? lua_tointeger(L, keyIndex) : 0);
 17.2632 +							        int	 value		 = lua_tointeger(L, valueIndex);
 17.2633 +							        if (value < 0) value = 0;
 17.2634 +							        if (value > 255) value = 255;
 17.2635 +							        switch (key)
 17.2636 +							        {
 17.2637 +									case 1:
 17.2638 +									case 'r':
 17.2639 +										color |= value << 24; break;
 17.2640 +									case 2:
 17.2641 +									case 'g':
 17.2642 +										color |= value << 16; break;
 17.2643 +									case 3:
 17.2644 +									case 'b':
 17.2645 +										color |= value << 8; break;
 17.2646 +									case 4:
 17.2647 +									case 'a':
 17.2648 +										color = (color & ~0xFF) | value; break;
 17.2649 +									}
 17.2650 +							        lua_pop(L, 1);
 17.2651 +								}
 17.2652 +							    return color;
 17.2653 +							}   break;
 17.2654 +
 17.2655 +						case LUA_TFUNCTION:
 17.2656 +							luaL_error(L, "invalid colour"); // NYI
 17.2657 +							return 0;
 17.2658 +
 17.2659 +						default:
 17.2660 +							if (hasDefaultValue)
 17.2661 +								return defaultColour;
 17.2662 +							else
 17.2663 +								return luaL_error(L, "invalid colour");
 17.2664 +						}
 17.2665 +					}
 17.2666 +
 17.2667 +				    static uint32 gui_getcolour(lua_State *L, int offset)
 17.2668 +				    {
 17.2669 +				        uint32 colour;
 17.2670 +				        int	   a, r, g, b;
 17.2671 +
 17.2672 +				        colour = gui_getcolour_wrapped(L, offset, false, 0);
 17.2673 +				        a	   = ((colour & 0xff) * transparencyModifier) / 255;
 17.2674 +				        if (a > 255)
 17.2675 +							a = 255;
 17.2676 +				        b = (colour >> 8) & 0xff;
 17.2677 +				        g = (colour >> 16) & 0xff;
 17.2678 +				        r = (colour >> 24) & 0xff;
 17.2679 +				        return LUA_BUILD_PIXEL(a, r, g, b);
 17.2680 +					}
 17.2681 +
 17.2682 +				    static uint32 gui_optcolour(lua_State *L, int offset, uint32 defaultColour)
 17.2683 +				    {
 17.2684 +				        uint32 colour;
 17.2685 +				        int	   a, r, g, b;
 17.2686 +				        uint8  defA, defB, defG, defR;
 17.2687 +
 17.2688 +				        LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB);
 17.2689 +				        defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA;
 17.2690 +
 17.2691 +				        colour = gui_getcolour_wrapped(L, offset, true, defaultColour);
 17.2692 +				        a	   = ((colour & 0xff) * transparencyModifier) / 255;
 17.2693 +				        if (a > 255)
 17.2694 +							a = 255;
 17.2695 +				        b = (colour >> 8) & 0xff;
 17.2696 +				        g = (colour >> 16) & 0xff;
 17.2697 +				        r = (colour >> 24) & 0xff;
 17.2698 +				        return LUA_BUILD_PIXEL(a, r, g, b);
 17.2699 +					}
 17.2700 +
 17.2701 +// gui.drawpixel(x,y,colour)
 17.2702 +				    static int gui_drawpixel(lua_State *L)
 17.2703 +				    {
 17.2704 +				        int x = luaL_checkinteger(L, 1);
 17.2705 +				        int y = luaL_checkinteger(L, 2);
 17.2706 +
 17.2707 +				        uint32 colour = gui_getcolour(L, 3);
 17.2708 +
 17.2709 +				        //	if (!gui_check_boundary(x, y))
 17.2710 +				        //		luaL_error(L,"bad coordinates");
 17.2711 +				        gui_prepare();
 17.2712 +
 17.2713 +				        gui_drawpixel_internal(x, y, colour);
 17.2714 +
 17.2715 +				        return 0;
 17.2716 +					}
 17.2717 +
 17.2718 +// gui.drawline(x1,y1,x2,y2,color,skipFirst)
 17.2719 +				    static int gui_drawline(lua_State *L)
 17.2720 +				    {
 17.2721 +				        int	   x1, y1, x2, y2;
 17.2722 +				        uint32 color;
 17.2723 +				        x1	  = luaL_checkinteger(L, 1);
 17.2724 +				        y1	  = luaL_checkinteger(L, 2);
 17.2725 +				        x2	  = luaL_checkinteger(L, 3);
 17.2726 +				        y2	  = luaL_checkinteger(L, 4);
 17.2727 +				        color = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 255, 255, 255));
 17.2728 +				        int skipFirst = lua_toboolean(L, 6);
 17.2729 +
 17.2730 +				        gui_prepare();
 17.2731 +
 17.2732 +				        gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color);
 17.2733 +
 17.2734 +				        return 0;
 17.2735 +					}
 17.2736 +
 17.2737 +// gui.drawbox(x1, y1, x2, y2, fillcolor, outlinecolor)
 17.2738 +				    static int gui_drawbox(lua_State *L)
 17.2739 +				    {
 17.2740 +				        int	   x1, y1, x2, y2;
 17.2741 +				        uint32 fillcolor;
 17.2742 +				        uint32 outlinecolor;
 17.2743 +
 17.2744 +				        x1 = luaL_checkinteger(L, 1);
 17.2745 +				        y1 = luaL_checkinteger(L, 2);
 17.2746 +				        x2 = luaL_checkinteger(L, 3);
 17.2747 +				        y2 = luaL_checkinteger(L, 4);
 17.2748 +				        fillcolor	 = gui_optcolour(L, 5, LUA_BUILD_PIXEL(63, 255, 255, 255));
 17.2749 +				        outlinecolor = gui_optcolour(L, 6, LUA_BUILD_PIXEL(255, LUA_PIXEL_R(fillcolor), LUA_PIXEL_G(fillcolor), LUA_PIXEL_B(fillcolor)));
 17.2750 +
 17.2751 +				        if (x1 > x2)
 17.2752 +							std::swap(x1, x2);
 17.2753 +				        if (y1 > y2)
 17.2754 +							std::swap(y1, y2);
 17.2755 +
 17.2756 +				        gui_prepare();
 17.2757 +
 17.2758 +				        gui_drawbox_internal(x1, y1, x2, y2, outlinecolor);
 17.2759 +				        if ((x2 - x1) >= 2 && (y2 - y1) >= 2)
 17.2760 +							gui_fillbox_internal(x1 + 1, y1 + 1, x2 - 1, y2 - 1, fillcolor);
 17.2761 +
 17.2762 +				        return 0;
 17.2763 +					}
 17.2764 +
 17.2765 +// gui.drawcircle(x0, y0, radius, colour)
 17.2766 +				    static int gui_drawcircle(lua_State *L)
 17.2767 +				    {
 17.2768 +				        int	   x, y, r;
 17.2769 +				        uint32 colour;
 17.2770 +
 17.2771 +				        x	   = luaL_checkinteger(L, 1);
 17.2772 +				        y	   = luaL_checkinteger(L, 2);
 17.2773 +				        r	   = luaL_checkinteger(L, 3);
 17.2774 +				        colour = gui_getcolour(L, 4);
 17.2775 +
 17.2776 +				        gui_prepare();
 17.2777 +
 17.2778 +				        gui_drawcircle_internal(x, y, r, colour);
 17.2779 +
 17.2780 +				        return 0;
 17.2781 +					}
 17.2782 +
 17.2783 +// gui.fillbox(x1, y1, x2, y2, colour)
 17.2784 +				    static int gui_fillbox(lua_State *L)
 17.2785 +				    {
 17.2786 +				        int	   x1, y1, x2, y2;
 17.2787 +				        uint32 colour;
 17.2788 +
 17.2789 +				        x1	   = luaL_checkinteger(L, 1);
 17.2790 +				        y1	   = luaL_checkinteger(L, 2);
 17.2791 +				        x2	   = luaL_checkinteger(L, 3);
 17.2792 +				        y2	   = luaL_checkinteger(L, 4);
 17.2793 +				        colour = gui_getcolour(L, 5);
 17.2794 +
 17.2795 +				        //	if (!gui_check_boundary(x1, y1))
 17.2796 +				        //		luaL_error(L,"bad coordinates");
 17.2797 +				        //
 17.2798 +				        //	if (!gui_check_boundary(x2, y2))
 17.2799 +				        //		luaL_error(L,"bad coordinates");
 17.2800 +				        gui_prepare();
 17.2801 +
 17.2802 +				        if (!gui_checkbox(x1, y1, x2, y2))
 17.2803 +							return 0;
 17.2804 +
 17.2805 +				        gui_fillbox_internal(x1, y1, x2, y2, colour);
 17.2806 +
 17.2807 +				        return 0;
 17.2808 +					}
 17.2809 +
 17.2810 +// gui.fillcircle(x0, y0, radius, colour)
 17.2811 +				    static int gui_fillcircle(lua_State *L)
 17.2812 +				    {
 17.2813 +				        int	   x, y, r;
 17.2814 +				        uint32 colour;
 17.2815 +
 17.2816 +				        x	   = luaL_checkinteger(L, 1);
 17.2817 +				        y	   = luaL_checkinteger(L, 2);
 17.2818 +				        r	   = luaL_checkinteger(L, 3);
 17.2819 +				        colour = gui_getcolour(L, 4);
 17.2820 +
 17.2821 +				        gui_prepare();
 17.2822 +
 17.2823 +				        gui_fillcircle_internal(x, y, r, colour);
 17.2824 +
 17.2825 +				        return 0;
 17.2826 +					}
 17.2827 +
 17.2828 +				    static int gui_getpixel(lua_State *L)
 17.2829 +				    {
 17.2830 +				        int x = luaL_checkinteger(L, 1);
 17.2831 +				        int y = luaL_checkinteger(L, 2);
 17.2832 +
 17.2833 +				        int pixWidth   = 240, pixHeight = 160;
 17.2834 +				        int scrWidth   = 240, scrHeight = 160;
 17.2835 +				        int scrOffsetX = 0, scrOffsetY = 0;
 17.2836 +				        int pitch;
 17.2837 +				        if (!systemIsRunningGBA())
 17.2838 +				        {
 17.2839 +				            if (gbBorderOn)
 17.2840 +				            {
 17.2841 +				                pixWidth   = 256, pixHeight = 224;
 17.2842 +				                scrOffsetX = 48, scrOffsetY = 40;
 17.2843 +							}
 17.2844 +				            else
 17.2845 +				            {
 17.2846 +				                pixWidth = 160, pixHeight = 144;
 17.2847 +							}
 17.2848 +				            scrWidth = 160, scrHeight = 144;
 17.2849 +						}
 17.2850 +				        pitch = pixWidth * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
 17.2851 +				        scrOffsetY++; // don't know why it's needed
 17.2852 +
 17.2853 +				        if (!(x >= 0 && y >= 0 && x < scrWidth && y < scrHeight) /*!gui_check_boundary(x,y)*/)
 17.2854 +				        {
 17.2855 +				            lua_pushinteger(L, 0);
 17.2856 +				            lua_pushinteger(L, 0);
 17.2857 +				            lua_pushinteger(L, 0);
 17.2858 +						}
 17.2859 +				        else
 17.2860 +				        {
 17.2861 +				            switch (systemColorDepth)
 17.2862 +				            {
 17.2863 +							case 16:
 17.2864 +								{
 17.2865 +								    uint16 *screen	 = (uint16 *) (&pix[scrOffsetY * pitch + scrOffsetX * 2]);
 17.2866 +								    uint16	pixColor = screen[y * pitch / 2 + x];
 17.2867 +								    lua_pushinteger(L, (pixColor >> 8) & 0xF8); // red
 17.2868 +								    lua_pushinteger(L, (pixColor >> 3) & 0xFC); // green
 17.2869 +								    lua_pushinteger(L, (pixColor << 3) & 0xF8); // blue
 17.2870 +								}
 17.2871 +								break;
 17.2872 +							case 24:
 17.2873 +								{
 17.2874 +								    uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 3];
 17.2875 +								    lua_pushinteger(L, screen[y * pitch + x * 3 + 2]); // red
 17.2876 +								    lua_pushinteger(L, screen[y * pitch + x * 3 + 1]); // green
 17.2877 +								    lua_pushinteger(L, screen[y * pitch + x * 3 + 0]); // blue
 17.2878 +								}
 17.2879 +								break;
 17.2880 +							case 32:
 17.2881 +								{
 17.2882 +								    uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 4];
 17.2883 +								    lua_pushinteger(L, screen[y * pitch + x * 4 + 2]); // red
 17.2884 +								    lua_pushinteger(L, screen[y * pitch + x * 4 + 1]); // green
 17.2885 +								    lua_pushinteger(L, screen[y * pitch + x * 4 + 0]); // blue
 17.2886 +								}
 17.2887 +								break;
 17.2888 +							default:
 17.2889 +								lua_pushinteger(L, 0);
 17.2890 +								lua_pushinteger(L, 0);
 17.2891 +								lua_pushinteger(L, 0);
 17.2892 +								break;
 17.2893 +							}
 17.2894 +						}
 17.2895 +				        return 3;
 17.2896 +					}
 17.2897 +
 17.2898 +				    static int gui_parsecolor(lua_State *L)
 17.2899 +				    {
 17.2900 +				        int	   r, g, b, a;
 17.2901 +				        uint32 color = gui_getcolour(L, 1);
 17.2902 +				        LUA_DECOMPOSE_PIXEL(color, a, r, g, b);
 17.2903 +				        lua_pushinteger(L, r);
 17.2904 +				        lua_pushinteger(L, g);
 17.2905 +				        lua_pushinteger(L, b);
 17.2906 +				        lua_pushinteger(L, a);
 17.2907 +				        return 4;
 17.2908 +					}
 17.2909 +
 17.2910 +// gui.gdscreenshot()
 17.2911 +//
 17.2912 +//  Returns a screen shot as a string in gd's v1 file format.
 17.2913 +//  This allows us to make screen shots available without gd installed locally.
 17.2914 +//  Users can also just grab pixels via substring selection.
 17.2915 +//
 17.2916 +//  I think...  Does lua support grabbing byte values from a string? // yes, string.byte(str,offset)
 17.2917 +//  Well, either way, just install gd and do what you like with it.
 17.2918 +//  It really is easier that way.
 17.2919 +
 17.2920 +// example: gd.createFromGdStr(gui.gdscreenshot()):png("outputimage.png")
 17.2921 +				    static int gui_gdscreenshot(lua_State *L)
 17.2922 +				    {
 17.2923 +				        int xofs = 0, yofs = 0, ppl = 240, width = 240, height = 160;
 17.2924 +				        if (!systemIsRunningGBA())
 17.2925 +				        {
 17.2926 +				            if (gbBorderOn)
 17.2927 +								xofs = 48, yofs = 40, ppl = 256;
 17.2928 +				            else
 17.2929 +								ppl = 160;
 17.2930 +				            width = 160, height = 144;
 17.2931 +						}
 17.2932 +
 17.2933 +				        yofs++;
 17.2934 +
 17.2935 +				        //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3;
 17.2936 +				        int	   pitch  = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
 17.2937 +				        uint8 *screen = &pix[yofs * pitch + xofs * (systemColorDepth / 8)];
 17.2938 +
 17.2939 +				        int	  size = 11 + width * height * 4;
 17.2940 +				        char *str  = new char[size + 1];
 17.2941 +				        str[size] = 0;
 17.2942 +
 17.2943 +				        unsigned char *ptr = (unsigned char *)str;
 17.2944 +
 17.2945 +				        // GD format header for truecolor image (11 bytes)
 17.2946 +				        *ptr++ = (65534 >> 8) & 0xFF;
 17.2947 +				        *ptr++ = (65534) & 0xFF;
 17.2948 +				        *ptr++ = (width >> 8) & 0xFF;
 17.2949 +				        *ptr++ = (width) & 0xFF;
 17.2950 +				        *ptr++ = (height >> 8) & 0xFF;
 17.2951 +				        *ptr++ = (height) & 0xFF;
 17.2952 +				        *ptr++ = 1;
 17.2953 +				        *ptr++ = 255;
 17.2954 +				        *ptr++ = 255;
 17.2955 +				        *ptr++ = 255;
 17.2956 +				        *ptr++ = 255;
 17.2957 +
 17.2958 +				        GetColorFunc getColor;
 17.2959 +				        getColorIOFunc(systemColorDepth, &getColor, NULL);
 17.2960 +
 17.2961 +				        int x, y;
 17.2962 +				        for (y = 0; y < height; y++)
 17.2963 +				        {
 17.2964 +				            uint8 *s = &screen[y * pitch];
 17.2965 +				            for (x = 0; x < width; x++, s += systemColorDepth / 8)
 17.2966 +				            {
 17.2967 +				                uint8 r, g, b;
 17.2968 +				                getColor(s, &r, &g, &b);
 17.2969 +
 17.2970 +				                *ptr++ = 0;
 17.2971 +				                *ptr++ = r;
 17.2972 +				                *ptr++ = g;
 17.2973 +				                *ptr++ = b;
 17.2974 +							}
 17.2975 +						}
 17.2976 +
 17.2977 +				        lua_pushlstring(L, str, size);
 17.2978 +				        delete[] str;
 17.2979 +				        return 1;
 17.2980 +					}
 17.2981 +
 17.2982 +// gui.opacity(number alphaValue)
 17.2983 +// sets the transparency of subsequent draw calls
 17.2984 +// 0.0 is completely transparent, 1.0 is completely opaque
 17.2985 +// non-integer values are supported and meaningful, as are values greater than 1.0
 17.2986 +// it is not necessary to use this function to get transparency (or the less-recommended gui.transparency() either),
 17.2987 +// because you can provide an alpha value in the color argument of each draw call.
 17.2988 +
 17.2989 +// however, it can be convenient to be able to globally modify the drawing transparency
 17.2990 +				    static int gui_setopacity(lua_State *L)
 17.2991 +				    {
 17.2992 +				        double opacF = luaL_checknumber(L, 1);
 17.2993 +				        transparencyModifier = (int)(opacF * 255);
 17.2994 +				        if (transparencyModifier < 0)
 17.2995 +							transparencyModifier = 0;
 17.2996 +				        return 0;
 17.2997 +					}
 17.2998 +
 17.2999 +// gui.transparency(int strength)
 17.3000 +//
 17.3001 +
 17.3002 +//  0 = solid,
 17.3003 +				    static int gui_transparency(lua_State *L)
 17.3004 +				    {
 17.3005 +				        double trans = luaL_checknumber(L, 1);
 17.3006 +				        transparencyModifier = (int)((4.0 - trans) / 4.0 * 255);
 17.3007 +				        if (transparencyModifier < 0)
 17.3008 +							transparencyModifier = 0;
 17.3009 +				        return 0;
 17.3010 +					}
 17.3011 +
 17.3012 +				    static const uint32 Small_Font_Data[] =
 17.3013 +				    {
 17.3014 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 32
 17.3015 +				        0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 33	!
 17.3016 +				        0x00000000, 0x00040002, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 34	"
 17.3017 +				        0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 35	#
 17.3018 +				        0x00000000, 0x00040300, 0x00000403, 0x00000500, 0x00070600, 0x00000706, 0x00000000, // 36	$
 17.3019 +				        0x00000000, 0x00000002, 0x00050000, 0x00000500, 0x00000005, 0x00080000, 0x00000000, // 37	%
 17.3020 +				        0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00080700, 0x00000000, // 38	&
 17.3021 +				        0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 39	'
 17.3022 +				        0x00000000, 0x00000300, 0x00000003, 0x00000004, 0x00000005, 0x00000700, 0x00000000, // 40	(
 17.3023 +				        0x00000000, 0x00000300, 0x00050000, 0x00060000, 0x00070000, 0x00000700, 0x00000000, // 41	)
 17.3024 +				        0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00080006, 0x00000000, // 42	*
 17.3025 +				        0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00000000, 0x00000000, // 43	+
 17.3026 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00000700, 0x00000007, // 44	,
 17.3027 +				        0x00000000, 0x00000000, 0x00000000, 0x00060504, 0x00000000, 0x00000000, 0x00000000, // 45	-
 17.3028 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 46	.
 17.3029 +				        0x00030000, 0x00040000, 0x00000400, 0x00000500, 0x00000005, 0x00000006, 0x00000000, // 47	/
 17.3030 +				        0x00000000, 0x00000300, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 48	0
 17.3031 +				        0x00000000, 0x00000300, 0x00000403, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 49	1
 17.3032 +				        0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 50	2
 17.3033 +				        0x00000000, 0x00000302, 0x00050000, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 51	3
 17.3034 +				        0x00000000, 0x00000300, 0x00000003, 0x00060004, 0x00070605, 0x00080000, 0x00000000, // 52	4
 17.3035 +				        0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 53	5
 17.3036 +				        0x00000000, 0x00000300, 0x00000003, 0x00000504, 0x00070005, 0x00000700, 0x00000000, // 54	6
 17.3037 +				        0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 55	7
 17.3038 +				        0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00000700, 0x00000000, // 56	8
 17.3039 +				        0x00000000, 0x00000300, 0x00050003, 0x00060500, 0x00070000, 0x00000700, 0x00000000, // 57	9
 17.3040 +				        0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 58	:
 17.3041 +				        0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000700, 0x00000007, // 59	;
 17.3042 +				        0x00000000, 0x00040000, 0x00000400, 0x00000004, 0x00000600, 0x00080000, 0x00000000, // 60	<
 17.3043 +				        0x00000000, 0x00000000, 0x00050403, 0x00000000, 0x00070605, 0x00000000, 0x00000000, // 61	=
 17.3044 +				        0x00000000, 0x00000002, 0x00000400, 0x00060000, 0x00000600, 0x00000006, 0x00000000, // 62	>
 17.3045 +				        0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 63	?
 17.3046 +				        0x00000000, 0x00000300, 0x00050400, 0x00060004, 0x00070600, 0x00000000, 0x00000000, // 64	@
 17.3047 +				        0x00000000, 0x00000300, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 65	A
 17.3048 +				        0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 66	B
 17.3049 +				        0x00000000, 0x00040300, 0x00000003, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 67	C
 17.3050 +				        0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00000706, 0x00000000, // 68	D
 17.3051 +				        0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00080706, 0x00000000, // 69	E
 17.3052 +				        0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 70	F
 17.3053 +				        0x00000000, 0x00040300, 0x00000003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 71	G
 17.3054 +				        0x00000000, 0x00040002, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 72	H
 17.3055 +				        0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 73	I
 17.3056 +				        0x00000000, 0x00040000, 0x00050000, 0x00060000, 0x00070005, 0x00000700, 0x00000000, // 74	J
 17.3057 +				        0x00000000, 0x00040002, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 75	K
 17.3058 +				        0x00000000, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00080706, 0x00000000, // 76	l
 17.3059 +				        0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 77	M
 17.3060 +				        0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 78	N
 17.3061 +				        0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 79	O
 17.3062 +				        0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 80	P
 17.3063 +				        0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00090000, // 81	Q
 17.3064 +				        0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 82	R
 17.3065 +				        0x00000000, 0x00040300, 0x00000003, 0x00000500, 0x00070000, 0x00000706, 0x00000000, // 83	S
 17.3066 +				        0x00000000, 0x00040302, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 84	T
 17.3067 +				        0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 85	U
 17.3068 +				        0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000000, // 86	V
 17.3069 +				        0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 87	W
 17.3070 +				        0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 88	X
 17.3071 +				        0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 89	Y
 17.3072 +				        0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 90	Z
 17.3073 +				        0x00000000, 0x00040300, 0x00000400, 0x00000500, 0x00000600, 0x00080700, 0x00000000, // 91	[
 17.3074 +				        0x00000000, 0x00000002, 0x00000400, 0x00000500, 0x00070000, 0x00080000, 0x00000000, // 92	'\'
 17.3075 +				        0x00000000, 0x00000302, 0x00000400, 0x00000500, 0x00000600, 0x00000706, 0x00000000, // 93	]
 17.3076 +				        0x00000000, 0x00000300, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 94	^
 17.3077 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080706, 0x00000000, // 95	_
 17.3078 +				        0x00000000, 0x00000002, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 96	`
 17.3079 +				        0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 97	a
 17.3080 +				        0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 98	b
 17.3081 +				        0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 99	c
 17.3082 +				        0x00000000, 0x00040000, 0x00050000, 0x00060500, 0x00070005, 0x00080700, 0x00000000, // 100	d
 17.3083 +				        0x00000000, 0x00000000, 0x00050400, 0x00060504, 0x00000005, 0x00080700, 0x00000000, // 101	e
 17.3084 +				        0x00000000, 0x00040300, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 102	f
 17.3085 +				        0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070600, 0x00080000, 0x00000807, // 103	g
 17.3086 +				        0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 104	h
 17.3087 +				        0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 105	i
 17.3088 +				        0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000007, // 106	j
 17.3089 +				        0x00000000, 0x00000002, 0x00000003, 0x00060004, 0x00000605, 0x00080006, 0x00000000, // 107	k
 17.3090 +				        0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 108	l
 17.3091 +				        0x00000000, 0x00000000, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 109	m
 17.3092 +				        0x00000000, 0x00000000, 0x00000403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 110	n
 17.3093 +				        0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 111	o
 17.3094 +				        0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00000605, 0x00000006, 0x00000007, // 112	p
 17.3095 +				        0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070600, 0x00080000, 0x00090000, // 113	q
 17.3096 +				        0x00000000, 0x00000000, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 114	r
 17.3097 +				        0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00070600, 0x00000706, 0x00000000, // 115	s
 17.3098 +				        0x00000000, 0x00000300, 0x00050403, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 116	t
 17.3099 +				        0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 117	u
 17.3100 +				        0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 118	v
 17.3101 +				        0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 119	w
 17.3102 +				        0x00000000, 0x00000000, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 120	x
 17.3103 +				        0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000007, // 121	y
 17.3104 +				        0x00000000, 0x00000000, 0x00050403, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 122	z
 17.3105 +				        0x00000000, 0x00040300, 0x00000400, 0x00000504, 0x00000600, 0x00080700, 0x00000000, // 123	{
 17.3106 +				        0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000600, 0x00000700, 0x00000000, // 124	|
 17.3107 +				        0x00000000, 0x00000302, 0x00000400, 0x00060500, 0x00000600, 0x00000706, 0x00000000, // 125	}
 17.3108 +				        0x00000000, 0x00000302, 0x00050000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 126	~
 17.3109 +				        0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070605, 0x00000000, 0x00000000, // 127	
 17.3110 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
 17.3111 +					};
 17.3112 +
 17.3113 +				    static void PutTextInternal(const char *str, int len, short x, short y, int color, int backcolor)
 17.3114 +				    {
 17.3115 +				        int Opac	 = (color >> 24) & 0xFF;
 17.3116 +				        int backOpac = (backcolor >> 24) & 0xFF;
 17.3117 +				        int origX	 = x;
 17.3118 +
 17.3119 +				        if (!Opac && !backOpac)
 17.3120 +							return;
 17.3121 +
 17.3122 +				        while (*str && len && y < LUA_SCREEN_HEIGHT)
 17.3123 +				        {
 17.3124 +				            int c = *str++;
 17.3125 +				            while (x > LUA_SCREEN_WIDTH && c != '\n')
 17.3126 +				            {
 17.3127 +				                c = *str;
 17.3128 +				                if (c == '\0')
 17.3129 +									break;
 17.3130 +				                str++;
 17.3131 +							}
 17.3132 +
 17.3133 +				            if (c == '\n')
 17.3134 +				            {
 17.3135 +				                x  = origX;
 17.3136 +				                y += 8;
 17.3137 +				                continue;
 17.3138 +							}
 17.3139 +				            else if (c == '\t') // just in case
 17.3140 +				            {
 17.3141 +				                const int tabSpace = 8;
 17.3142 +				                x += (tabSpace - (((x - origX) / 4) % tabSpace)) * 4;
 17.3143 +				                continue;
 17.3144 +							}
 17.3145 +
 17.3146 +				            if ((unsigned int)(c - 32) >= 96)
 17.3147 +								continue;
 17.3148 +
 17.3149 +				            const unsigned char *Cur_Glyph = (const unsigned char *) &Small_Font_Data + (c - 32) * 7 * 4;
 17.3150 +
 17.3151 +				            for (int y2 = 0; y2 < 8; y2++)
 17.3152 +				            {
 17.3153 +				                unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y2);
 17.3154 +				                for (int x2 = -1; x2 < 4; x2++)
 17.3155 +				                {
 17.3156 +				                    int shift	  = x2 << 3;
 17.3157 +				                    int mask	  = 0xFF << shift;
 17.3158 +				                    int intensity = (glyphLine & mask) >> shift;
 17.3159 +
 17.3160 +				                    if (intensity && x2 >= 0 && y2 < 7)
 17.3161 +				                    {
 17.3162 +				                        //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2));
 17.3163 +				                        //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2));
 17.3164 +				                        //gui_drawpixel_fast(xdraw, ydraw, color);
 17.3165 +				                        gui_drawpixel_internal(x + x2, y + y2, color);
 17.3166 +									}
 17.3167 +				                    else if (backOpac)
 17.3168 +				                    {
 17.3169 +				                        for (int y3 = max(0, y2 - 1); y3 <= min(6, y2 + 1); y3++)
 17.3170 +				                        {
 17.3171 +				                            unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y3);
 17.3172 +				                            for (int x3 = max(0, x2 - 1); x3 <= min(3, x2 + 1); x3++)
 17.3173 +				                            {
 17.3174 +				                                int shift = x3 << 3;
 17.3175 +				                                int mask  = 0xFF << shift;
 17.3176 +				                                intensity |= (glyphLine & mask) >> shift;
 17.3177 +				                                if (intensity)
 17.3178 +													goto draw_outline;  // speedup?
 17.3179 +											}
 17.3180 +										}
 17.3181 +
 17.3182 +draw_outline:
 17.3183 +				                        if (intensity)
 17.3184 +				                        {
 17.3185 +				                            //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2));
 17.3186 +				                            //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2));
 17.3187 +				                            //gui_drawpixel_fast(xdraw, ydraw, backcolor);
 17.3188 +				                            gui_drawpixel_internal(x + x2, y + y2, backcolor);
 17.3189 +										}
 17.3190 +									}
 17.3191 +								}
 17.3192 +							}
 17.3193 +
 17.3194 +				            x += 4;
 17.3195 +				            len--;
 17.3196 +						}
 17.3197 +					}
 17.3198 +
 17.3199 +				    static int strlinelen(const char *string)
 17.3200 +				    {
 17.3201 +				        const char *s = string;
 17.3202 +				        while (*s && *s != '\n')
 17.3203 +							s++;
 17.3204 +				        if (*s)
 17.3205 +							s++;
 17.3206 +				        return s - string;
 17.3207 +					}
 17.3208 +
 17.3209 +				    static void LuaDisplayString(const char *string, int y, int x, uint32 color, uint32 outlineColor)
 17.3210 +				    {
 17.3211 +				        if (!string)
 17.3212 +							return;
 17.3213 +
 17.3214 +				        gui_prepare();
 17.3215 +
 17.3216 +				        PutTextInternal(string, strlen(string), x, y, color, outlineColor);
 17.3217 +
 17.3218 +				        /*
 17.3219 +				           const char* ptr = string;
 17.3220 +				           while(*ptr && y < LUA_SCREEN_HEIGHT)
 17.3221 +				           {
 17.3222 +				            int len = strlinelen(ptr);
 17.3223 +				            int skip = 0;
 17.3224 +				            if(len < 1) len = 1;
 17.3225 +
 17.3226 +				            // break up the line if it's too long to display otherwise
 17.3227 +				            if(len > 63)
 17.3228 +				            {
 17.3229 +				                len = 63;
 17.3230 +				                const char* ptr2 = ptr + len-1;
 17.3231 +				                for(int j = len-1; j; j--, ptr2--)
 17.3232 +				                {
 17.3233 +				                    if(*ptr2 == ' ' || *ptr2 == '\t')
 17.3234 +				                    {
 17.3235 +				                        len = j;
 17.3236 +				                        skip = 1;
 17.3237 +				                        break;
 17.3238 +				                    }
 17.3239 +				                }
 17.3240 +				            }
 17.3241 +
 17.3242 +				            int xl = 0;
 17.3243 +				            int yl = 0;
 17.3244 +				            int xh = (LUA_SCREEN_WIDTH - 1 - 1) - 4*len;
 17.3245 +				            int yh = LUA_SCREEN_HEIGHT - 1;
 17.3246 +				            int x2 = min(max(x,xl),xh);
 17.3247 +				            int y2 = min(max(y,yl),yh);
 17.3248 +
 17.3249 +				            PutTextInternal(ptr,len,x2,y2,color,outlineColor);
 17.3250 +
 17.3251 +				            ptr += len + skip;
 17.3252 +				            y += 8;
 17.3253 +				           }
 17.3254 +				         */
 17.3255 +					}
 17.3256 +
 17.3257 +// gui.text(int x, int y, string msg)
 17.3258 +//
 17.3259 +//  Displays the given text on the screen, using the same font and techniques as the
 17.3260 +
 17.3261 +//  main HUD.
 17.3262 +				    static int gui_text(lua_State *L)
 17.3263 +				    {
 17.3264 +				        //extern int font_height;
 17.3265 +				        const char *msg;
 17.3266 +				        int			x, y;
 17.3267 +				        uint32		colour, borderColour;
 17.3268 +
 17.3269 +				        x = luaL_checkinteger(L, 1);
 17.3270 +				        y = luaL_checkinteger(L, 2);
 17.3271 +				        //msg = luaL_checkstring(L, 3);
 17.3272 +				        msg = toCString(L, 3);
 17.3273 +
 17.3274 +				        //	if (x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= (LUA_SCREEN_HEIGHT - font_height))
 17.3275 +				        //		luaL_error(L,"bad coordinates");
 17.3276 +				        colour		 = gui_optcolour(L, 4, LUA_BUILD_PIXEL(255, 255, 255, 255));
 17.3277 +				        borderColour = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 0, 0, 0));
 17.3278 +
 17.3279 +				        gui_prepare();
 17.3280 +
 17.3281 +				        LuaDisplayString(msg, y, x, colour, borderColour);
 17.3282 +
 17.3283 +				        return 0;
 17.3284 +					}
 17.3285 +
 17.3286 +// gui.gdoverlay([int dx=0, int dy=0,] string str [, sx=0, sy=0, sw, sh] [, float alphamul=1.0])
 17.3287 +//
 17.3288 +//  Overlays the given image on the screen.
 17.3289 +
 17.3290 +// example: gui.gdoverlay(gd.createFromPng("myimage.png"):gdStr())
 17.3291 +				    static int gui_gdoverlay(lua_State *L)
 17.3292 +				    {
 17.3293 +				        int argCount = lua_gettop(L);
 17.3294 +
 17.3295 +				        int xStartDst = 0;
 17.3296 +				        int yStartDst = 0;
 17.3297 +				        int xStartSrc = 0;
 17.3298 +				        int yStartSrc = 0;
 17.3299 +
 17.3300 +				        int index = 1;
 17.3301 +				        if (lua_type(L, index) == LUA_TNUMBER)
 17.3302 +				        {
 17.3303 +				            xStartDst = lua_tointeger(L, index++);
 17.3304 +				            if (lua_type(L, index) == LUA_TNUMBER)
 17.3305 +								yStartDst = lua_tointeger(L, index++);
 17.3306 +						}
 17.3307 +
 17.3308 +				        luaL_checktype(L, index, LUA_TSTRING);
 17.3309 +
 17.3310 +				        const unsigned char *ptr = (const unsigned char *)lua_tostring(L, index++);
 17.3311 +
 17.3312 +				        if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255))
 17.3313 +							luaL_error(L, "bad image data");
 17.3314 +
 17.3315 +				        bool trueColor = (ptr[1] == 254);
 17.3316 +				        ptr += 2;
 17.3317 +
 17.3318 +				        int imgwidth = *ptr++ << 8;
 17.3319 +				        imgwidth |= *ptr++;
 17.3320 +
 17.3321 +				        int width	  = imgwidth;
 17.3322 +				        int imgheight = *ptr++ << 8;
 17.3323 +				        imgheight |= *ptr++;
 17.3324 +
 17.3325 +				        int height = imgheight;
 17.3326 +				        if ((!trueColor && *ptr) || (trueColor && !*ptr))
 17.3327 +							luaL_error(L, "bad image data");
 17.3328 +				        ptr++;
 17.3329 +
 17.3330 +				        int pitch = imgwidth * (trueColor ? 4 : 1);
 17.3331 +
 17.3332 +				        if ((argCount - index + 1) >= 4)
 17.3333 +				        {
 17.3334 +				            xStartSrc = luaL_checkinteger(L, index++);
 17.3335 +				            yStartSrc = luaL_checkinteger(L, index++);
 17.3336 +				            width	  = luaL_checkinteger(L, index++);
 17.3337 +				            height	  = luaL_checkinteger(L, index++);
 17.3338 +						}
 17.3339 +
 17.3340 +				        int alphaMul = transparencyModifier;
 17.3341 +				        if (lua_isnumber(L, index))
 17.3342 +							alphaMul = (int)(alphaMul * lua_tonumber(L, index++));
 17.3343 +				        if (alphaMul <= 0)
 17.3344 +							return 0;
 17.3345 +
 17.3346 +				        // since there aren't that many possible opacity levels,
 17.3347 +				        // do the opacity modification calculations beforehand instead of per pixel
 17.3348 +				        int opacMap[256];
 17.3349 +				        for (int i = 0; i < 128; i++)
 17.3350 +				        {
 17.3351 +				            int opac = 255 - ((i << 1) | (i & 1)); // gdAlphaMax = 127, not 255
 17.3352 +				            opac = (opac * alphaMul) / 255;
 17.3353 +				            if (opac < 0)
 17.3354 +								opac = 0;
 17.3355 +				            if (opac > 255)
 17.3356 +								opac = 255;
 17.3357 +				            opacMap[i] = opac;
 17.3358 +						}
 17.3359 +
 17.3360 +				        for (int i = 128; i < 256; i++)
 17.3361 +							opacMap[i] = 0;  // what should we do for them, actually?
 17.3362 +				        int colorsTotal = 0;
 17.3363 +				        if (!trueColor)
 17.3364 +				        {
 17.3365 +				            colorsTotal	 = *ptr++ << 8;
 17.3366 +				            colorsTotal |= *ptr++;
 17.3367 +						}
 17.3368 +
 17.3369 +				        int transparent = *ptr++ << 24;
 17.3370 +				        transparent |= *ptr++ << 16;
 17.3371 +				        transparent |= *ptr++ << 8;
 17.3372 +				        transparent |= *ptr++;
 17.3373 +				        struct
 17.3374 +				        {
 17.3375 +				            uint8 r, g, b, a;
 17.3376 +						} pal[256];
 17.3377 +				        if (!trueColor)
 17.3378 +							for (int i = 0; i < 256; i++)
 17.3379 +							{
 17.3380 +							    pal[i].r = *ptr++;
 17.3381 +							    pal[i].g = *ptr++;
 17.3382 +							    pal[i].b = *ptr++;
 17.3383 +							    pal[i].a = opacMap[*ptr++];
 17.3384 +							}
 17.3385 +
 17.3386 +				        // some of clippings
 17.3387 +				        if (xStartSrc < 0)
 17.3388 +				        {
 17.3389 +				            width	  += xStartSrc;
 17.3390 +				            xStartDst -= xStartSrc;
 17.3391 +				            xStartSrc  = 0;
 17.3392 +						}
 17.3393 +
 17.3394 +				        if (yStartSrc < 0)
 17.3395 +				        {
 17.3396 +				            height	  += yStartSrc;
 17.3397 +				            yStartDst -= yStartSrc;
 17.3398 +				            yStartSrc  = 0;
 17.3399 +						}
 17.3400 +
 17.3401 +				        if (xStartSrc + width >= imgwidth)
 17.3402 +							width = imgwidth - xStartSrc;
 17.3403 +				        if (yStartSrc + height >= imgheight)
 17.3404 +							height = imgheight - yStartSrc;
 17.3405 +				        if (xStartDst < 0)
 17.3406 +				        {
 17.3407 +				            width += xStartDst;
 17.3408 +				            if (width <= 0)
 17.3409 +								return 0;
 17.3410 +				            xStartSrc = -xStartDst;
 17.3411 +				            xStartDst = 0;
 17.3412 +						}
 17.3413 +
 17.3414 +				        if (yStartDst < 0)
 17.3415 +				        {
 17.3416 +				            height += yStartDst;
 17.3417 +				            if (height <= 0)
 17.3418 +								return 0;
 17.3419 +				            yStartSrc = -yStartDst;
 17.3420 +				            yStartDst = 0;
 17.3421 +						}
 17.3422 +
 17.3423 +				        if (xStartDst + width >= LUA_SCREEN_WIDTH)
 17.3424 +							width = LUA_SCREEN_WIDTH - xStartDst;
 17.3425 +				        if (yStartDst + height >= LUA_SCREEN_HEIGHT)
 17.3426 +							height = LUA_SCREEN_HEIGHT - yStartDst;
 17.3427 +				        if (width <= 0 || height <= 0)
 17.3428 +							return 0;  // out of screen or invalid size
 17.3429 +				        gui_prepare();
 17.3430 +
 17.3431 +				        const uint8 *pix = (const uint8 *)(&ptr[yStartSrc * pitch + (xStartSrc * (trueColor ? 4 : 1))]);
 17.3432 +				        int			 bytesToNextLine = pitch - (width * (trueColor ? 4 : 1));
 17.3433 +				        if (trueColor)
 17.3434 +				        {
 17.3435 +				            for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine)
 17.3436 +				            {
 17.3437 +				                for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4)
 17.3438 +				                {
 17.3439 +				                    gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3]));
 17.3440 +								}
 17.3441 +							}
 17.3442 +						}
 17.3443 +				        else
 17.3444 +				        {
 17.3445 +				            for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine)
 17.3446 +				            {
 17.3447 +				                for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++)
 17.3448 +				                {
 17.3449 +				                    gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b));
 17.3450 +								}
 17.3451 +							}
 17.3452 +						}
 17.3453 +
 17.3454 +				        return 0;
 17.3455 +					}
 17.3456 +
 17.3457 +// function gui.register(function f)
 17.3458 +//
 17.3459 +//  This function will be called just before a graphical update.
 17.3460 +//  More complicated, but doesn't suffer any frame delays.
 17.3461 +//  Nil will be accepted in place of a function to erase
 17.3462 +//  a previously registered function, and the previous function
 17.3463 +
 17.3464 +//  (if any) is returned, or nil if none.
 17.3465 +				    static int gui_register(lua_State *L)
 17.3466 +				    {
 17.3467 +				        // We'll do this straight up.
 17.3468 +				        // First set up the stack.
 17.3469 +				        lua_settop(L, 1);
 17.3470 +
 17.3471 +				        // Verify the validity of the entry
 17.3472 +				        if (!lua_isnil(L, 1))
 17.3473 +							luaL_checktype(L, 1, LUA_TFUNCTION);
 17.3474 +
 17.3475 +				        // Get the old value
 17.3476 +				        lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
 17.3477 +
 17.3478 +				        // Save the new value
 17.3479 +				        lua_pushvalue(L, 1);
 17.3480 +				        lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
 17.3481 +
 17.3482 +				        // The old value is on top of the stack. Return it.
 17.3483 +				        return 1;
 17.3484 +					}
 17.3485 +
 17.3486 +// string gui.popup(string message, [string type = "ok"])
 17.3487 +//
 17.3488 +
 17.3489 +//  Popup dialog!
 17.3490 +				    int gui_popup(lua_State *L)
 17.3491 +				    {
 17.3492 +				        const char *message = luaL_checkstring(L, 1);
 17.3493 +				        const char *type	= luaL_optstring(L, 2, "ok");
 17.3494 +
 17.3495 +#if (defined(WIN32) && !defined(SDL))
 17.3496 +				        int t;
 17.3497 +				        if (strcmp(type, "ok") == 0)
 17.3498 +							t = MB_OK;
 17.3499 +				        else if (strcmp(type, "yesno") == 0)
 17.3500 +							t = MB_YESNO;
 17.3501 +				        else if (strcmp(type, "yesnocancel") == 0)
 17.3502 +							t = MB_YESNOCANCEL;
 17.3503 +				        else
 17.3504 +							return luaL_error(L, "invalid popup type \"%s\"", type);
 17.3505 +
 17.3506 +				        theApp.winCheckFullscreen();
 17.3507 +				        systemSoundClearBuffer();
 17.3508 +				        int result = AfxGetApp()->m_pMainWnd->MessageBox(message, "Lua Script Pop-up", t);
 17.3509 +
 17.3510 +				        lua_settop(L, 1);
 17.3511 +
 17.3512 +				        if (t != MB_OK)
 17.3513 +				        {
 17.3514 +				            if (result == IDYES)
 17.3515 +								lua_pushstring(L, "yes");
 17.3516 +				            else if (result == IDNO)
 17.3517 +								lua_pushstring(L, "no");
 17.3518 +				            else if (result == IDCANCEL)
 17.3519 +								lua_pushstring(L, "cancel");
 17.3520 +				            else
 17.3521 +								luaL_error(L, "win32 unrecognized return value %d", result);
 17.3522 +				            return 1;
 17.3523 +						}
 17.3524 +
 17.3525 +				        // else, we don't care.
 17.3526 +				        return 0;
 17.3527 +#else
 17.3528 +				        char *t;
 17.3529 +	#ifdef __linux
 17.3530 +				        // The Linux backend has a "FromPause" variable.
 17.3531 +				        // If set to 1, assume some known external event has screwed with the flow of time.
 17.3532 +				        // Since this pauses the emulator waiting for a response, we set it to 1.
 17.3533 +// FIXME: Well, actually it doesn't
 17.3534 +//	extern int FromPause;
 17.3535 +//	FromPause = 1;
 17.3536 +
 17.3537 +				        int pid; // appease compiler
 17.3538 +
 17.3539 +				        // Before doing any work, verify the correctness of the parameters.
 17.3540 +				        if (strcmp(type, "ok") == 0)
 17.3541 +							t = "OK:100";
 17.3542 +				        else if (strcmp(type, "yesno") == 0)
 17.3543 +							t = "Yes:100,No:101";
 17.3544 +				        else if (strcmp(type, "yesnocancel") == 0)
 17.3545 +							t = "Yes:100,No:101,Cancel:102";
 17.3546 +				        else
 17.3547 +							return luaL_error(L, "invalid popup type \"%s\"", type);
 17.3548 +
 17.3549 +				        // Can we find a copy of xmessage? Search the path.
 17.3550 +				        char *path = strdup(getenv("PATH"));
 17.3551 +
 17.3552 +				        char *current = path;
 17.3553 +
 17.3554 +				        char *colon;
 17.3555 +
 17.3556 +				        int found = 0;
 17.3557 +
 17.3558 +				        while (current)
 17.3559 +				        {
 17.3560 +				            colon = strchr(current, ':');
 17.3561 +
 17.3562 +				            // Clip off the colon.
 17.3563 +				            *colon++ = 0;
 17.3564 +
 17.3565 +				            int	  len	   = strlen(current);
 17.3566 +				            char *filename = (char *)malloc(len + 12); // always give excess
 17.3567 +				            snprintf(filename, len + 12, "%s/xmessage", current);
 17.3568 +
 17.3569 +				            if (access(filename, X_OK) == 0)
 17.3570 +				            {
 17.3571 +				                free(filename);
 17.3572 +				                found = 1;
 17.3573 +				                break;
 17.3574 +							}
 17.3575 +
 17.3576 +				            // Failed, move on.
 17.3577 +				            current = colon;
 17.3578 +				            free(filename);
 17.3579 +						}
 17.3580 +
 17.3581 +				        free(path);
 17.3582 +
 17.3583 +				        // We've found it?
 17.3584 +				        if (!found)
 17.3585 +							goto use_console;
 17.3586 +
 17.3587 +				        pid = fork();
 17.3588 +				        if (pid == 0)
 17.3589 +				        { // I'm the virgin sacrifice
 17.3590 +				          // I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me.
 17.3591 +				          // Go ahead and abuse strdup.
 17.3592 +				            char *parameters[] = { "xmessage", "-buttons", t, strdup(message), NULL };
 17.3593 +
 17.3594 +				            execvp("xmessage", parameters);
 17.3595 +
 17.3596 +				            // Aw shitty
 17.3597 +				            perror("exec xmessage");
 17.3598 +				            exit(1);
 17.3599 +						}
 17.3600 +				        else if (pid < 0) // something went wrong!!! Oh hell... use the console
 17.3601 +							goto use_console;
 17.3602 +				        else
 17.3603 +				        {
 17.3604 +				            // We're the parent. Watch for the child.
 17.3605 +				            int r;
 17.3606 +				            int res = waitpid(pid, &r, 0);
 17.3607 +				            if (res < 0) // wtf?
 17.3608 +								goto use_console;
 17.3609 +
 17.3610 +				            // The return value gets copmlicated...
 17.3611 +				            if (!WIFEXITED(r))
 17.3612 +				            {
 17.3613 +				                luaL_error(L, "don't screw with my xmessage process!");
 17.3614 +							}
 17.3615 +
 17.3616 +				            r = WEXITSTATUS(r);
 17.3617 +
 17.3618 +				            // We assume it's worked.
 17.3619 +				            if (r == 0)
 17.3620 +				            {
 17.3621 +				                return 0; // no parameters for an OK
 17.3622 +							}
 17.3623 +
 17.3624 +				            if (r == 100)
 17.3625 +				            {
 17.3626 +				                lua_pushstring(L, "yes");
 17.3627 +				                return 1;
 17.3628 +							}
 17.3629 +
 17.3630 +				            if (r == 101)
 17.3631 +				            {
 17.3632 +				                lua_pushstring(L, "no");
 17.3633 +				                return 1;
 17.3634 +							}
 17.3635 +
 17.3636 +				            if (r == 102)
 17.3637 +				            {
 17.3638 +				                lua_pushstring(L, "cancel");
 17.3639 +				                return 1;
 17.3640 +							}
 17.3641 +
 17.3642 +				            // Wtf?
 17.3643 +				            return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r);
 17.3644 +						}
 17.3645 +
 17.3646 +use_console:
 17.3647 +	#endif
 17.3648 +
 17.3649 +				        // All else has failed
 17.3650 +				        if (strcmp(type, "ok") == 0)
 17.3651 +							t = "";
 17.3652 +				        else if (strcmp(type, "yesno") == 0)
 17.3653 +							t = "yn";
 17.3654 +				        else if (strcmp(type, "yesnocancel") == 0)
 17.3655 +							t = "ync";
 17.3656 +				        else
 17.3657 +							return luaL_error(L, "invalid popup type \"%s\"", type);
 17.3658 +
 17.3659 +				        fprintf(stderr, "Lua Message: %s\n", message);
 17.3660 +
 17.3661 +				        while (true)
 17.3662 +				        {
 17.3663 +				            char buffer[64];
 17.3664 +
 17.3665 +				            // We don't want parameters
 17.3666 +				            if (!t[0])
 17.3667 +				            {
 17.3668 +				                fprintf(stderr, "[Press Enter]");
 17.3669 +				                fgets(buffer, sizeof(buffer), stdin);
 17.3670 +
 17.3671 +				                // We're done
 17.3672 +				                return 0;
 17.3673 +							}
 17.3674 +
 17.3675 +				            fprintf(stderr, "(%s): ", t);
 17.3676 +				            fgets(buffer, sizeof(buffer), stdin);
 17.3677 +
 17.3678 +				            // Check if the option is in the list
 17.3679 +				            if (strchr(t, tolower(buffer[0])))
 17.3680 +				            {
 17.3681 +				                switch (tolower(buffer[0]))
 17.3682 +				                {
 17.3683 +								case 'y':
 17.3684 +									lua_pushstring(L, "yes");
 17.3685 +									return 1;
 17.3686 +								case 'n':
 17.3687 +									lua_pushstring(L, "no");
 17.3688 +									return 1;
 17.3689 +								case 'c':
 17.3690 +									lua_pushstring(L, "cancel");
 17.3691 +									return 1;
 17.3692 +								default:
 17.3693 +									luaL_error(L, "internal logic error in console based prompts for gui.popup");
 17.3694 +								}
 17.3695 +							}
 17.3696 +
 17.3697 +				            // We fell through, so we assume the user answered wrong and prompt again.
 17.3698 +						}
 17.3699 +
 17.3700 +				        // Nothing here, since the only way out is in the loop.
 17.3701 +#endif
 17.3702 +					}
 17.3703 +
 17.3704 +#if (defined(WIN32) && !defined(SDL))
 17.3705 +				    const char  *s_keyToName[256] =
 17.3706 +				    {
 17.3707 +				        NULL,
 17.3708 +				        "leftclick",
 17.3709 +				        "rightclick",
 17.3710 +				        NULL,
 17.3711 +				        "middleclick",
 17.3712 +				        NULL,
 17.3713 +				        NULL,
 17.3714 +				        NULL,
 17.3715 +				        "backspace",
 17.3716 +				        "tab",
 17.3717 +				        NULL,
 17.3718 +				        NULL,
 17.3719 +				        NULL,
 17.3720 +				        "enter",
 17.3721 +				        NULL,
 17.3722 +				        NULL,
 17.3723 +				        "shift",       // 0x10
 17.3724 +				        "control",
 17.3725 +				        "alt",
 17.3726 +				        "pause",
 17.3727 +				        "capslock",
 17.3728 +				        NULL,
 17.3729 +				        NULL,
 17.3730 +				        NULL,
 17.3731 +				        NULL,
 17.3732 +				        NULL,
 17.3733 +				        NULL,
 17.3734 +				        "escape",
 17.3735 +				        NULL,
 17.3736 +				        NULL,
 17.3737 +				        NULL,
 17.3738 +				        NULL,
 17.3739 +				        "space",       // 0x20
 17.3740 +				        "pageup",
 17.3741 +				        "pagedown",
 17.3742 +				        "end",
 17.3743 +				        "home",
 17.3744 +				        "left",
 17.3745 +				        "up",
 17.3746 +				        "right",
 17.3747 +				        "down",
 17.3748 +				        NULL,
 17.3749 +				        NULL,
 17.3750 +				        NULL,
 17.3751 +				        NULL,
 17.3752 +				        "insert",
 17.3753 +				        "delete",
 17.3754 +				        NULL,
 17.3755 +				        "0",		   "1",			   "2",			   "3",			   "4",		   "5",		  "6",		 "7",		"8",	   "9",
 17.3756 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,
 17.3757 +				        "A",		   "B",			   "C",			   "D",			   "E",		   "F",		  "G",		 "H",		"I",	   "J",
 17.3758 +				        "K",		   "L",			   "M",			   "N",			   "O",		   "P",		  "Q",		 "R",		"S",	   "T",
 17.3759 +				        "U",		   "V",			   "W",			   "X",			   "Y",		   "Z",
 17.3760 +				        NULL,
 17.3761 +				        NULL,
 17.3762 +				        NULL,
 17.3763 +				        NULL,
 17.3764 +				        NULL,
 17.3765 +				        "numpad0",	   "numpad1",	   "numpad2",	   "numpad3",	   "numpad4",  "numpad5", "numpad6", "numpad7", "numpad8", "numpad9",
 17.3766 +				        "numpad*",	   "numpad+",
 17.3767 +				        NULL,
 17.3768 +				        "numpad-",	   "numpad.",	   "numpad/",
 17.3769 +				        "F1",		   "F2",		   "F3",		   "F4",		   "F5",	   "F6",	  "F7",		 "F8",		"F9",	   "F10",	  "F11",
 17.3770 +				        "F12",
 17.3771 +				        "F13",		   "F14",		   "F15",		   "F16",		   "F17",	   "F18",	  "F19",	 "F20",		"F21",	   "F22",	  "F23",
 17.3772 +				        "F24",
 17.3773 +				        NULL,
 17.3774 +				        NULL,
 17.3775 +				        NULL,
 17.3776 +				        NULL,
 17.3777 +				        NULL,
 17.3778 +				        NULL,
 17.3779 +				        NULL,
 17.3780 +				        NULL,
 17.3781 +				        "numlock",
 17.3782 +				        "scrolllock",
 17.3783 +				        NULL,          // 0x92
 17.3784 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,		NULL,	   NULL,	  NULL,
 17.3785 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,		NULL,	   NULL,
 17.3786 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,		NULL,
 17.3787 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,
 17.3788 +				        NULL,          // 0xB9
 17.3789 +				        "semicolon",
 17.3790 +				        "plus",
 17.3791 +				        "comma",
 17.3792 +				        "minus",
 17.3793 +				        "period",
 17.3794 +				        "slash",
 17.3795 +				        "tilde",
 17.3796 +				        NULL,          // 0xC1
 17.3797 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,		NULL,
 17.3798 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,
 17.3799 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,
 17.3800 +				        NULL,          // 0xDA
 17.3801 +				        "leftbracket",
 17.3802 +				        "backslash",
 17.3803 +				        "rightbracket",
 17.3804 +				        "quote",
 17.3805 +					};
 17.3806 +#endif
 17.3807 +
 17.3808 +// input.get()
 17.3809 +// takes no input, returns a lua table of entries representing the current input state,
 17.3810 +// independent of the joypad buttons the emulated game thinks are pressed
 17.3811 +// for example:
 17.3812 +//   if the user is holding the W key and the left mouse button
 17.3813 +//   and has the mouse at the bottom-right corner of the game screen,
 17.3814 +
 17.3815 +//   then this would return {W=true, leftclick=true, xmouse=255, ymouse=223}
 17.3816 +				    static int input_getcurrentinputstatus(lua_State *L)
 17.3817 +				    {
 17.3818 +				        lua_newtable(L);
 17.3819 +
 17.3820 +#if (defined(WIN32) && !defined(SDL))
 17.3821 +				        // keyboard and mouse button status
 17.3822 +				        {
 17.3823 +				            unsigned char keys[256];
 17.3824 +				            if (true /*!GUI.BackgroundInput*/) // TODO: background input
 17.3825 +				            {
 17.3826 +				                if (GetKeyboardState(keys))
 17.3827 +				                {
 17.3828 +				                    for (int i = 1; i < 255; i++)
 17.3829 +				                    {
 17.3830 +				                        int mask = (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) ? 0x01 : 0x80;
 17.3831 +				                        if (keys[i] & mask)
 17.3832 +				                        {
 17.3833 +				                            const char *name = s_keyToName[i];
 17.3834 +				                            if (name)
 17.3835 +				                            {
 17.3836 +				                                lua_pushboolean(L, true);
 17.3837 +				                                lua_setfield(L, -2, name);
 17.3838 +											}
 17.3839 +										}
 17.3840 +									}
 17.3841 +								}
 17.3842 +							}
 17.3843 +				            else // use a slightly different method that will detect background input:
 17.3844 +				            {
 17.3845 +				                for (int i = 1; i < 255; i++)
 17.3846 +				                {
 17.3847 +				                    const char *name = s_keyToName[i];
 17.3848 +				                    if (name)
 17.3849 +				                    {
 17.3850 +				                        int active;
 17.3851 +				                        if (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL)
 17.3852 +											active = GetKeyState(i) & 0x01;
 17.3853 +				                        else
 17.3854 +											active = GetAsyncKeyState(i) & 0x8000;
 17.3855 +				                        if (active)
 17.3856 +				                        {
 17.3857 +				                            lua_pushboolean(L, true);
 17.3858 +				                            lua_setfield(L, -2, name);
 17.3859 +										}
 17.3860 +									}
 17.3861 +								}
 17.3862 +							}
 17.3863 +						}
 17.3864 +
 17.3865 +				        // mouse position in game screen pixel coordinates
 17.3866 +				        {
 17.3867 +				            POINT mouse;
 17.3868 +
 17.3869 +				            int xofs = 0, yofs = 0, width = 240, height = 160;
 17.3870 +				            if (!systemIsRunningGBA())
 17.3871 +				            {
 17.3872 +				                if (gbBorderOn)
 17.3873 +									width = 256, height = 224, xofs = 48, yofs = 40;
 17.3874 +				                else
 17.3875 +									width = 160, height = 144;
 17.3876 +							}
 17.3877 +
 17.3878 +				            GetCursorPos(&mouse);
 17.3879 +				            AfxGetApp()->m_pMainWnd->ScreenToClient(&mouse);
 17.3880 +
 17.3881 +				            // game screen is always fully stretched to window size,
 17.3882 +				            // with no aspect rate correction, or something like that.
 17.3883 +				            RECT clientRect;
 17.3884 +				            AfxGetApp()->m_pMainWnd->GetClientRect(&clientRect);
 17.3885 +
 17.3886 +				            int wndWidth  = clientRect.right - clientRect.left;
 17.3887 +				            int wndHeight = clientRect.bottom - clientRect.top;
 17.3888 +				            mouse.x = (LONG) (mouse.x * ((float)width / wndWidth)) - xofs;
 17.3889 +				            mouse.y = (LONG) (mouse.y * ((float)height / wndHeight)) - yofs;
 17.3890 +
 17.3891 +				            lua_pushinteger(L, mouse.x);
 17.3892 +				            lua_setfield(L, -2, "xmouse");
 17.3893 +				            lua_pushinteger(L, mouse.y);
 17.3894 +				            lua_setfield(L, -2, "ymouse");
 17.3895 +						}
 17.3896 +
 17.3897 +#else
 17.3898 +				        // NYI (well, return an empty table)
 17.3899 +#endif
 17.3900 +				        return 1;
 17.3901 +					}
 17.3902 +
 17.3903 +				    static int avi_framecount(lua_State *L)
 17.3904 +				    {
 17.3905 +	#ifdef WIN32
 17.3906 +				        if (theApp.aviRecorder != NULL)
 17.3907 +				        {
 17.3908 +				            lua_pushinteger(L, theApp.aviRecorder->videoFrames());
 17.3909 +						}
 17.3910 +				        else
 17.3911 +	#endif
 17.3912 +				        {
 17.3913 +				            lua_pushinteger(L, 0);
 17.3914 +						}
 17.3915 +				        return 1;
 17.3916 +					}
 17.3917 +
 17.3918 +				    static int avi_pause(lua_State *L)
 17.3919 +				    {
 17.3920 +	#ifdef WIN32
 17.3921 +				        if (theApp.aviRecorder != NULL)
 17.3922 +							theApp.aviRecorder->Pause(true);
 17.3923 +	#endif
 17.3924 +				        return 1;
 17.3925 +					}
 17.3926 +
 17.3927 +				    static int avi_resume(lua_State *L)
 17.3928 +				    {
 17.3929 +	#ifdef WIN32
 17.3930 +				        if (theApp.aviRecorder != NULL)
 17.3931 +							theApp.aviRecorder->Pause(false);
 17.3932 +	#endif
 17.3933 +				        return 1;
 17.3934 +					}
 17.3935 +
 17.3936 +					static int sound_get(lua_State *L)
 17.3937 +					{
 17.3938 +						extern int32 soundLevel1;
 17.3939 +						extern int32 soundLevel2;
 17.3940 +						extern int32 soundBalance;
 17.3941 +						extern int32 soundMasterOn;
 17.3942 +						extern int32 soundVIN;
 17.3943 +						extern int32 sound1On;
 17.3944 +						extern int32 sound1EnvelopeVolume;
 17.3945 +						extern int32 sound2On;
 17.3946 +						extern int32 sound2EnvelopeVolume;
 17.3947 +						extern int32 sound3On;
 17.3948 +						extern int32 sound3OutputLevel;
 17.3949 +						extern int32 sound3Bank;
 17.3950 +						extern int32 sound3DataSize;
 17.3951 +						extern int32 sound3ForcedOutput;
 17.3952 +						extern int32 sound4On;
 17.3953 +						extern int32 sound4EnvelopeVolume;
 17.3954 +						extern u8 sound3WaveRam[0x20];
 17.3955 +
 17.3956 +						int freqReg;
 17.3957 +						double freq;
 17.3958 +						double leftvolscale;
 17.3959 +						double rightvolscale;
 17.3960 +						double panpot;
 17.3961 +						bool gba = systemIsRunningGBA();
 17.3962 +						u8* gbMem = gba ? ioMem : gbMemory;
 17.3963 +						const int rNR10 = gba ? 0x60 : 0xff10;
 17.3964 +						const int rNR11 = gba ? 0x62 : 0xff11;
 17.3965 +						const int rNR12 = gba ? 0x63 : 0xff12;
 17.3966 +						const int rNR13 = gba ? 0x64 : 0xff13;
 17.3967 +						const int rNR14 = gba ? 0x65 : 0xff14;
 17.3968 +						const int rNR21 = gba ? 0x68 : 0xff16;
 17.3969 +						const int rNR22 = gba ? 0x69 : 0xff17;
 17.3970 +						const int rNR23 = gba ? 0x6c : 0xff18;
 17.3971 +						const int rNR24 = gba ? 0x6d : 0xff19;
 17.3972 +						const int rNR30 = gba ? 0x70 : 0xff1a;
 17.3973 +						const int rNR31 = gba ? 0x72 : 0xff1b;
 17.3974 +						const int rNR32 = gba ? 0x73 : 0xff1c;
 17.3975 +						const int rNR33 = gba ? 0x74 : 0xff1d;
 17.3976 +						const int rNR34 = gba ? 0x75 : 0xff1e;
 17.3977 +						const int rNR41 = gba ? 0x78 : 0xff20;
 17.3978 +						const int rNR42 = gba ? 0x79 : 0xff21;
 17.3979 +						const int rNR43 = gba ? 0x7c : 0xff22;
 17.3980 +						const int rNR44 = gba ? 0x7d : 0xff23;
 17.3981 +						const int rNR50 = gba ? 0x80 : 0xff24;
 17.3982 +						const int rNR51 = gba ? 0x81 : 0xff25;
 17.3983 +						const int rNR52 = gba ? 0x84 : 0xff26;
 17.3984 +						const int rWAVE_RAM = gba ? 0x90 : 0xff30;
 17.3985 +
 17.3986 +						const int32 _soundVIN = 0x88; // gba ? 0x88 : soundVIN;
 17.3987 +						const bool soundVINLeft = ((_soundVIN & 0x80) != 0);
 17.3988 +						const bool soundVINRight = ((_soundVIN & 0x08) != 0);
 17.3989 +
 17.3990 +						lua_newtable(L);
 17.3991 +
 17.3992 +						// square1
 17.3993 +						lua_newtable(L);
 17.3994 +						if(sound1On == 0 || soundMasterOn == 0)
 17.3995 +						{
 17.3996 +							lua_pushnumber(L, 0.0);
 17.3997 +							panpot = 0.5;
 17.3998 +						}
 17.3999 +						else
 17.4000 +						{
 17.4001 +							double envVolume = sound1EnvelopeVolume / 15.0;
 17.4002 +							if (soundVINLeft && (soundBalance & 0x10) != 0)
 17.4003 +								leftvolscale = ((soundLevel2 / 7.0) * envVolume);
 17.4004 +							else
 17.4005 +								leftvolscale = 0.0;
 17.4006 +							if (soundVINRight && (soundBalance & 0x01) != 0)
 17.4007 +								rightvolscale = ((soundLevel1 / 7.0) * envVolume);
 17.4008 +							else
 17.4009 +								rightvolscale = 0.0;
 17.4010 +							if ((leftvolscale + rightvolscale) != 0)
 17.4011 +								panpot = rightvolscale / (leftvolscale + rightvolscale);
 17.4012 +							else
 17.4013 +								panpot = 0.5;
 17.4014 +							lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
 17.4015 +						}
 17.4016 +						lua_setfield(L, -2, "volume");
 17.4017 +						lua_pushnumber(L, panpot);
 17.4018 +						lua_setfield(L, -2, "panpot");
 17.4019 +						freqReg = (((int)(gbMem[rNR14] & 7) << 8) | gbMem[rNR13]);
 17.4020 +						freq = 131072.0 / (2048 - freqReg);
 17.4021 +						lua_pushnumber(L, freq);
 17.4022 +						lua_setfield(L, -2, "frequency");
 17.4023 +						lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
 17.4024 +						lua_setfield(L, -2, "midikey");
 17.4025 +						lua_pushinteger(L, (gbMem[rNR11] & 0xC0) >> 6);
 17.4026 +						lua_setfield(L, -2, "duty");
 17.4027 +						lua_newtable(L);
 17.4028 +						lua_pushinteger(L, freqReg);
 17.4029 +						lua_setfield(L, -2, "frequency");
 17.4030 +						lua_setfield(L, -2, "regs");
 17.4031 +						lua_setfield(L, -2, "square1");
 17.4032 +						// square2
 17.4033 +						lua_newtable(L);
 17.4034 +						if(sound2On == 0 || soundMasterOn == 0)
 17.4035 +						{
 17.4036 +							lua_pushnumber(L, 0.0);
 17.4037 +							panpot = 0.5;
 17.4038 +						}
 17.4039 +						else
 17.4040 +						{
 17.4041 +							double envVolume = sound2EnvelopeVolume / 15.0;
 17.4042 +							if (soundVINLeft && (soundBalance & 0x20) != 0)
 17.4043 +								leftvolscale = ((soundLevel2 / 7.0) * envVolume);
 17.4044 +							else
 17.4045 +								leftvolscale = 0.0;
 17.4046 +							if (soundVINRight && (soundBalance & 0x02) != 0)
 17.4047 +								rightvolscale = ((soundLevel1 / 7.0) * envVolume);
 17.4048 +							else
 17.4049 +								rightvolscale = 0.0;
 17.4050 +							if ((leftvolscale + rightvolscale) != 0)
 17.4051 +								panpot = rightvolscale / (leftvolscale + rightvolscale);
 17.4052 +							else
 17.4053 +								panpot = 0.5;
 17.4054 +							lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
 17.4055 +						}
 17.4056 +						lua_setfield(L, -2, "volume");
 17.4057 +						lua_pushnumber(L, panpot);
 17.4058 +						lua_setfield(L, -2, "panpot");
 17.4059 +						freqReg = (((int)(gbMem[rNR24] & 7) << 8) | gbMem[rNR23]);
 17.4060 +						freq = 131072.0 / (2048 - freqReg);
 17.4061 +						lua_pushnumber(L, freq);
 17.4062 +						lua_setfield(L, -2, "frequency");
 17.4063 +						lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
 17.4064 +						lua_setfield(L, -2, "midikey");
 17.4065 +						lua_pushinteger(L, (gbMem[rNR21] & 0xC0) >> 6);
 17.4066 +						lua_setfield(L, -2, "duty");
 17.4067 +						lua_newtable(L);
 17.4068 +						lua_pushinteger(L, freqReg);
 17.4069 +						lua_setfield(L, -2, "frequency");
 17.4070 +						lua_setfield(L, -2, "regs");
 17.4071 +						lua_setfield(L, -2, "square2");
 17.4072 +						// wavememory
 17.4073 +						lua_newtable(L);
 17.4074 +						if(sound3On == 0 || soundMasterOn == 0)
 17.4075 +						{
 17.4076 +							lua_pushnumber(L, 0.0);
 17.4077 +							panpot = 0.5;
 17.4078 +						}
 17.4079 +						else
 17.4080 +						{
 17.4081 +							double envVolume;
 17.4082 +							if (gba && sound3ForcedOutput != 0)
 17.4083 +								envVolume = 0.75;
 17.4084 +							else
 17.4085 +							{
 17.4086 +								double volTable[4] = { 0.0, 1.0, 0.5, 0.25 };
 17.4087 +								envVolume = volTable[sound3OutputLevel & 3];
 17.4088 +							}
 17.4089 +
 17.4090 +							if (soundVINLeft && (soundBalance & 0x40) != 0)
 17.4091 +								leftvolscale = ((soundLevel2 / 7.0) * envVolume);
 17.4092 +							else
 17.4093 +								leftvolscale = 0.0;
 17.4094 +							if (soundVINRight && (soundBalance & 0x04) != 0)
 17.4095 +								rightvolscale = ((soundLevel1 / 7.0) * envVolume);
 17.4096 +							else
 17.4097 +								rightvolscale = 0.0;
 17.4098 +							if ((leftvolscale + rightvolscale) != 0)
 17.4099 +								panpot = rightvolscale / (leftvolscale + rightvolscale);
 17.4100 +							else
 17.4101 +								panpot = 0.5;
 17.4102 +							lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
 17.4103 +						}
 17.4104 +						lua_setfield(L, -2, "volume");
 17.4105 +						lua_pushnumber(L, panpot);
 17.4106 +						lua_setfield(L, -2, "panpot");
 17.4107 +						int waveMemSamples = 32;
 17.4108 +						if (gba)
 17.4109 +						{
 17.4110 +							lua_pushlstring(L, (const char *) &sound3WaveRam[sound3Bank * 0x10], sound3DataSize ? 0x20 : 0x10);
 17.4111 +							waveMemSamples = sound3DataSize ? 64 : 32;
 17.4112 +						}
 17.4113 +						else
 17.4114 +						{
 17.4115 +							lua_pushlstring(L, (const char *) &gbMem[rWAVE_RAM], 0x10);
 17.4116 +						}
 17.4117 +						lua_setfield(L, -2, "waveform");
 17.4118 +						freqReg = (((int)(gbMem[rNR34] & 7) << 8) | gbMem[rNR33]);
 17.4119 +						freq = 2097152.0 / (waveMemSamples * (2048 - freqReg));
 17.4120 +						lua_pushnumber(L, freq);
 17.4121 +						lua_setfield(L, -2, "frequency");
 17.4122 +						lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
 17.4123 +						lua_setfield(L, -2, "midikey");
 17.4124 +						lua_newtable(L);
 17.4125 +						lua_pushinteger(L, freqReg);
 17.4126 +						lua_setfield(L, -2, "frequency");
 17.4127 +						lua_setfield(L, -2, "regs");
 17.4128 +						lua_setfield(L, -2, "wavememory");
 17.4129 +						// noise
 17.4130 +						lua_newtable(L);
 17.4131 +						if(sound4On == 0 || soundMasterOn == 0)
 17.4132 +						{
 17.4133 +							lua_pushnumber(L, 0.0);
 17.4134 +							panpot = 0.5;
 17.4135 +						}
 17.4136 +						else
 17.4137 +						{
 17.4138 +							double envVolume = sound4EnvelopeVolume / 15.0;
 17.4139 +							if (soundVINLeft && (soundBalance & 0x80) != 0)
 17.4140 +								leftvolscale = ((soundLevel2 / 7.0) * envVolume);
 17.4141 +							else
 17.4142 +								leftvolscale = 0.0;
 17.4143 +							if (soundVINRight && (soundBalance & 0x08) != 0)
 17.4144 +								rightvolscale = ((soundLevel1 / 7.0) * envVolume);
 17.4145 +							else
 17.4146 +								rightvolscale = 0.0;
 17.4147 +							if ((leftvolscale + rightvolscale) != 0)
 17.4148 +								panpot = rightvolscale / (leftvolscale + rightvolscale);
 17.4149 +							else
 17.4150 +								panpot = 0.5;
 17.4151 +							lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
 17.4152 +						}
 17.4153 +						lua_setfield(L, -2, "volume");
 17.4154 +						lua_pushnumber(L, panpot);
 17.4155 +						lua_setfield(L, -2, "panpot");
 17.4156 +						const int gbNoiseFreqTable[8] = { 1, 2, 4, 6, 8, 10, 12, 14 };
 17.4157 +						freqReg = gbNoiseFreqTable[gbMem[rNR43] & 7] << (1 + (gbMem[rNR43] >> 4));
 17.4158 +						lua_pushboolean(L, (gbMem[rNR43] & 8) != 0);
 17.4159 +						lua_setfield(L, -2, "short");
 17.4160 +						freq = 1048576.0 / freqReg;
 17.4161 +						lua_pushnumber(L, freq);
 17.4162 +						lua_setfield(L, -2, "frequency");
 17.4163 +						lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
 17.4164 +						lua_setfield(L, -2, "midikey");
 17.4165 +						lua_newtable(L);
 17.4166 +						lua_pushinteger(L, freqReg);
 17.4167 +						lua_setfield(L, -2, "frequency");
 17.4168 +						lua_setfield(L, -2, "regs");
 17.4169 +						lua_setfield(L, -2, "noise");
 17.4170 +
 17.4171 +						return 1;
 17.4172 +					}
 17.4173 +
 17.4174 +// same as math.random, but uses SFMT instead of C rand()
 17.4175 +// FIXME: this function doesn't care multi-instance,
 17.4176 +
 17.4177 +//        original math.random either though (Lua 5.1)
 17.4178 +				    static int sfmt_random(lua_State *L)
 17.4179 +				    {
 17.4180 +				        lua_Number r = (lua_Number) genrand_real2();
 17.4181 +				        switch (lua_gettop(L))
 17.4182 +				        { // check number of arguments
 17.4183 +						case 0:
 17.4184 +							{ // no arguments
 17.4185 +							    lua_pushnumber(L, r); // Number between 0 and 1
 17.4186 +							    break;
 17.4187 +							}
 17.4188 +
 17.4189 +						case 1:
 17.4190 +							{ // only upper limit
 17.4191 +							    int u = luaL_checkint(L, 1);
 17.4192 +							    luaL_argcheck(L, 1 <= u, 1, "interval is empty");
 17.4193 +							    lua_pushnumber(L, floor(r * u) + 1); // int between 1 and `u'
 17.4194 +							    break;
 17.4195 +							}
 17.4196 +
 17.4197 +						case 2:
 17.4198 +							{ // lower and upper limits
 17.4199 +							    int l = luaL_checkint(L, 1);
 17.4200 +							    int u = luaL_checkint(L, 2);
 17.4201 +							    luaL_argcheck(L, l <= u, 2, "interval is empty");
 17.4202 +							    lua_pushnumber(L, floor(r * (u - l + 1)) + l); // int between `l' and `u'
 17.4203 +							    break;
 17.4204 +							}
 17.4205 +
 17.4206 +						default:
 17.4207 +							return luaL_error(L, "wrong number of arguments");
 17.4208 +						}
 17.4209 +
 17.4210 +				        return 1;
 17.4211 +					}
 17.4212 +
 17.4213 +// same as math.randomseed, but uses SFMT instead of C srand()
 17.4214 +// FIXME: this function doesn't care multi-instance,
 17.4215 +
 17.4216 +//        original math.randomseed either though (Lua 5.1)
 17.4217 +				    static int sfmt_randomseed(lua_State *L)
 17.4218 +				    {
 17.4219 +				        init_gen_rand(luaL_checkint(L, 1));
 17.4220 +				        return 0;
 17.4221 +					}
 17.4222 +
 17.4223 +// the following bit operations are ported from LuaBitOp 1.0.1,
 17.4224 +// because it can handle the sign bit (bit 31) correctly.
 17.4225 +
 17.4226 +/*
 17.4227 +** Lua BitOp -- a bit operations library for Lua 5.1.
 17.4228 +** http://bitop.luajit.org/
 17.4229 +**
 17.4230 +** Copyright (C) 2008-2009 Mike Pall. All rights reserved.
 17.4231 +**
 17.4232 +** Permission is hereby granted, free of charge, to any person obtaining
 17.4233 +** a copy of this software and associated documentation files (the
 17.4234 +** "Software"), to deal in the Software without restriction, including
 17.4235 +** without limitation the rights to use, copy, modify, merge, publish,
 17.4236 +** distribute, sublicense, and/or sell copies of the Software, and to
 17.4237 +** permit persons to whom the Software is furnished to do so, subject to
 17.4238 +** the following conditions:
 17.4239 +**
 17.4240 +** The above copyright notice and this permission notice shall be
 17.4241 +** included in all copies or substantial portions of the Software.
 17.4242 +**
 17.4243 +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 17.4244 +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 17.4245 +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 17.4246 +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 17.4247 +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 17.4248 +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 17.4249 +** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 17.4250 +**
 17.4251 +** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
 17.4252 +*/
 17.4253 +
 17.4254 +#ifdef _MSC_VER
 17.4255 +/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */
 17.4256 +				    typedef __int32			 int32_t;
 17.4257 +				    typedef unsigned __int32 uint32_t;
 17.4258 +				    typedef unsigned __int64 uint64_t;
 17.4259 +#else
 17.4260 +#include <stdint.h>
 17.4261 +#endif
 17.4262 +
 17.4263 +				    typedef int32_t	 SBits;
 17.4264 +				    typedef uint32_t UBits;
 17.4265 +
 17.4266 +				    typedef union
 17.4267 +				    {
 17.4268 +				        lua_Number n;
 17.4269 +#ifdef LUA_NUMBER_DOUBLE
 17.4270 +				        uint64_t b;
 17.4271 +#else
 17.4272 +				        UBits b;
 17.4273 +#endif
 17.4274 +					} BitNum;
 17.4275 +
 17.4276 +/* Convert argument to bit type. */
 17.4277 +				    static UBits barg(lua_State *L, int idx)
 17.4278 +				    {
 17.4279 +				        BitNum bn;
 17.4280 +				        UBits  b;
 17.4281 +				        bn.n = lua_tonumber(L, idx);
 17.4282 +#if defined(LUA_NUMBER_DOUBLE)
 17.4283 +				        bn.n += 6755399441055744.0; /* 2^52+2^51 */
 17.4284 +#ifdef SWAPPED_DOUBLE
 17.4285 +				        b = (UBits)(bn.b >> 32);
 17.4286 +#else
 17.4287 +				        b = (UBits)(bn.b & 0xffffffff);
 17.4288 +#endif
 17.4289 +#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \
 17.4290 +				        defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \
 17.4291 +				        defined(LUA_NUMBER_LLONG)
 17.4292 +				        if (sizeof(UBits) == sizeof(lua_Number))
 17.4293 +							b = bn.b;
 17.4294 +				        else
 17.4295 +							b = (UBits)(SBits)bn.n;
 17.4296 +#elif defined(LUA_NUMBER_FLOAT)
 17.4297 +#error "A 'float' lua_Number type is incompatible with this library"
 17.4298 +#else
 17.4299 +#error "Unknown number type, check LUA_NUMBER_* in luaconf.h"
 17.4300 +#endif
 17.4301 +				        if (b == 0 && !lua_isnumber(L, idx))
 17.4302 +							luaL_typerror(L, idx, "number");
 17.4303 +				        return b;
 17.4304 +					}
 17.4305 +
 17.4306 +/* Return bit type. */
 17.4307 +#define BRET(b)  lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1;
 17.4308 +
 17.4309 +				    static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
 17.4310 +				    static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
 17.4311 +
 17.4312 +#define BIT_OP(func, opr) \
 17.4313 +	static int func(lua_State * L) { int i; UBits b = barg(L, 1); \
 17.4314 +				                     for (i = lua_gettop(L); i > 1; i--) \
 17.4315 +										 b opr barg(L, i); BRET(b) }
 17.4316 +				    BIT_OP(bit_band, &= )
 17.4317 +				    BIT_OP(bit_bor, |= )
 17.4318 +				    BIT_OP(bit_bxor, ^= )
 17.4319 +
 17.4320 +#define bshl(b, n)  (b << n)
 17.4321 +#define bshr(b, n)  (b >> n)
 17.4322 +#define bsar(b, n)  ((SBits)b >> n)
 17.4323 +#define brol(b, n)  ((b << n) | (b >> (32 - n)))
 17.4324 +#define bror(b, n)  ((b << (32 - n)) | (b >> n))
 17.4325 +#define BIT_SH(func, fn) \
 17.4326 +	static int func(lua_State * L) { \
 17.4327 +		UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) }
 17.4328 +				    BIT_SH(bit_lshift, bshl)
 17.4329 +				    BIT_SH(bit_rshift, bshr)
 17.4330 +				    BIT_SH(bit_arshift, bsar)
 17.4331 +				    BIT_SH(bit_rol, brol)
 17.4332 +				    BIT_SH(bit_ror, bror)
 17.4333 +
 17.4334 +				    static int bit_bswap(lua_State *L)
 17.4335 +				    {
 17.4336 +				        UBits b = barg(L, 1);
 17.4337 +				        b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
 17.4338 +				        BRET(b)
 17.4339 +					}
 17.4340 +
 17.4341 +				    static int bit_tohex(lua_State *L)
 17.4342 +				    {
 17.4343 +				        UBits		b		  = barg(L, 1);
 17.4344 +				        SBits		n		  = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
 17.4345 +				        const char *hexdigits = "0123456789abcdef";
 17.4346 +				        char		buf[8];
 17.4347 +				        int			i;
 17.4348 +				        if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
 17.4349 +				        if (n > 8) n = 8;
 17.4350 +				        for (i = (int)n; --i >= 0; )
 17.4351 +				        {
 17.4352 +				            buf[i] = hexdigits[b & 15]; b >>= 4;
 17.4353 +						}
 17.4354 +				        lua_pushlstring(L, buf, (size_t)n);
 17.4355 +				        return 1;
 17.4356 +					}
 17.4357 +
 17.4358 +				    static const struct luaL_Reg bit_funcs[] = {
 17.4359 +				        { "tobit",	 bit_tobit	 },
 17.4360 +				        { "bnot",	 bit_bnot	 },
 17.4361 +				        { "band",	 bit_band	 },
 17.4362 +				        { "bor",	 bit_bor	 },
 17.4363 +				        { "bxor",	 bit_bxor	 },
 17.4364 +				        { "lshift",	 bit_lshift	 },
 17.4365 +				        { "rshift",	 bit_rshift	 },
 17.4366 +				        { "arshift", bit_arshift },
 17.4367 +				        { "rol",	 bit_rol	 },
 17.4368 +				        { "ror",	 bit_ror	 },
 17.4369 +				        { "bswap",	 bit_bswap	 },
 17.4370 +				        { "tohex",	 bit_tohex	 },
 17.4371 +				        { NULL,		 NULL		 }
 17.4372 +					};
 17.4373 +
 17.4374 +/* Signed right-shifts are implementation-defined per C89/C99.
 17.4375 +** But the de facto standard are arithmetic right-shifts on two's
 17.4376 +** complement CPUs. This behaviour is required here, so test for it.
 17.4377 +*/
 17.4378 +#define BAD_SAR     (bsar(-8, 2) != (SBits) - 2)
 17.4379 +
 17.4380 +				    bool luabitop_validate(lua_State *L) // originally named as luaopen_bit
 17.4381 +				    {
 17.4382 +				        UBits b;
 17.4383 +				        lua_pushnumber(L, (lua_Number)1437217655L);
 17.4384 +				        b = barg(L, -1);
 17.4385 +				        if (b != (UBits)1437217655L || BAD_SAR) /* Perform a simple self-test. */
 17.4386 +				        {
 17.4387 +				            const char *msg = "compiled with incompatible luaconf.h";
 17.4388 +#ifdef LUA_NUMBER_DOUBLE
 17.4389 +#ifdef WIN32
 17.4390 +				            if (b == (UBits)1610612736L)
 17.4391 +								msg = "use D3DCREATE_FPU_PRESERVE with DirectX";
 17.4392 +#endif
 17.4393 +				            if (b == (UBits)1127743488L)
 17.4394 +								msg = "not compiled with SWAPPED_DOUBLE";
 17.4395 +#endif
 17.4396 +				            if (BAD_SAR)
 17.4397 +								msg = "arithmetic right-shift broken";
 17.4398 +				            luaL_error(L, "bit library self-test failed (%s)", msg);
 17.4399 +				            return false;
 17.4400 +						}
 17.4401 +				        return true;
 17.4402 +					}
 17.4403 +
 17.4404 +// LuaBitOp ends here
 17.4405 +
 17.4406 +				    static int bit_bshift_emulua(lua_State *L)
 17.4407 +				    {
 17.4408 +				        int shift = luaL_checkinteger(L, 2);
 17.4409 +				        if (shift < 0)
 17.4410 +				        {
 17.4411 +				            lua_pushinteger(L, -shift);
 17.4412 +				            lua_replace(L, 2);
 17.4413 +				            return bit_lshift(L);
 17.4414 +						}
 17.4415 +				        else
 17.4416 +							return bit_rshift(L);
 17.4417 +					}
 17.4418 +
 17.4419 +				    static int bitbit(lua_State *L)
 17.4420 +				    {
 17.4421 +				        int rv		= 0;
 17.4422 +				        int numArgs = lua_gettop(L);
 17.4423 +				        for (int i = 1; i <= numArgs; i++)
 17.4424 +				        {
 17.4425 +				            int where = luaL_checkinteger(L, i);
 17.4426 +				            if (where >= 0 && where < 32)
 17.4427 +								rv |= (1 << where);
 17.4428 +						}
 17.4429 +				        lua_settop(L, 0);
 17.4430 +				        BRET(rv);
 17.4431 +					}
 17.4432 +
 17.4433 +// The function called periodically to ensure Lua doesn't run amok.
 17.4434 +				    static void VBALuaHookFunction(lua_State *L, lua_Debug *dbg)
 17.4435 +				    {
 17.4436 +				        if (numTries-- == 0)
 17.4437 +				        {
 17.4438 +				            int kill = 0;
 17.4439 +
 17.4440 +#if (defined(WIN32) && !defined(SDL))
 17.4441 +				            // Uh oh
 17.4442 +				            theApp.winCheckFullscreen();
 17.4443 +				            systemSoundClearBuffer();
 17.4444 +				            int ret = AfxGetApp()->m_pMainWnd->MessageBox(
 17.4445 +				                "The Lua script running has been running a long time. It may have gone crazy. Kill it?\n\n(No = don't check anymore either)",
 17.4446 +				                "Lua Script Gone Nuts?",
 17.4447 +				                MB_YESNO);
 17.4448 +
 17.4449 +				            if (ret == IDYES)
 17.4450 +				            {
 17.4451 +				                kill = 1;
 17.4452 +							}
 17.4453 +
 17.4454 +#else
 17.4455 +				            fprintf(
 17.4456 +				                stderr,
 17.4457 +				                "The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n");
 17.4458 +
 17.4459 +				            char buffer[64];
 17.4460 +				            while (true)
 17.4461 +				            {
 17.4462 +				                fprintf(stderr, "(y/n): ");
 17.4463 +				                fgets(buffer, sizeof(buffer), stdin);
 17.4464 +				                if (buffer[0] == 'y' || buffer[0] == 'Y')
 17.4465 +				                {
 17.4466 +				                    kill = 1;
 17.4467 +				                    break;
 17.4468 +								}
 17.4469 +
 17.4470 +				                if (buffer[0] == 'n' || buffer[0] == 'N')
 17.4471 +									break;
 17.4472 +							}
 17.4473 +#endif
 17.4474 +				            if (kill)
 17.4475 +				            {
 17.4476 +				                luaL_error(L, "Killed by user request.");
 17.4477 +				                VBALuaOnStop();
 17.4478 +							}
 17.4479 +
 17.4480 +				            // else, kill the debug hook.
 17.4481 +				            lua_sethook(L, NULL, 0, 0);
 17.4482 +						}
 17.4483 +					}
 17.4484 +
 17.4485 +				    static const struct luaL_reg vbalib[] = {
 17.4486 +				        //	{"speedmode", vba_speedmode},	// TODO: NYI
 17.4487 +				        { "frameadvance",	vba_frameadvance	  },
 17.4488 +				        { "pause",			vba_pause			  },
 17.4489 +				        { "framecount",		vba_framecount		  },
 17.4490 +				        { "lagcount",		vba_getlagcount		  },
 17.4491 +				        { "lagged",			vba_lagged			  },
 17.4492 +				        { "emulating",		vba_emulating		  },
 17.4493 +				        { "registerbefore", vba_registerbefore	  },
 17.4494 +				        { "registerafter",	vba_registerafter	  },
 17.4495 +				        { "registerexit",	vba_registerexit	  },
 17.4496 +				        { "message",		vba_message			  },
 17.4497 +				        { "print",			print				  }, // sure, why not
 17.4498 +				        { NULL,				NULL				  }
 17.4499 +					};
 17.4500 +
 17.4501 +				    static const struct luaL_reg memorylib[] = {
 17.4502 +				        { "readbyte",				memory_readbyte				},
 17.4503 +				        { "readbytesigned",			memory_readbytesigned		},
 17.4504 +				        { "readword",				memory_readword				},
 17.4505 +				        { "readwordsigned",			memory_readwordsigned		},
 17.4506 +				        { "readdword",				memory_readdword			},
 17.4507 +				        { "readdwordsigned",		memory_readdwordsigned		},
 17.4508 +				        { "readbyterange",			memory_readbyterange		},
 17.4509 +				        { "writebyte",				memory_writebyte			},
 17.4510 +				        { "writeword",				memory_writeword			},
 17.4511 +				        { "writedword",				memory_writedword			},
 17.4512 +				        { "getregister",			memory_getregister			},
 17.4513 +				        { "setregister",			memory_setregister			},
 17.4514 +						{ "gbromreadbyte",			memory_gbromreadbyte		},
 17.4515 +						{ "gbromreadbytesigned",	memory_gbromreadbytesigned	},
 17.4516 +						{ "gbromreadword",			memory_gbromreadword		},
 17.4517 +						{ "gbromreadwordsigned",	memory_gbromreadwordsigned	},
 17.4518 +						{ "gbromreaddword",			memory_gbromreaddword		},
 17.4519 +						{ "gbromreaddwordsigned",	memory_gbromreaddwordsigned	},
 17.4520 +						{ "gbromreadbyterange",		memory_gbromreadbyterange	},
 17.4521 +
 17.4522 +				        // alternate naming scheme for word and double-word and unsigned
 17.4523 +				        { "readbyteunsigned",		memory_readbyte				},
 17.4524 +				        { "readwordunsigned",		memory_readword				},
 17.4525 +				        { "readdwordunsigned",		memory_readdword			},
 17.4526 +				        { "readshort",				memory_readword				},
 17.4527 +				        { "readshortunsigned",		memory_readword				},
 17.4528 +				        { "readshortsigned",		memory_readwordsigned		},
 17.4529 +				        { "readlong",				memory_readdword			},
 17.4530 +				        { "readlongunsigned",		memory_readdword			},
 17.4531 +						{ "readlongsigned",			memory_readdwordsigned		},
 17.4532 +				        { "writeshort",				memory_writeword			},
 17.4533 +				        { "writelong",				memory_writedword			},
 17.4534 +						{ "gbromreadbyteunsigned",	memory_gbromreadbyte		},
 17.4535 +						{ "gbromreadwordunsigned",	memory_gbromreadword		},
 17.4536 +						{ "gbromreaddwordunsigned",	memory_gbromreaddword		},
 17.4537 +						{ "gbromreadshort",			memory_gbromreadword		},
 17.4538 +						{ "gbromreadshortunsigned",	memory_gbromreadword		},
 17.4539 +						{ "gbromreadshortsigned",	memory_gbromreadwordsigned	},
 17.4540 +						{ "gbromreadlong",			memory_gbromreaddword		},
 17.4541 +						{ "gbromreadlongunsigned",	memory_gbromreaddword		},
 17.4542 +						{ "gbromreadlongsigned",	memory_gbromreaddwordsigned	},
 17.4543 +
 17.4544 +				        // memory hooks
 17.4545 +				        { "registerwrite",	   memory_registerwrite			 },
 17.4546 +				        //{"registerread", memory_registerread},
 17.4547 +				        { "registerexec",	   memory_registerexec			 },
 17.4548 +				        // alternate names
 17.4549 +				        { "register",		   memory_registerwrite			 },
 17.4550 +				        { "registerrun",	   memory_registerexec			 },
 17.4551 +				        { "registerexecute",   memory_registerexec			 },
 17.4552 +
 17.4553 +				        { NULL,				   NULL							 }
 17.4554 +					};
 17.4555 +
 17.4556 +				    static const struct luaL_reg joypadlib[] = {
 17.4557 +				        { "get",	  joypad_get	  },
 17.4558 +				        { "getdown",  joypad_getdown  },
 17.4559 +				        { "getup",	  joypad_getup	  },
 17.4560 +				        { "set",	  joypad_set	  },
 17.4561 +
 17.4562 +				        // alternative names
 17.4563 +				        { "read",	  joypad_get	  },
 17.4564 +				        { "write",	  joypad_set	  },
 17.4565 +				        { "readdown", joypad_getdown  },
 17.4566 +				        { "readup",	  joypad_getup	  },
 17.4567 +				        { NULL,		  NULL			  }
 17.4568 +					};
 17.4569 +
 17.4570 +				    static const struct luaL_reg savestatelib[] = {
 17.4571 +				        { "create", savestate_create },
 17.4572 +				        { "save",	savestate_save	 },
 17.4573 +				        { "load",	savestate_load	 },
 17.4574 +
 17.4575 +				        { NULL,		NULL			 }
 17.4576 +					};
 17.4577 +
 17.4578 +				    static const struct luaL_reg movielib[] = {
 17.4579 +				        { "active",			  movie_isactive				},
 17.4580 +				        { "recording",		  movie_isrecording				},
 17.4581 +				        { "playing",		  movie_isplaying				},
 17.4582 +				        { "mode",			  movie_getmode					},
 17.4583 +
 17.4584 +				        { "length",			  movie_getlength				},
 17.4585 +				        { "author",			  movie_getauthor				},
 17.4586 +				        { "name",			  movie_getfilename				},
 17.4587 +				        { "rerecordcount",	  movie_rerecordcount			},
 17.4588 +				        { "setrerecordcount", movie_setrerecordcount		},
 17.4589 +
 17.4590 +				        { "rerecordcounting", movie_rerecordcounting		},
 17.4591 +				        { "framecount",		  vba_framecount				}, // for those familiar with
 17.4592 +				                                                              // other emulators that have
 17.4593 +				                                                              // movie.framecount()
 17.4594 +				                                                              // instead of
 17.4595 +				                                                              // emulatorname.framecount()
 17.4596 +
 17.4597 +				        { "stop",			  movie_stop					},
 17.4598 +
 17.4599 +				        // alternative names
 17.4600 +				        { "close",			  movie_stop					},
 17.4601 +				        { "getauthor",		  movie_getauthor				},
 17.4602 +				        { "getname",		  movie_getfilename				},
 17.4603 +				        { NULL,				  NULL							}
 17.4604 +					};
 17.4605 +
 17.4606 +				    static const struct luaL_reg guilib[] = {
 17.4607 +				        { "register",	  gui_register		   },
 17.4608 +				        { "text",		  gui_text			   },
 17.4609 +				        { "box",		  gui_drawbox		   },
 17.4610 +				        { "line",		  gui_drawline		   },
 17.4611 +				        { "pixel",		  gui_drawpixel		   },
 17.4612 +				        { "opacity",	  gui_setopacity	   },
 17.4613 +				        { "transparency", gui_transparency	   },
 17.4614 +				        { "popup",		  gui_popup			   },
 17.4615 +				        { "parsecolor",	  gui_parsecolor	   },
 17.4616 +				        { "gdscreenshot", gui_gdscreenshot	   },
 17.4617 +				        { "gdoverlay",	  gui_gdoverlay		   },
 17.4618 +				        { "getpixel",	  gui_getpixel		   },
 17.4619 +
 17.4620 +				        // alternative names
 17.4621 +				        { "drawtext",	  gui_text			   },
 17.4622 +				        { "drawbox",	  gui_drawbox		   },
 17.4623 +				        { "drawline",	  gui_drawline		   },
 17.4624 +				        { "drawpixel",	  gui_drawpixel		   },
 17.4625 +				        { "setpixel",	  gui_drawpixel		   },
 17.4626 +				        { "writepixel",	  gui_drawpixel		   },
 17.4627 +				        { "rect",		  gui_drawbox		   },
 17.4628 +				        { "drawrect",	  gui_drawbox		   },
 17.4629 +				        { "drawimage",	  gui_gdoverlay		   },
 17.4630 +				        { "image",		  gui_gdoverlay		   },
 17.4631 +				        { "readpixel",	  gui_getpixel		   },
 17.4632 +				        { NULL,			  NULL				   }
 17.4633 +					};
 17.4634 +
 17.4635 +				    static const struct luaL_reg inputlib[] = {
 17.4636 +				        { "get",  input_getcurrentinputstatus  },
 17.4637 +
 17.4638 +				        // alternative names
 17.4639 +				        { "read", input_getcurrentinputstatus  },
 17.4640 +				        { NULL,	  NULL						   }
 17.4641 +					};
 17.4642 +
 17.4643 +				    static const struct luaL_reg soundlib[] = {
 17.4644 +				        { "get",  sound_get                    },
 17.4645 +
 17.4646 +				        // alternative names
 17.4647 +				        { NULL,	  NULL						   }
 17.4648 +					};
 17.4649 +
 17.4650 +// gocha: since vba dumps avi so badly,
 17.4651 +// I add avilib as a workaround for enhanced video encoding.
 17.4652 +				    static const struct luaL_reg avilib[] = {
 17.4653 +				        { "framecount", avi_framecount },
 17.4654 +				        { "pause",		avi_pause	   },
 17.4655 +				        { "resume",		avi_resume	   },
 17.4656 +				        { NULL,			NULL		   }
 17.4657 +					};
 17.4658 +
 17.4659 +				    void CallExitFunction(void)
 17.4660 +				    {
 17.4661 +				        if (!LUA)
 17.4662 +							return;
 17.4663 +
 17.4664 +				        lua_settop(LUA, 0);
 17.4665 +				        lua_getfield(LUA, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
 17.4666 +
 17.4667 +				        int errorcode = 0;
 17.4668 +				        if (lua_isfunction(LUA, -1))
 17.4669 +				        {
 17.4670 +				            errorcode = lua_pcall(LUA, 0, 0, 0);
 17.4671 +						}
 17.4672 +
 17.4673 +				        if (errorcode)
 17.4674 +							HandleCallbackError(LUA);
 17.4675 +					}
 17.4676 +
 17.4677 +				    void VBALuaFrameBoundary(void)
 17.4678 +				    {
 17.4679 +				        //	printf("Lua Frame\n");
 17.4680 +
 17.4681 +				        lua_joypads_used = 0;
 17.4682 +
 17.4683 +				        // HA!
 17.4684 +				        if (!LUA || !luaRunning)
 17.4685 +							return;
 17.4686 +
 17.4687 +				        // Our function needs calling
 17.4688 +				        lua_settop(LUA, 0);
 17.4689 +				        lua_getfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
 17.4690 +
 17.4691 +				        lua_State *thread = lua_tothread(LUA, 1);
 17.4692 +
 17.4693 +				        // Lua calling C must know that we're busy inside a frame boundary
 17.4694 +				        frameBoundary		= true;
 17.4695 +				        frameAdvanceWaiting = false;
 17.4696 +
 17.4697 +				        numTries = 1000;
 17.4698 +
 17.4699 +				        int result = lua_resume(thread, 0);
 17.4700 +
 17.4701 +				        if (result == LUA_YIELD)
 17.4702 +				        {
 17.4703 +				            // Okay, we're fine with that.
 17.4704 +						}
 17.4705 +				        else if (result != 0)
 17.4706 +				        {
 17.4707 +				            // Done execution by bad causes
 17.4708 +				            VBALuaOnStop();
 17.4709 +				            lua_pushnil(LUA);
 17.4710 +				            lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
 17.4711 +				            lua_pushnil(LUA);
 17.4712 +				            lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
 17.4713 +
 17.4714 +				            // Error?
 17.4715 +//#if (defined(WIN32) && !defined(SDL))
 17.4716 +//		info_print(info_uid, lua_tostring(thread, -1)); //Clear_Sound_Buffer();
 17.4717 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(thread, -1), "Lua run error", MB_OK | MB_ICONSTOP);
 17.4718 +//#else
 17.4719 +//		fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(thread, -1));
 17.4720 +//#endif
 17.4721 +				            printerror(thread, -1);
 17.4722 +						}
 17.4723 +				        else
 17.4724 +				        {
 17.4725 +				            VBALuaOnStop();
 17.4726 +				            printf("Script died of natural causes.\n");
 17.4727 +						}
 17.4728 +
 17.4729 +				        // Past here, VBA actually runs, so any Lua code is called mid-frame. We must
 17.4730 +				        // not do anything too stupid, so let ourselves know.
 17.4731 +				        frameBoundary = false;
 17.4732 +
 17.4733 +				        if (!frameAdvanceWaiting)
 17.4734 +				        {
 17.4735 +				            VBALuaOnStop();
 17.4736 +						}
 17.4737 +					}
 17.4738 +
 17.4739 +/**
 17.4740 + * Loads and runs the given Lua script.
 17.4741 + * The emulator MUST be paused for this function to be
 17.4742 + * called. Otherwise, all frame boundary assumptions go out the window.
 17.4743 + *
 17.4744 + * Returns true on success, false on failure.
 17.4745 + */
 17.4746 +				    int VBALoadLuaCode(const char *filename)
 17.4747 +				    {
 17.4748 +				        static bool sfmtInitialized = false;
 17.4749 +				        if (!sfmtInitialized)
 17.4750 +				        {
 17.4751 +				            init_gen_rand((unsigned)time(NULL));
 17.4752 +				            sfmtInitialized = true;
 17.4753 +						}
 17.4754 +
 17.4755 +				        if (filename != luaScriptName)
 17.4756 +				        {
 17.4757 +				            if (luaScriptName)
 17.4758 +								free(luaScriptName);
 17.4759 +				            luaScriptName = strdup(filename);
 17.4760 +						}
 17.4761 +
 17.4762 +				        //stop any lua we might already have had running
 17.4763 +				        VBALuaStop();
 17.4764 +
 17.4765 +				        // Set current directory from filename (for dofile)
 17.4766 +				        char  dir[_MAX_PATH];
 17.4767 +				        char *slash, *backslash;
 17.4768 +				        strcpy(dir, filename);
 17.4769 +				        slash	  = strrchr(dir, '/');
 17.4770 +				        backslash = strrchr(dir, '\\');
 17.4771 +				        if (!slash || (backslash && backslash < slash))
 17.4772 +							slash = backslash;
 17.4773 +				        if (slash)
 17.4774 +				        {
 17.4775 +				            slash[1] = '\0'; // keep slash itself for some reasons
 17.4776 +				            chdir(dir);
 17.4777 +						}
 17.4778 +
 17.4779 +				        if (!LUA)
 17.4780 +				        {
 17.4781 +				            LUA = lua_open();
 17.4782 +				            luaL_openlibs(LUA);
 17.4783 +
 17.4784 +				            luaL_register(LUA, "emu", vbalib); // added for better cross-emulator compatibility
 17.4785 +				            luaL_register(LUA, "vba", vbalib); // kept for backward compatibility
 17.4786 +				            luaL_register(LUA, "memory", memorylib);
 17.4787 +				            luaL_register(LUA, "joypad", joypadlib);
 17.4788 +				            luaL_register(LUA, "savestate", savestatelib);
 17.4789 +				            luaL_register(LUA, "movie", movielib);
 17.4790 +				            luaL_register(LUA, "gui", guilib);
 17.4791 +				            luaL_register(LUA, "input", inputlib);
 17.4792 +				            luaL_register(LUA, "sound", soundlib);
 17.4793 +				            luaL_register(LUA, "bit", bit_funcs); // LuaBitOp library
 17.4794 +				            luaL_register(LUA, "avi", avilib); // workaround for enhanced video encoding
 17.4795 +				            lua_settop(LUA, 0); // clean the stack, because each call to luaL_register leaves a table on top
 17.4796 +
 17.4797 +				            // register a few utility functions outside of libraries (in the global namespace)
 17.4798 +				            lua_register(LUA, "print", print);
 17.4799 +				            lua_register(LUA, "tostring", tostring);
 17.4800 +				            lua_register(LUA, "addressof", addressof);
 17.4801 +				            lua_register(LUA, "copytable", copytable);
 17.4802 +
 17.4803 +				            // old bit operation functions
 17.4804 +				            lua_register(LUA, "AND", bit_band);
 17.4805 +				            lua_register(LUA, "OR", bit_bor);
 17.4806 +				            lua_register(LUA, "XOR", bit_bxor);
 17.4807 +				            lua_register(LUA, "SHIFT", bit_bshift_emulua);
 17.4808 +				            lua_register(LUA, "BIT", bitbit);
 17.4809 +
 17.4810 +				            luabitop_validate(LUA);
 17.4811 +
 17.4812 +				            lua_pushstring(LUA, "math");
 17.4813 +				            lua_gettable(LUA, LUA_GLOBALSINDEX);
 17.4814 +				            lua_pushcfunction(LUA, sfmt_random);
 17.4815 +				            lua_setfield(LUA, -2, "random");
 17.4816 +				            lua_pushcfunction(LUA, sfmt_randomseed);
 17.4817 +				            lua_setfield(LUA, -2, "randomseed");
 17.4818 +				            lua_settop(LUA, 0);
 17.4819 +
 17.4820 +				            // push arrays for storing hook functions in
 17.4821 +				            for (int i = 0; i < LUAMEMHOOK_COUNT; i++)
 17.4822 +				            {
 17.4823 +				                lua_newtable(LUA);
 17.4824 +				                lua_setfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]);
 17.4825 +							}
 17.4826 +						}
 17.4827 +
 17.4828 +				        // We make our thread NOW because we want it at the bottom of the stack.
 17.4829 +				        // If all goes wrong, we let the garbage collector remove it.
 17.4830 +				        lua_State *thread = lua_newthread(LUA);
 17.4831 +
 17.4832 +				        // Load the data
 17.4833 +				        int result = luaL_loadfile(LUA, filename);
 17.4834 +
 17.4835 +				        if (result)
 17.4836 +				        {
 17.4837 +//#if (defined(WIN32) && !defined(SDL))
 17.4838 +//		info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer();
 17.4839 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua load error", MB_OK | MB_ICONSTOP);
 17.4840 +//#else
 17.4841 +//		fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(LUA, -1));
 17.4842 +//#endif
 17.4843 +				            printerror(LUA, -1);
 17.4844 +
 17.4845 +				            // Wipe the stack. Our thread
 17.4846 +				            lua_settop(LUA, 0);
 17.4847 +				            return 0; // Oh shit.
 17.4848 +						}
 17.4849 +
 17.4850 +				        // Get our function into it
 17.4851 +				        lua_xmove(LUA, thread, 1);
 17.4852 +
 17.4853 +				        // Save the thread to the registry. This is why I make the thread FIRST.
 17.4854 +				        lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
 17.4855 +
 17.4856 +				        // Initialize settings
 17.4857 +				        luaRunning = true;
 17.4858 +				        skipRerecords		 = false;
 17.4859 +				        numMemHooks			 = 0;
 17.4860 +				        transparencyModifier = 255; // opaque
 17.4861 +				        lua_joypads_used	 = 0; // not used
 17.4862 +				        //wasPaused = systemIsPaused();
 17.4863 +				        //systemSetPause(false);
 17.4864 +
 17.4865 +				        // Set up our protection hook to be executed once every 10,000 bytecode instructions.
 17.4866 +				        lua_sethook(thread, VBALuaHookFunction, LUA_MASKCOUNT, 10000);
 17.4867 +
 17.4868 +#ifdef WIN32
 17.4869 +				        info_print	 = PrintToWindowConsole;
 17.4870 +				        info_onstart = WinLuaOnStart;
 17.4871 +				        info_onstop	 = WinLuaOnStop;
 17.4872 +				        if (!LuaConsoleHWnd)
 17.4873 +							LuaConsoleHWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_LUA),
 17.4874 +							                              AfxGetMainWnd()->GetSafeHwnd(), (DLGPROC) DlgLuaScriptDialog);
 17.4875 +				        info_uid = (int)LuaConsoleHWnd;
 17.4876 +#else
 17.4877 +				        info_print	 = NULL;
 17.4878 +				        info_onstart = NULL;
 17.4879 +				        info_onstop	 = NULL;
 17.4880 +#endif
 17.4881 +				        if (info_onstart)
 17.4882 +							info_onstart(info_uid);
 17.4883 +
 17.4884 +				        // And run it right now. :)
 17.4885 +				        VBALuaFrameBoundary();
 17.4886 +				        systemRenderFrame();
 17.4887 +
 17.4888 +				        // We're done.
 17.4889 +				        return 1;
 17.4890 +					}
 17.4891 +
 17.4892 +/**
 17.4893 + * Equivalent to repeating the last VBALoadLuaCode() call.
 17.4894 + */
 17.4895 +				    int VBAReloadLuaCode(void)
 17.4896 +				    {
 17.4897 +				        if (!luaScriptName)
 17.4898 +				        {
 17.4899 +				            systemScreenMessage("There's no script to reload.");
 17.4900 +				            return 0;
 17.4901 +						}
 17.4902 +				        else
 17.4903 +							return VBALoadLuaCode(luaScriptName);
 17.4904 +					}
 17.4905 +
 17.4906 +/**
 17.4907 + * Terminates a running Lua script by killing the whole Lua engine.
 17.4908 + *
 17.4909 + * Always safe to call, except from within a lua call itself (duh).
 17.4910 + *
 17.4911 + */
 17.4912 +				    void VBALuaStop(void)
 17.4913 +				    {
 17.4914 +				        //already killed
 17.4915 +				        if (!LUA)
 17.4916 +							return;
 17.4917 +
 17.4918 +				        //execute the user's shutdown callbacks
 17.4919 +				        CallExitFunction();
 17.4920 +
 17.4921 +				        /*info.*/ numMemHooks = 0;
 17.4922 +				        for (int i = 0; i < LUAMEMHOOK_COUNT; i++)
 17.4923 +							CalculateMemHookRegions((LuaMemHookType)i);
 17.4924 +
 17.4925 +				        //sometimes iup uninitializes com
 17.4926 +				        //MBG TODO - test whether this is really necessary. i dont think it is
 17.4927 +#if (defined(WIN32) && !defined(SDL))
 17.4928 +				        CoInitialize(0);
 17.4929 +#endif
 17.4930 +
 17.4931 +				        if (info_onstop)
 17.4932 +							info_onstop(info_uid);
 17.4933 +
 17.4934 +				        //lua_gc(LUA,LUA_GCCOLLECT,0);
 17.4935 +				        lua_close(LUA); // this invokes our garbage collectors for us
 17.4936 +				        LUA = NULL;
 17.4937 +				        VBALuaOnStop();
 17.4938 +					}
 17.4939 +
 17.4940 +/**
 17.4941 + * Returns true if there is a Lua script running.
 17.4942 + *
 17.4943 + */
 17.4944 +				    int VBALuaRunning(void)
 17.4945 +				    {
 17.4946 +				        // FIXME: return false when no callback functions are registered.
 17.4947 +				        return (int) (LUA != NULL); // should return true if callback functions are active.
 17.4948 +					}
 17.4949 +
 17.4950 +/**
 17.4951 + * Returns true if Lua would like to steal the given joypad control.
 17.4952 + *
 17.4953 + * Range is 0 through 3
 17.4954 + */
 17.4955 +				    int VBALuaUsingJoypad(int which)
 17.4956 +				    {
 17.4957 +				        if (which < 0 || which > 3)
 17.4958 +							which = systemGetDefaultJoypad();
 17.4959 +				        return lua_joypads_used & (1 << which);
 17.4960 +					}
 17.4961 +
 17.4962 +/**
 17.4963 + * Reads the buttons Lua is feeding for the given joypad, in the same
 17.4964 + * format as the OS-specific code.
 17.4965 + *
 17.4966 + * <del>This function must not be called more than once per frame. </del>Ideally exactly once
 17.4967 + * per frame (if VBALuaUsingJoypad says it's safe to do so)
 17.4968 + */
 17.4969 +				    int VBALuaReadJoypad(int which)
 17.4970 +				    {
 17.4971 +				        if (which < 0 || which > 3)
 17.4972 +							which = systemGetDefaultJoypad();
 17.4973 +
 17.4974 +				        //lua_joypads_used &= ~(1 << which);
 17.4975 +				        return lua_joypads[which];
 17.4976 +					}
 17.4977 +
 17.4978 +/**
 17.4979 + * If this function returns true, the movie code should NOT increment
 17.4980 + * the rerecord count for a load-state.
 17.4981 + *
 17.4982 + * This function will not return true if a script is not running.
 17.4983 + */
 17.4984 +				    bool8 VBALuaRerecordCountSkip(void)
 17.4985 +				    {
 17.4986 +				        // FIXME: return true if (there are any active callback functions && skipRerecords)
 17.4987 +				        return LUA && luaRunning && skipRerecords;
 17.4988 +					}
 17.4989 +
 17.4990 +/**
 17.4991 + * Given a screen with the indicated resolution,
 17.4992 + * draw the current GUI onto it.
 17.4993 + */
 17.4994 +				    void VBALuaGui(uint8 *screen, int ppl, int width, int height)
 17.4995 +				    {
 17.4996 +				        if (!LUA /* || !luaRunning*/)
 17.4997 +							return;
 17.4998 +
 17.4999 +				        // First, check if we're being called by anybody
 17.5000 +				        lua_getfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
 17.5001 +
 17.5002 +				        if (lua_isfunction(LUA, -1))
 17.5003 +				        {
 17.5004 +				            // We call it now
 17.5005 +				            numTries = 1000;
 17.5006 +
 17.5007 +				            int ret = lua_pcall(LUA, 0, 0, 0);
 17.5008 +				            if (ret != 0)
 17.5009 +				            {
 17.5010 +				                // This is grounds for trashing the function
 17.5011 +				                // Note: This must be done before the messagebox pops up,
 17.5012 +				                //       otherwise the messagebox will cause a paint event which causes a weird
 17.5013 +				                //       infinite call sequence that makes Snes9x silently exit with error code 3,
 17.5014 +				                //       if a Lua GUI function crashes. (nitsuja)
 17.5015 +				                lua_pushnil(LUA);
 17.5016 +				                lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
 17.5017 +
 17.5018 +//#if (defined(WIN32) && !defined(SDL))
 17.5019 +//			info_print(info_uid, lua_tostring(LUA, -1)); //AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua Error
 17.5020 +// in GUI function", MB_OK);
 17.5021 +//#else
 17.5022 +//			fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(LUA, -1));
 17.5023 +//#endif
 17.5024 +				                printerror(LUA, -1);
 17.5025 +							}
 17.5026 +						}
 17.5027 +
 17.5028 +				        // And wreak the stack
 17.5029 +				        lua_settop(LUA, 0);
 17.5030 +
 17.5031 +				        if (!gui_used)
 17.5032 +							return;
 17.5033 +
 17.5034 +				        gui_used = false;
 17.5035 +
 17.5036 +				        int x, y;
 17.5037 +
 17.5038 +				        //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3;
 17.5039 +				        int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
 17.5040 +
 17.5041 +				        if (width > LUA_SCREEN_WIDTH)
 17.5042 +							width = LUA_SCREEN_WIDTH;
 17.5043 +				        if (height > LUA_SCREEN_HEIGHT)
 17.5044 +							height = LUA_SCREEN_HEIGHT;
 17.5045 +
 17.5046 +				        GetColorFunc getColor;
 17.5047 +				        SetColorFunc setColor;
 17.5048 +				        getColorIOFunc(systemColorDepth, &getColor, &setColor);
 17.5049 +
 17.5050 +				        for (y = 0; y < height; y++)
 17.5051 +				        {
 17.5052 +				            uint8 *scr = &screen[y * pitch];
 17.5053 +				            for (x = 0; x < width; x++, scr += systemColorDepth / 8)
 17.5054 +				            {
 17.5055 +				                const uint8 gui_alpha = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 3];
 17.5056 +				                if (gui_alpha == 0)
 17.5057 +				                {
 17.5058 +				                    // do nothing
 17.5059 +				                    continue;
 17.5060 +								}
 17.5061 +
 17.5062 +				                const uint8 gui_red	  = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 2];
 17.5063 +				                const uint8 gui_green = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 1];
 17.5064 +				                const uint8 gui_blue  = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4];
 17.5065 +				                int			red, green, blue;
 17.5066 +
 17.5067 +				                if (gui_alpha == 255)
 17.5068 +				                {
 17.5069 +				                    // direct copy
 17.5070 +				                    red	  = gui_red;
 17.5071 +				                    green = gui_green;
 17.5072 +				                    blue  = gui_blue;
 17.5073 +								}
 17.5074 +				                else
 17.5075 +				                {
 17.5076 +				                    // alpha-blending
 17.5077 +				                    uint8 scr_red, scr_green, scr_blue;
 17.5078 +				                    getColor(scr, &scr_red, &scr_green, &scr_blue);
 17.5079 +				                    red	  = (((int)gui_red - scr_red) * gui_alpha / 255 + scr_red) & 255;
 17.5080 +				                    green = (((int)gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255;
 17.5081 +				                    blue  = (((int)gui_blue - scr_blue) * gui_alpha / 255 + scr_blue) & 255;
 17.5082 +								}
 17.5083 +
 17.5084 +				                setColor(scr, (uint8) red, (uint8) green, (uint8) blue);
 17.5085 +							}
 17.5086 +						}
 17.5087 +
 17.5088 +				        return;
 17.5089 +					}
 17.5090 +
 17.5091 +				    void VBALuaClearGui(void)
 17.5092 +				    {
 17.5093 +				        gui_used = false;
 17.5094 +					}
 17.5095 +
 17.5096 +				    lua_State *VBAGetLuaState()
 17.5097 +				    {
 17.5098 +				        return LUA;
 17.5099 +					}
 17.5100 +
 17.5101 +				    char *VBAGetLuaScriptName()
 17.5102 +				    {
 17.5103 +				        return luaScriptName;
 17.5104 +					}
 17.5105 +
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/common/memgzio.c	Sun Mar 04 14:33:52 2012 -0600
    18.3 @@ -0,0 +1,791 @@
    18.4 +/* gzio.c -- IO on .gz files
    18.5 + * Copyright (C) 1995-2002 Jean-loup Gailly.
    18.6 + * For conditions of distribution and use, see copyright notice in zlib.h
    18.7 + *
    18.8 + * Compile this file with -DNO_DEFLATE to avoid the compression code.
    18.9 + */
   18.10 +
   18.11 +/* memgzio.c - IO on .gz files in memory
   18.12 + * Adapted from original gzio.c from zlib library by Forgotten
   18.13 + */
   18.14 +
   18.15 +/* @(#) $Id: memgzio.c,v 1.5 2006/06/06 21:04:20 spacy51 Exp $ */
   18.16 +
   18.17 +#include <stdio.h>
   18.18 +#include <stdarg.h>
   18.19 +#include <stdlib.h>
   18.20 +#include <string.h>
   18.21 +#include <errno.h>
   18.22 +
   18.23 +#include "memgzio.h"
   18.24 +
   18.25 +#ifndef local
   18.26 +#define local static
   18.27 +#endif
   18.28 +
   18.29 +#ifndef DEF_MEM_LEVEL
   18.30 +#  define DEF_MEM_LEVEL 8
   18.31 +#endif
   18.32 +
   18.33 +#ifndef OS_CODE
   18.34 +#define OS_CODE 3
   18.35 +#endif
   18.36 +
   18.37 +#ifndef zmemcpy
   18.38 +#define zmemcpy memcpy
   18.39 +#endif
   18.40 +
   18.41 +/*struct internal_state {int dummy;};*/ /* for buggy compilers */
   18.42 +
   18.43 +#ifndef Z_BUFSIZE
   18.44 +#  ifdef MAXSEG_64K
   18.45 +#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
   18.46 +#  else
   18.47 +#    define Z_BUFSIZE 16384
   18.48 +#  endif
   18.49 +#endif
   18.50 +#ifndef Z_PRINTF_BUFSIZE
   18.51 +#  define Z_PRINTF_BUFSIZE 4096
   18.52 +#endif
   18.53 +
   18.54 +#define ALLOC(size) malloc(size)
   18.55 +#define TRYFREE(p) \
   18.56 +	{if (p)                            \
   18.57 +		 free(p);}
   18.58 +
   18.59 +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
   18.60 +
   18.61 +/* gzip flag byte */
   18.62 +#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
   18.63 +#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
   18.64 +#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
   18.65 +#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
   18.66 +#define COMMENT      0x10 /* bit 4 set: file comment present */
   18.67 +#define RESERVED     0xE0 /* bits 5..7: reserved */
   18.68 +
   18.69 +typedef struct _MemFile
   18.70 +{
   18.71 +	char *memory;
   18.72 +	char *next;
   18.73 +	int   available;
   18.74 +	int   error;
   18.75 +	char  mode;
   18.76 +} MEMFILE;
   18.77 +
   18.78 +typedef struct mem_stream
   18.79 +{
   18.80 +	z_stream stream;
   18.81 +	int      z_err;   /* error code for last stream operation */
   18.82 +	int      z_eof;   /* set if end of input file */
   18.83 +	MEMFILE *file;    /* memoru file */
   18.84 +	Byte *   inbuf;   /* input buffer */
   18.85 +	Byte *   outbuf;  /* output buffer */
   18.86 +	uLong    crc;     /* crc32 of uncompressed data */
   18.87 +	char *   msg;     /* error message */
   18.88 +	int      transparent; /* 1 if input file is not a .gz file */
   18.89 +	char     mode;    /* 'w' or 'r' */
   18.90 +	long     startpos; /* start of compressed data in file (header skipped) */
   18.91 +} mem_stream;
   18.92 +
   18.93 +local gzFile gz_open      OF((char *memory, const int available, const char *mode));
   18.94 +local int do_flush        OF((gzFile file, int flush));
   18.95 +local int get_byte     OF((mem_stream *s));
   18.96 +local void check_header OF((mem_stream *s));
   18.97 +local int destroy      OF((mem_stream *s));
   18.98 +local void putLong      OF((MEMFILE *file, uLong x));
   18.99 +local uLong getLong      OF((mem_stream *s));
  18.100 +
  18.101 +local MEMFILE *memOpen(char *memory, int available, char mode)
  18.102 +{
  18.103 +	MEMFILE *f;
  18.104 +
  18.105 +	if (available <= 8)
  18.106 +		return NULL;
  18.107 +
  18.108 +	if (mode != 'w' && mode != 'r')
  18.109 +		return NULL;
  18.110 +
  18.111 +	f = (MEMFILE *)malloc(sizeof(MEMFILE));
  18.112 +
  18.113 +	f->memory = memory;
  18.114 +	f->mode   = mode;
  18.115 +	f->error  = 0;
  18.116 +
  18.117 +	if (mode == 'w')
  18.118 +	{
  18.119 +		f->available         = available - 8;
  18.120 +		f->next              = memory + 8;
  18.121 +		memory[0]            = 'V';
  18.122 +		memory[1]            = 'B';
  18.123 +		memory[2]            = 'A';
  18.124 +		memory[3]            = ' ';
  18.125 +		*((int *)(memory+4)) = 0;
  18.126 +	}
  18.127 +	else
  18.128 +	{
  18.129 +		if (memory[0] != 'V' || memory[1] != 'B' || memory[2] != 'A' ||
  18.130 +		    memory[3] != ' ')
  18.131 +		{
  18.132 +			free(f);
  18.133 +			return NULL;
  18.134 +		}
  18.135 +		f->available = *((int *)(memory+4));
  18.136 +		f->next      = memory+8;
  18.137 +	}
  18.138 +
  18.139 +	return f;
  18.140 +}
  18.141 +
  18.142 +local size_t memWrite(const void *buffer, size_t size, size_t count,
  18.143 +                      MEMFILE *file)
  18.144 +{
  18.145 +	size_t total = size*count;
  18.146 +
  18.147 +	if (file->mode != 'w')
  18.148 +	{
  18.149 +		file->error = 1;
  18.150 +		return 0;
  18.151 +	}
  18.152 +
  18.153 +	if (total > (size_t)file->available)
  18.154 +	{
  18.155 +		total = file->available;
  18.156 +	}
  18.157 +	memcpy(file->next, buffer, total);
  18.158 +	file->available -= (int)total;
  18.159 +	file->next      += total;
  18.160 +	return total;
  18.161 +}
  18.162 +
  18.163 +local size_t memRead(void *buffer, size_t size, size_t count,
  18.164 +                     MEMFILE *file)
  18.165 +{
  18.166 +	size_t total = size*count;
  18.167 +
  18.168 +	if (file->mode != 'r')
  18.169 +	{
  18.170 +		file->error = 1;
  18.171 +		return 0;
  18.172 +	}
  18.173 +
  18.174 +	if (file->available == 0)
  18.175 +		return -1;
  18.176 +
  18.177 +	if (total > (size_t)file->available)
  18.178 +	{
  18.179 +		total = file->available;
  18.180 +	}
  18.181 +	memcpy(buffer, file->next, total);
  18.182 +	file->available -= (int)total;
  18.183 +	file->next      += total;
  18.184 +	return total;
  18.185 +}
  18.186 +
  18.187 +local int memPutc(int c, MEMFILE *file)
  18.188 +{
  18.189 +	if (file->mode != 'w')
  18.190 +	{
  18.191 +		file->error = 1;
  18.192 +		return -1;
  18.193 +	}
  18.194 +
  18.195 +	if (file->available >= 1)
  18.196 +	{
  18.197 +		*file->next++ = c;
  18.198 +		file->available--;
  18.199 +	}
  18.200 +	else
  18.201 +		return -1;
  18.202 +
  18.203 +	return c;
  18.204 +}
  18.205 +
  18.206 +local long memTell(MEMFILE *f)
  18.207 +{
  18.208 +	return (long)(f->next - f->memory) - 8;
  18.209 +}
  18.210 +
  18.211 +local int memError(MEMFILE *f)
  18.212 +{
  18.213 +	return f->error;
  18.214 +}
  18.215 +
  18.216 +local int memClose(MEMFILE *f)
  18.217 +{
  18.218 +	if (f->mode == 'w')
  18.219 +	{
  18.220 +		*((int *)(f->memory+4)) = memTell(f);
  18.221 +	}
  18.222 +	free(f);
  18.223 +	return 0;
  18.224 +}
  18.225 +
  18.226 +local int memPrintf(MEMFILE *f, const char *format, ...)
  18.227 +{
  18.228 +	char    buffer[80];
  18.229 +	va_list list;
  18.230 +	int     len;
  18.231 +
  18.232 +	va_start(list, format);
  18.233 +	len = vsprintf(buffer, format, list);
  18.234 +	va_end(list);
  18.235 +
  18.236 +	return (int)memWrite(buffer, 1, len, f);
  18.237 +}
  18.238 +
  18.239 +/* ===========================================================================
  18.240 +     Opens a gzip (.gz) file for reading or writing. The mode parameter
  18.241 +   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
  18.242 +   or path name (if fd == -1).
  18.243 +     gz_open return NULL if the file could not be opened or if there was
  18.244 +   insufficient memory to allocate the (de)compression state; errno
  18.245 +   can be checked to distinguish the two cases (if errno is zero, the
  18.246 +   zlib error is Z_MEM_ERROR).
  18.247 + */
  18.248 +local gzFile gz_open(memory, available, mode)
  18.249 +char *memory;
  18.250 +const int   available;
  18.251 +const char *mode;
  18.252 +{
  18.253 +	int         err;
  18.254 +	int         level    = Z_DEFAULT_COMPRESSION; /* compression level */
  18.255 +	int         strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
  18.256 +	char *      p        = (char *)mode;
  18.257 +	mem_stream *s;
  18.258 +	char        fmode[80]; /* copy of mode, without the compression level */
  18.259 +	char *      m = fmode;
  18.260 +
  18.261 +	s = (mem_stream *)ALLOC(sizeof(mem_stream));
  18.262 +	if (!s)
  18.263 +		return Z_NULL;
  18.264 +
  18.265 +	s->stream.zalloc   = (alloc_func)0;
  18.266 +	s->stream.zfree    = (free_func)0;
  18.267 +	s->stream.opaque   = (voidpf)0;
  18.268 +	s->stream.next_in  = s->inbuf = Z_NULL;
  18.269 +	s->stream.next_out = s->outbuf = Z_NULL;
  18.270 +	s->stream.avail_in = s->stream.avail_out = 0;
  18.271 +	s->z_err           = Z_OK;
  18.272 +	s->z_eof           = 0;
  18.273 +	s->crc             = crc32(0L, Z_NULL, 0);
  18.274 +	s->msg             = NULL;
  18.275 +	s->transparent     = 0;
  18.276 +	s->file            = NULL;
  18.277 +
  18.278 +	s->mode = '\0';
  18.279 +	do
  18.280 +	{
  18.281 +		if (*p == 'r')
  18.282 +			s->mode = 'r';
  18.283 +		if (*p == 'w' || *p == 'a')
  18.284 +			s->mode = 'w';
  18.285 +		if (*p >= '0' && *p <= '9')
  18.286 +		{
  18.287 +			level = *p - '0';
  18.288 +		}
  18.289 +		else if (*p == 'f')
  18.290 +		{
  18.291 +			strategy = Z_FILTERED;
  18.292 +		}
  18.293 +		else if (*p == 'h')
  18.294 +		{
  18.295 +			strategy = Z_HUFFMAN_ONLY;
  18.296 +		}
  18.297 +		else
  18.298 +		{
  18.299 +			*m++ = *p; /* copy the mode */
  18.300 +		}
  18.301 +	}
  18.302 +	while (*p++ && m != fmode + sizeof(fmode));
  18.303 +	if (s->mode == '\0')
  18.304 +		return destroy(s), (gzFile)Z_NULL;
  18.305 +
  18.306 +	if (s->mode == 'w')
  18.307 +	{
  18.308 +#ifdef NO_DEFLATE
  18.309 +		err = Z_STREAM_ERROR;
  18.310 +#else
  18.311 +		err = deflateInit2(&(s->stream), level,
  18.312 +		                   Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
  18.313 +		/* windowBits is passed < 0 to suppress zlib header */
  18.314 +
  18.315 +		s->stream.next_out = s->outbuf = (Byte *)ALLOC(Z_BUFSIZE);
  18.316 +#endif
  18.317 +		if (err != Z_OK || s->outbuf == Z_NULL)
  18.318 +		{
  18.319 +			return destroy(s), (gzFile)Z_NULL;
  18.320 +		}
  18.321 +	}
  18.322 +	else
  18.323 +	{
  18.324 +		s->stream.next_in = s->inbuf = (Byte *)ALLOC(Z_BUFSIZE);
  18.325 +
  18.326 +		err = inflateInit2(&(s->stream), -MAX_WBITS);
  18.327 +		/* windowBits is passed < 0 to tell that there is no zlib header.
  18.328 +		 * Note that in this case inflate *requires* an extra "dummy" byte
  18.329 +		 * after the compressed stream in order to complete decompression and
  18.330 +		 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
  18.331 +		 * present after the compressed stream.
  18.332 +		 */
  18.333 +		if (err != Z_OK || s->inbuf == Z_NULL)
  18.334 +		{
  18.335 +			return destroy(s), (gzFile)Z_NULL;
  18.336 +		}
  18.337 +	}
  18.338 +	s->stream.avail_out = Z_BUFSIZE;
  18.339 +
  18.340 +	errno   = 0;
  18.341 +	s->file = memOpen(memory, available, s->mode);
  18.342 +
  18.343 +	if (s->file == NULL)
  18.344 +	{
  18.345 +		return destroy(s), (gzFile)Z_NULL;
  18.346 +	}
  18.347 +
  18.348 +	if (s->mode == 'w')
  18.349 +	{
  18.350 +		/* Write a very simple .gz header:
  18.351 +		 */
  18.352 +		memPrintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
  18.353 +		          Z_DEFLATED, 0 /*flags*/, 0, 0, 0, 0 /*time*/, 0 /*xflags*/, OS_CODE);
  18.354 +		s->startpos = 10L;
  18.355 +		/* We use 10L instead of ftell(s->file) to because ftell causes an
  18.356 +		 * fflush on some systems. This version of the library doesn't use
  18.357 +		 * startpos anyway in write mode, so this initialization is not
  18.358 +		 * necessary.
  18.359 +		 */
  18.360 +	}
  18.361 +	else
  18.362 +	{
  18.363 +		check_header(s); /* skip the .gz header */
  18.364 +		s->startpos = (memTell(s->file) - s->stream.avail_in);
  18.365 +	}
  18.366 +
  18.367 +	return (gzFile)s;
  18.368 +}
  18.369 +
  18.370 +/* ===========================================================================
  18.371 +     Opens a gzip (.gz) file for reading or writing.
  18.372 + */
  18.373 +gzFile ZEXPORT memgzopen(memory, available, mode)
  18.374 +char *memory;
  18.375 +int         available;
  18.376 +const char *mode;
  18.377 +{
  18.378 +	return gz_open(memory, available, mode);
  18.379 +}
  18.380 +
  18.381 +/* ===========================================================================
  18.382 +     Read a byte from a mem_stream; update next_in and avail_in. Return EOF
  18.383 +   for end of file.
  18.384 +   IN assertion: the stream s has been sucessfully opened for reading.
  18.385 + */
  18.386 +local int get_byte(s)
  18.387 +mem_stream *s;
  18.388 +{
  18.389 +	if (s->z_eof)
  18.390 +		return EOF;
  18.391 +	if (s->stream.avail_in == 0)
  18.392 +	{
  18.393 +		errno = 0;
  18.394 +		s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file);
  18.395 +		if (s->stream.avail_in == 0)
  18.396 +		{
  18.397 +			s->z_eof = 1;
  18.398 +			if (memError(s->file))
  18.399 +				s->z_err = Z_ERRNO;
  18.400 +			return EOF;
  18.401 +		}
  18.402 +		s->stream.next_in = s->inbuf;
  18.403 +	}
  18.404 +	s->stream.avail_in--;
  18.405 +	return *(s->stream.next_in)++;
  18.406 +}
  18.407 +
  18.408 +/* ===========================================================================
  18.409 +      Check the gzip header of a mem_stream opened for reading. Set the stream
  18.410 +    mode to transparent if the gzip magic header is not present; set s->err
  18.411 +    to Z_DATA_ERROR if the magic header is present but the rest of the header
  18.412 +    is incorrect.
  18.413 +    IN assertion: the stream s has already been created sucessfully;
  18.414 +       s->stream.avail_in is zero for the first time, but may be non-zero
  18.415 +       for concatenated .gz files.
  18.416 + */
  18.417 +local void check_header(s)
  18.418 +mem_stream *s;
  18.419 +{
  18.420 +	int  method; /* method byte */
  18.421 +	int  flags; /* flags byte */
  18.422 +	uInt len;
  18.423 +	int  c;
  18.424 +
  18.425 +	/* Check the gzip magic header */
  18.426 +	for (len = 0; len < 2; len++)
  18.427 +	{
  18.428 +		c = get_byte(s);
  18.429 +		if (c != gz_magic[len])
  18.430 +		{
  18.431 +			if (len != 0)
  18.432 +				s->stream.avail_in++, s->stream.next_in--;
  18.433 +			if (c != EOF)
  18.434 +			{
  18.435 +				s->stream.avail_in++, s->stream.next_in--;
  18.436 +				s->transparent = 1;
  18.437 +			}
  18.438 +			s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
  18.439 +			return;
  18.440 +		}
  18.441 +	}
  18.442 +	method = get_byte(s);
  18.443 +	flags  = get_byte(s);
  18.444 +	if (method != Z_DEFLATED || (flags & RESERVED) != 0)
  18.445 +	{
  18.446 +		s->z_err = Z_DATA_ERROR;
  18.447 +		return;
  18.448 +	}
  18.449 +
  18.450 +	/* Discard time, xflags and OS code: */
  18.451 +	for (len = 0; len < 6; len++)
  18.452 +		(void)get_byte(s);
  18.453 +
  18.454 +	if ((flags & EXTRA_FIELD) != 0)   /* skip the extra field */
  18.455 +	{
  18.456 +		len  =  (uInt)get_byte(s);
  18.457 +		len += ((uInt)get_byte(s))<<8;
  18.458 +		/* len is garbage if EOF but the loop below will quit anyway */
  18.459 +		while (len-- != 0 && get_byte(s) != EOF)
  18.460 +			;
  18.461 +	}
  18.462 +	if ((flags & ORIG_NAME) != 0)   /* skip the original file name */
  18.463 +	{
  18.464 +		while ((c = get_byte(s)) != 0 && c != EOF)
  18.465 +			;
  18.466 +	}
  18.467 +	if ((flags & COMMENT) != 0)     /* skip the .gz file comment */
  18.468 +	{
  18.469 +		while ((c = get_byte(s)) != 0 && c != EOF)
  18.470 +			;
  18.471 +	}
  18.472 +	if ((flags & HEAD_CRC) != 0)    /* skip the header crc */
  18.473 +	{
  18.474 +		for (len = 0; len < 2; len++)
  18.475 +			(void)get_byte(s);
  18.476 +	}
  18.477 +	s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
  18.478 +}
  18.479 +
  18.480 +/* ===========================================================================
  18.481 + * Cleanup then free the given mem_stream. Return a zlib error code.
  18.482 +   Try freeing in the reverse order of allocations.
  18.483 + */
  18.484 +local int destroy(s)
  18.485 +mem_stream *s;
  18.486 +{
  18.487 +	int err = Z_OK;
  18.488 +
  18.489 +	if (!s)
  18.490 +		return Z_STREAM_ERROR;
  18.491 +
  18.492 +	TRYFREE(s->msg);
  18.493 +
  18.494 +	if (s->stream.state != NULL)
  18.495 +	{
  18.496 +		if (s->mode == 'w')
  18.497 +		{
  18.498 +#ifdef NO_DEFLATE
  18.499 +			err = Z_STREAM_ERROR;
  18.500 +#else
  18.501 +			err = deflateEnd(&(s->stream));
  18.502 +#endif
  18.503 +		}
  18.504 +		else if (s->mode == 'r')
  18.505 +		{
  18.506 +			err = inflateEnd(&(s->stream));
  18.507 +		}
  18.508 +	}
  18.509 +	if (s->file != NULL && memClose(s->file))
  18.510 +	{
  18.511 +#ifdef ESPIPE
  18.512 +		if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
  18.513 +#endif
  18.514 +		err = Z_ERRNO;
  18.515 +	}
  18.516 +	if (s->z_err < 0)
  18.517 +		err = s->z_err;
  18.518 +
  18.519 +	TRYFREE(s->inbuf);
  18.520 +	TRYFREE(s->outbuf);
  18.521 +	TRYFREE(s);
  18.522 +	return err;
  18.523 +}
  18.524 +
  18.525 +/* ===========================================================================
  18.526 +     Reads the given number of uncompressed bytes from the compressed file.
  18.527 +   gzread returns the number of bytes actually read (0 for end of file).
  18.528 + */
  18.529 +int ZEXPORT memgzread(file, buf, len)
  18.530 +gzFile file;
  18.531 +voidp    buf;
  18.532 +unsigned len;
  18.533 +{
  18.534 +	mem_stream *s     = (mem_stream *)file;
  18.535 +	Bytef *     start = (Bytef *)buf; /* starting point for crc computation */
  18.536 +	Byte *      next_out; /* == stream.next_out but not forced far (for MSDOS) */
  18.537 +
  18.538 +	if (s == NULL || s->mode != 'r')
  18.539 +		return Z_STREAM_ERROR;
  18.540 +
  18.541 +	if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
  18.542 +		return -1;
  18.543 +	if (s->z_err == Z_STREAM_END)
  18.544 +		return 0;                            /* EOF */
  18.545 +
  18.546 +	next_out = (Byte *)buf;
  18.547 +	s->stream.next_out  = (Bytef *)buf;
  18.548 +	s->stream.avail_out = len;
  18.549 +
  18.550 +	while (s->stream.avail_out != 0)
  18.551 +	{
  18.552 +		if (s->transparent)
  18.553 +		{
  18.554 +			/* Copy first the lookahead bytes: */
  18.555 +			uInt n = s->stream.avail_in;
  18.556 +			if (n > s->stream.avail_out)
  18.557 +				n = s->stream.avail_out;
  18.558 +			if (n > 0)
  18.559 +			{
  18.560 +				zmemcpy(s->stream.next_out, s->stream.next_in, n);
  18.561 +				next_out += n;
  18.562 +				s->stream.next_out   = next_out;
  18.563 +				s->stream.next_in   += n;
  18.564 +				s->stream.avail_out -= n;
  18.565 +				s->stream.avail_in  -= n;
  18.566 +			}
  18.567 +			if (s->stream.avail_out > 0)
  18.568 +			{
  18.569 +				s->stream.avail_out -= (uInt)memRead(next_out, 1, s->stream.avail_out, s->file);
  18.570 +			}
  18.571 +			len -= s->stream.avail_out;
  18.572 +			s->stream.total_in  += (uLong)len;
  18.573 +			s->stream.total_out += (uLong)len;
  18.574 +			if (len == 0)
  18.575 +				s->z_eof = 1;
  18.576 +			return (int)len;
  18.577 +		}
  18.578 +		if (s->stream.avail_in == 0 && !s->z_eof)
  18.579 +		{
  18.580 +			errno = 0;
  18.581 +			s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file);
  18.582 +			if (s->stream.avail_in == 0)
  18.583 +			{
  18.584 +				s->z_eof = 1;
  18.585 +				if (memError(s->file))
  18.586 +				{
  18.587 +					s->z_err = Z_ERRNO;
  18.588 +					break;
  18.589 +				}
  18.590 +			}
  18.591 +			s->stream.next_in = s->inbuf;
  18.592 +		}
  18.593 +		s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
  18.594 +
  18.595 +		if (s->z_err == Z_STREAM_END)
  18.596 +		{
  18.597 +			/* Check CRC and original size */
  18.598 +			s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
  18.599 +			start  = s->stream.next_out;
  18.600 +
  18.601 +			if (getLong(s) != s->crc)
  18.602 +			{
  18.603 +				s->z_err = Z_DATA_ERROR;
  18.604 +			}
  18.605 +			else
  18.606 +			{
  18.607 +				(void)getLong(s);
  18.608 +				/* The uncompressed length returned by above getlong() may
  18.609 +				 * be different from s->stream.total_out) in case of
  18.610 +				 * concatenated .gz files. Check for such files:
  18.611 +				 */
  18.612 +				check_header(s);
  18.613 +				if (s->z_err == Z_OK)
  18.614 +				{
  18.615 +					uLong total_in  = s->stream.total_in;
  18.616 +					uLong total_out = s->stream.total_out;
  18.617 +
  18.618 +					inflateReset(&(s->stream));
  18.619 +					s->stream.total_in  = total_in;
  18.620 +					s->stream.total_out = total_out;
  18.621 +					s->crc = crc32(0L, Z_NULL, 0);
  18.622 +				}
  18.623 +			}
  18.624 +		}
  18.625 +		if (s->z_err != Z_OK || s->z_eof)
  18.626 +			break;
  18.627 +	}
  18.628 +	s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
  18.629 +
  18.630 +	return (int)(len - s->stream.avail_out);
  18.631 +}
  18.632 +
  18.633 +#ifndef NO_DEFLATE
  18.634 +/* ===========================================================================
  18.635 +     Writes the given number of uncompressed bytes into the compressed file.
  18.636 +   gzwrite returns the number of bytes actually written (0 in case of error).
  18.637 + */
  18.638 +int ZEXPORT memgzwrite(file, buf, len)
  18.639 +gzFile file;
  18.640 +const voidp buf;
  18.641 +unsigned    len;
  18.642 +{
  18.643 +	mem_stream *s = (mem_stream *)file;
  18.644 +
  18.645 +	if (s == NULL || s->mode != 'w')
  18.646 +		return Z_STREAM_ERROR;
  18.647 +
  18.648 +	s->stream.next_in  = (Bytef *)buf;
  18.649 +	s->stream.avail_in = len;
  18.650 +
  18.651 +	while (s->stream.avail_in != 0)
  18.652 +	{
  18.653 +		if (s->stream.avail_out == 0)
  18.654 +		{
  18.655 +			s->stream.next_out = s->outbuf;
  18.656 +			if (memWrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE)
  18.657 +			{
  18.658 +				s->z_err = Z_ERRNO;
  18.659 +				break;
  18.660 +			}
  18.661 +			s->stream.avail_out = Z_BUFSIZE;
  18.662 +		}
  18.663 +		s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
  18.664 +		if (s->z_err != Z_OK)
  18.665 +			break;
  18.666 +	}
  18.667 +	s->crc = crc32(s->crc, (const Bytef *)buf, len);
  18.668 +
  18.669 +	return (int)(len - s->stream.avail_in);
  18.670 +}
  18.671 +#endif
  18.672 +/* ===========================================================================
  18.673 +     Flushes all pending output into the compressed file. The parameter
  18.674 +   flush is as in the deflate() function.
  18.675 + */
  18.676 +local int do_flush(file, flush)
  18.677 +gzFile file;
  18.678 +int flush;
  18.679 +{
  18.680 +	uInt        len;
  18.681 +	int         done = 0;
  18.682 +	mem_stream *s    = (mem_stream *)file;
  18.683 +
  18.684 +	if (s == NULL || s->mode != 'w')
  18.685 +		return Z_STREAM_ERROR;
  18.686 +
  18.687 +	s->stream.avail_in = 0; /* should be zero already anyway */
  18.688 +
  18.689 +	for (;;)
  18.690 +	{
  18.691 +		len = Z_BUFSIZE - s->stream.avail_out;
  18.692 +
  18.693 +		if (len != 0)
  18.694 +		{
  18.695 +			if ((uInt)memWrite(s->outbuf, 1, len, s->file) != len)
  18.696 +			{
  18.697 +				s->z_err = Z_ERRNO;
  18.698 +				return Z_ERRNO;
  18.699 +			}
  18.700 +			s->stream.next_out  = s->outbuf;
  18.701 +			s->stream.avail_out = Z_BUFSIZE;
  18.702 +		}
  18.703 +		if (done)
  18.704 +			break;
  18.705 +		s->z_err = deflate(&(s->stream), flush);
  18.706 +
  18.707 +		/* Ignore the second of two consecutive flushes: */
  18.708 +		if (len == 0 && s->z_err == Z_BUF_ERROR)
  18.709 +			s->z_err = Z_OK;
  18.710 +
  18.711 +		/* deflate has finished flushing only when it hasn't used up
  18.712 +		 * all the available space in the output buffer:
  18.713 +		 */
  18.714 +		done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
  18.715 +
  18.716 +		if (s->z_err != Z_OK && s->z_err != Z_STREAM_END)
  18.717 +			break;
  18.718 +	}
  18.719 +	return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
  18.720 +}
  18.721 +
  18.722 +/* ===========================================================================
  18.723 +   Outputs a long in LSB order to the given file
  18.724 + */
  18.725 +local void putLong(file, x)
  18.726 +MEMFILE *file;
  18.727 +uLong x;
  18.728 +{
  18.729 +	int n;
  18.730 +	for (n = 0; n < 4; n++)
  18.731 +	{
  18.732 +		memPutc((int)(x & 0xff), file);
  18.733 +		x >>= 8;
  18.734 +	}
  18.735 +}
  18.736 +
  18.737 +/* ===========================================================================
  18.738 +   Reads a long in LSB order from the given mem_stream. Sets z_err in case
  18.739 +   of error.
  18.740 + */
  18.741 +local uLong getLong(s)
  18.742 +mem_stream *s;
  18.743 +{
  18.744 +	uLong x = (uLong)get_byte(s);
  18.745 +	int   c;
  18.746 +
  18.747 +	x += ((uLong)get_byte(s))<<8;
  18.748 +	x += ((uLong)get_byte(s))<<16;
  18.749 +	c  = get_byte(s);
  18.750 +	if (c == EOF)
  18.751 +		s->z_err = Z_DATA_ERROR;
  18.752 +	x += ((uLong)c)<<24;
  18.753 +	return x;
  18.754 +}
  18.755 +
  18.756 +/* ===========================================================================
  18.757 +     Flushes all pending output if necessary, closes the compressed file
  18.758 +   and deallocates all the (de)compression state.
  18.759 + */
  18.760 +int ZEXPORT memgzclose(file)
  18.761 +gzFile file;
  18.762 +{
  18.763 +	int         err;
  18.764 +	mem_stream *s = (mem_stream *)file;
  18.765 +
  18.766 +	if (s == NULL)
  18.767 +		return Z_STREAM_ERROR;
  18.768 +
  18.769 +	if (s->mode == 'w')
  18.770 +	{
  18.771 +#ifdef NO_DEFLATE
  18.772 +		return Z_STREAM_ERROR;
  18.773 +#else
  18.774 +		err = do_flush(file, Z_FINISH);
  18.775 +		if (err != Z_OK)
  18.776 +			return destroy((mem_stream *)file);
  18.777 +
  18.778 +		putLong(s->file, s->crc);
  18.779 +		putLong(s->file, s->stream.total_in);
  18.780 +#endif
  18.781 +	}
  18.782 +	return destroy((mem_stream *)file);
  18.783 +}
  18.784 +
  18.785 +long ZEXPORT memtell(file)
  18.786 +gzFile file;
  18.787 +{
  18.788 +	mem_stream *s = (mem_stream *)file;
  18.789 +
  18.790 +	if (s == NULL)
  18.791 +		return Z_STREAM_ERROR;
  18.792 +
  18.793 +	return memTell(s->file);
  18.794 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/common/memgzio.h	Sun Mar 04 14:33:52 2012 -0600
    19.3 @@ -0,0 +1,23 @@
    19.4 +#ifndef MEMGZIO_H
    19.5 +#define MEMGZIO_H
    19.6 +
    19.7 +/* gzio.c -- IO on .gz files
    19.8 + * Copyright (C) 1995-2002 Jean-loup Gailly.
    19.9 + * For conditions of distribution and use, see copyright notice in zlib.h
   19.10 + *
   19.11 + * Compile this file with -DNO_DEFLATE to avoid the compression code.
   19.12 + */
   19.13 +
   19.14 +/* memgzio.c - IO on .gz files in memory
   19.15 + * Adapted from original gzio.c from zlib library by Forgotten
   19.16 + */
   19.17 +
   19.18 +#include <zlib.h>
   19.19 +
   19.20 +gzFile ZEXPORT memgzopen(char *memory, int available, const char *mode);
   19.21 +int ZEXPORT memgzread(gzFile file, voidp buf, unsigned len);
   19.22 +int ZEXPORT memgzwrite(gzFile file, const voidp buf, unsigned len);
   19.23 +int ZEXPORT memgzclose(gzFile file);
   19.24 +long ZEXPORT memtell(gzFile file);
   19.25 +
   19.26 +#endif // MEMGZIO_H
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/common/movie.cpp	Sun Mar 04 14:33:52 2012 -0600
    20.3 @@ -0,0 +1,1772 @@
    20.4 +#include <cstdio>
    20.5 +#include <cctype>
    20.6 +#include <cstdlib>
    20.7 +#include <cstring>
    20.8 +#include <cassert>
    20.9 +#include <algorithm>
   20.10 +
   20.11 +using namespace std;
   20.12 +
   20.13 +#ifdef HAVE_STRINGS_H
   20.14 +#   include <strings.h>
   20.15 +#endif
   20.16 +
   20.17 +#if defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP)
   20.18 +#   include <unistd.h>
   20.19 +#   include <sys/types.h>
   20.20 +#   include <sys/stat.h>
   20.21 +#   include <climits>
   20.22 +#   define stricmp strcasecmp
   20.23 +// FIXME: this is wrong, but we don't want buffer overflow
   20.24 +#   if defined _MAX_PATH
   20.25 +#       undef _MAX_PATH
   20.26 +//#       define _MAX_PATH 128
   20.27 +#       define _MAX_PATH 260
   20.28 +#   endif
   20.29 +#endif
   20.30 +
   20.31 +#ifdef WIN32
   20.32 +#   include <io.h>
   20.33 +#   ifndef W_OK
   20.34 +#       define W_OK 2
   20.35 +#   endif
   20.36 +#   define ftruncate chsize
   20.37 +#endif
   20.38 +
   20.39 +#include "movie.h"
   20.40 +#include "System.h"
   20.41 +#include "../gba/GBA.h"
   20.42 +#include "../gba/GBAGlobals.h"
   20.43 +#include "../gba/RTC.h"
   20.44 +#include "../gb/GB.h"
   20.45 +#include "../gb/gbGlobals.h"
   20.46 +#include "inputGlobal.h"
   20.47 +#include "unzip.h"
   20.48 +#include "Util.h"
   20.49 +
   20.50 +#include "vbalua.h"
   20.51 +
   20.52 +#if (defined(WIN32) && !defined(SDL))
   20.53 +#   include "../win32/stdafx.h"
   20.54 +#   include "../win32/MainWnd.h"
   20.55 +#   include "../win32/VBA.h"
   20.56 +#   include "../win32/WinMiscUtil.h"
   20.57 +#endif
   20.58 +
   20.59 +extern int emulating; // from system.cpp
   20.60 +extern u16 currentButtons[4];     // from System.cpp
   20.61 +extern u16 lastKeys;
   20.62 +
   20.63 +SMovie Movie;
   20.64 +bool   loadingMovie = false;
   20.65 +
   20.66 +// probably bad idea to have so many global variables, but I hate to recompile almost everything after editing VBA.h
   20.67 +bool autoConvertMovieWhenPlaying = false;
   20.68 +
   20.69 +static u16 initialInputs[4] = { 0 };
   20.70 +
   20.71 +static bool resetSignaled	  = false;
   20.72 +static bool resetSignaledLast = false;
   20.73 +
   20.74 +static int prevEmulatorType, prevBorder, prevWinBorder, prevBorderAuto;
   20.75 +
   20.76 +// little-endian integer pop/push functions:
   20.77 +static inline uint32 Pop32(const uint8 * &ptr)
   20.78 +{
   20.79 +	uint32 v = (ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24));
   20.80 +	ptr += 4;
   20.81 +	return v;
   20.82 +}
   20.83 +
   20.84 +static inline uint16 Pop16(const uint8 * &ptr) /* const version */
   20.85 +{
   20.86 +	uint16 v = (ptr[0] | (ptr[1] << 8));
   20.87 +	ptr += 2;
   20.88 +	return v;
   20.89 +}
   20.90 +
   20.91 +static inline uint16 Pop16(uint8 * &ptr) /* non-const version */
   20.92 +{
   20.93 +	uint16 v = (ptr[0] | (ptr[1] << 8));
   20.94 +	ptr += 2;
   20.95 +	return v;
   20.96 +}
   20.97 +
   20.98 +static inline uint8 Pop8(const uint8 * &ptr)
   20.99 +{
  20.100 +	return *(ptr)++;
  20.101 +}
  20.102 +
  20.103 +static inline void Push32(uint32 v, uint8 * &ptr)
  20.104 +{
  20.105 +	ptr[0] = (uint8)(v & 0xff);
  20.106 +	ptr[1] = (uint8)((v >> 8) & 0xff);
  20.107 +	ptr[2] = (uint8)((v >> 16) & 0xff);
  20.108 +	ptr[3] = (uint8)((v >> 24) & 0xff);
  20.109 +	ptr	  += 4;
  20.110 +}
  20.111 +
  20.112 +static inline void Push16(uint16 v, uint8 * &ptr)
  20.113 +{
  20.114 +	ptr[0] = (uint8)(v & 0xff);
  20.115 +	ptr[1] = (uint8)((v >> 8) & 0xff);
  20.116 +	ptr	  += 2;
  20.117 +}
  20.118 +
  20.119 +static inline void Push8(uint8 v, uint8 * &ptr)
  20.120 +{
  20.121 +	*ptr++ = v;
  20.122 +}
  20.123 +
  20.124 +// little-endian integer read/write functions:
  20.125 +static inline uint16 Read16(const uint8 *ptr)
  20.126 +{
  20.127 +	return ptr[0] | (ptr[1] << 8);
  20.128 +}
  20.129 +
  20.130 +static inline void Write16(uint16 v, uint8 *ptr)
  20.131 +{
  20.132 +	ptr[0] = uint8(v & 0xff);
  20.133 +	ptr[1] = uint8((v >> 8) & 0xff);
  20.134 +}
  20.135 +
  20.136 +static long file_length(FILE *fp)
  20.137 +{
  20.138 +	long cur_pos = ftell(fp);
  20.139 +	fseek(fp, 0, SEEK_END);
  20.140 +	long length = ftell(fp);
  20.141 +	fseek(fp, cur_pos, SEEK_SET);
  20.142 +	return length;
  20.143 +}
  20.144 +
  20.145 +static int bytes_per_frame(SMovie &mov)
  20.146 +{
  20.147 +	int num_controllers = 0;
  20.148 +
  20.149 +	for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i)
  20.150 +		if (mov.header.controllerFlags & MOVIE_CONTROLLER(i))
  20.151 +			++num_controllers;
  20.152 +
  20.153 +	return CONTROLLER_DATA_SIZE * num_controllers;
  20.154 +}
  20.155 +
  20.156 +static void reserve_buffer_space(uint32 space_needed)
  20.157 +{
  20.158 +	if (space_needed > Movie.inputBufferSize)
  20.159 +	{
  20.160 +		uint32 ptr_offset	= Movie.inputBufferPtr - Movie.inputBuffer;
  20.161 +		uint32 alloc_chunks = (space_needed - 1) / BUFFER_GROWTH_SIZE + 1;
  20.162 +		uint32 old_size     = Movie.inputBufferSize;
  20.163 +		Movie.inputBufferSize = BUFFER_GROWTH_SIZE * alloc_chunks;
  20.164 +		Movie.inputBuffer	  = (uint8 *)realloc(Movie.inputBuffer, Movie.inputBufferSize);
  20.165 +		// FIXME: this only fixes the random input problem during dma-frame-skip, but not the skip
  20.166 +		memset(Movie.inputBuffer + old_size, 0, Movie.inputBufferSize - old_size);
  20.167 +		Movie.inputBufferPtr  = Movie.inputBuffer + ptr_offset;
  20.168 +	}
  20.169 +}
  20.170 +
  20.171 +static int read_movie_header(FILE *file, SMovie &movie)
  20.172 +{
  20.173 +	assert(file != NULL);
  20.174 +	assert(VBM_HEADER_SIZE == sizeof(SMovieFileHeader)); // sanity check on the header type definition
  20.175 +
  20.176 +	uint8 headerData [VBM_HEADER_SIZE];
  20.177 +
  20.178 +	if (fread(headerData, 1, VBM_HEADER_SIZE, file) != VBM_HEADER_SIZE)
  20.179 +		return MOVIE_WRONG_FORMAT;  // if we failed to read in all VBM_HEADER_SIZE bytes of the header
  20.180 +
  20.181 +	const uint8 *	  ptr	 = headerData;
  20.182 +	SMovieFileHeader &header = movie.header;
  20.183 +
  20.184 +	header.magic = Pop32(ptr);
  20.185 +	if (header.magic != VBM_MAGIC)
  20.186 +		return MOVIE_WRONG_FORMAT;
  20.187 +
  20.188 +	header.version = Pop32(ptr);
  20.189 +	if (header.version != VBM_VERSION)
  20.190 +		return MOVIE_WRONG_VERSION;
  20.191 +
  20.192 +	header.uid = Pop32(ptr);
  20.193 +	header.length_frames  = Pop32(ptr) + 1;    // HACK: add 1 to the length for compatibility
  20.194 +	header.rerecord_count = Pop32(ptr);
  20.195 +
  20.196 +	header.startFlags	   = Pop8(ptr);
  20.197 +	header.controllerFlags = Pop8(ptr);
  20.198 +	header.typeFlags	   = Pop8(ptr);
  20.199 +	header.optionFlags	   = Pop8(ptr);
  20.200 +
  20.201 +	header.saveType		  = Pop32(ptr);
  20.202 +	header.flashSize	  = Pop32(ptr);
  20.203 +	header.gbEmulatorType = Pop32(ptr);
  20.204 +
  20.205 +	for (int i = 0; i < 12; i++)
  20.206 +		header.romTitle[i] = Pop8(ptr);
  20.207 +
  20.208 +	header.minorVersion = Pop8(ptr);
  20.209 +
  20.210 +	header.romCRC = Pop8(ptr);
  20.211 +	header.romOrBiosChecksum = Pop16(ptr);
  20.212 +	header.romGameCode		 = Pop32(ptr);
  20.213 +
  20.214 +	header.offset_to_savestate		 = Pop32(ptr);
  20.215 +	header.offset_to_controller_data = Pop32(ptr);
  20.216 +
  20.217 +	return MOVIE_SUCCESS;
  20.218 +}
  20.219 +
  20.220 +static void write_movie_header(FILE *file, const SMovie &movie)
  20.221 +{
  20.222 +	assert(ftell(file) == 0); // we assume file points to beginning of movie file
  20.223 +
  20.224 +	uint8  headerData [VBM_HEADER_SIZE];
  20.225 +	uint8 *ptr = headerData;
  20.226 +	const SMovieFileHeader &header = movie.header;
  20.227 +
  20.228 +	Push32(header.magic, ptr);
  20.229 +	Push32(header.version, ptr);
  20.230 +
  20.231 +	Push32(header.uid, ptr);
  20.232 +	Push32(header.length_frames - 1, ptr);     // HACK: reduce the length by 1 for compatibility with certain faulty old tools
  20.233 +	                                           // like TME
  20.234 +	Push32(header.rerecord_count, ptr);
  20.235 +
  20.236 +	Push8(header.startFlags, ptr);
  20.237 +	Push8(header.controllerFlags, ptr);
  20.238 +	Push8(header.typeFlags, ptr);
  20.239 +	Push8(header.optionFlags, ptr);
  20.240 +
  20.241 +	Push32(header.saveType, ptr);
  20.242 +	Push32(header.flashSize, ptr);
  20.243 +	Push32(header.gbEmulatorType, ptr);
  20.244 +
  20.245 +	for (int i = 0; i < 12; ++i)
  20.246 +		Push8(header.romTitle[i], ptr);
  20.247 +
  20.248 +	Push8(header.minorVersion, ptr);
  20.249 +
  20.250 +	Push8(header.romCRC, ptr);
  20.251 +	Push16(header.romOrBiosChecksum, ptr);
  20.252 +	Push32(header.romGameCode, ptr);
  20.253 +
  20.254 +	Push32(header.offset_to_savestate, ptr);
  20.255 +	Push32(header.offset_to_controller_data, ptr);
  20.256 +
  20.257 +	fwrite(headerData, 1, VBM_HEADER_SIZE, file);
  20.258 +}
  20.259 +
  20.260 +static void flush_movie_header()
  20.261 +{
  20.262 +	assert(Movie.file != 0 && "logical error!");
  20.263 +	if (!Movie.file)
  20.264 +		return;
  20.265 +
  20.266 +	long originalPos = ftell(Movie.file);
  20.267 +
  20.268 +	// (over-)write the header
  20.269 +	fseek(Movie.file, 0, SEEK_SET);
  20.270 +	write_movie_header(Movie.file, Movie);
  20.271 +
  20.272 +	fflush(Movie.file);
  20.273 +
  20.274 +	fseek(Movie.file, originalPos, SEEK_SET);
  20.275 +}
  20.276 +
  20.277 +static void flush_movie_frames()
  20.278 +{
  20.279 +	assert(Movie.file && "logical error!");
  20.280 +	if (!Movie.file)
  20.281 +		return;
  20.282 +
  20.283 +	long originalPos = ftell(Movie.file);
  20.284 +
  20.285 +	// overwrite the controller data
  20.286 +	fseek(Movie.file, Movie.header.offset_to_controller_data, SEEK_SET);
  20.287 +	fwrite(Movie.inputBuffer, 1, Movie.bytesPerFrame * Movie.header.length_frames, Movie.file);
  20.288 +
  20.289 +	fflush(Movie.file);
  20.290 +
  20.291 +	fseek(Movie.file, originalPos, SEEK_SET);
  20.292 +}
  20.293 +
  20.294 +static void truncate_movie(long length)
  20.295 +{
  20.296 +	// truncate movie to length
  20.297 +	// NOTE: it's certain that the savestate block is never after the
  20.298 +	//       controller data block, because the VBM format decrees it.
  20.299 +
  20.300 +	assert(Movie.file && length >= 0);
  20.301 +	if (!Movie.file || length < 0)
  20.302 +		return;
  20.303 +
  20.304 +	assert(Movie.header.offset_to_savestate <= Movie.header.offset_to_controller_data);
  20.305 +	if (Movie.header.offset_to_savestate > Movie.header.offset_to_controller_data)
  20.306 +		return;
  20.307 +
  20.308 +	Movie.header.length_frames = length;
  20.309 +	flush_movie_header();
  20.310 +	const long truncLen = long(Movie.header.offset_to_controller_data + Movie.bytesPerFrame * length);
  20.311 +	if (file_length(Movie.file) != truncLen)
  20.312 +	{
  20.313 +		ftruncate(fileno(Movie.file), truncLen);
  20.314 +	}
  20.315 +}
  20.316 +
  20.317 +static void remember_input_state()
  20.318 +{
  20.319 +	for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i)
  20.320 +	{
  20.321 +		if (systemCartridgeType == 0)
  20.322 +		{
  20.323 +			initialInputs[i] = u16(~P1 & 0x03FF);
  20.324 +		}
  20.325 +		else
  20.326 +		{
  20.327 +			extern int32 gbJoymask[4];
  20.328 +			for (int i = 0; i < 4; ++i)
  20.329 +				initialInputs[i] = u16(gbJoymask[i] & 0xFFFF);
  20.330 +		}
  20.331 +	}
  20.332 +}
  20.333 +
  20.334 +static void change_state(MovieState new_state)
  20.335 +{
  20.336 +#if (defined(WIN32) && !defined(SDL))
  20.337 +	theApp.frameSearching	   = false;
  20.338 +	theApp.frameSearchSkipping = false;
  20.339 +#endif
  20.340 +
  20.341 +	if (new_state == MOVIE_STATE_NONE)
  20.342 +	{
  20.343 +		Movie.pauseFrame = -1;
  20.344 +
  20.345 +		if (Movie.state == MOVIE_STATE_NONE)
  20.346 +			return;
  20.347 +
  20.348 +		truncate_movie(Movie.header.length_frames);
  20.349 +
  20.350 +		fclose(Movie.file);
  20.351 +		Movie.file		   = NULL;
  20.352 +		Movie.currentFrame = 0;
  20.353 +#if (defined(WIN32) && !defined(SDL))
  20.354 +		// undo changes to border settings
  20.355 +		{
  20.356 +			gbBorderOn = prevBorder;
  20.357 +			theApp.winGbBorderOn = prevWinBorder;
  20.358 +			gbBorderAutomatic	 = prevBorderAuto;
  20.359 +			systemGbBorderOn();
  20.360 +		}
  20.361 +#endif
  20.362 +		gbEmulatorType = prevEmulatorType;
  20.363 +
  20.364 +		extern int32 gbDMASpeedVersion;
  20.365 +		gbDMASpeedVersion = 1;
  20.366 +
  20.367 +		extern int32 gbEchoRAMFixOn;
  20.368 +		gbEchoRAMFixOn = 1;
  20.369 +
  20.370 +		gbNullInputHackTempEnabled = gbNullInputHackEnabled;
  20.371 +
  20.372 +		if (Movie.inputBuffer)
  20.373 +		{
  20.374 +			free(Movie.inputBuffer);
  20.375 +			Movie.inputBuffer = NULL;
  20.376 +		}
  20.377 +	}
  20.378 +	else if (new_state == MOVIE_STATE_PLAY)
  20.379 +	{
  20.380 +		assert(Movie.file);
  20.381 +
  20.382 +		// this would cause problems if not dealt with
  20.383 +		if (Movie.currentFrame >= Movie.header.length_frames)
  20.384 +		{
  20.385 +			new_state = MOVIE_STATE_END;
  20.386 +			Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames;
  20.387 +		}
  20.388 +	}
  20.389 +	else if (new_state == MOVIE_STATE_RECORD)
  20.390 +	{
  20.391 +		assert(Movie.file);
  20.392 +
  20.393 +		// this would cause problems if not dealt with
  20.394 +		if (Movie.currentFrame > Movie.header.length_frames)
  20.395 +		{
  20.396 +			new_state = MOVIE_STATE_END;
  20.397 +			Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames;
  20.398 +		}
  20.399 +
  20.400 +		fseek(Movie.file, Movie.header.offset_to_controller_data + Movie.bytesPerFrame * Movie.currentFrame, SEEK_SET);
  20.401 +	}
  20.402 +
  20.403 +	if (new_state == MOVIE_STATE_END && Movie.state != MOVIE_STATE_END)
  20.404 +	{
  20.405 +#if defined(SDL)		
  20.406 +		systemClearJoypads();
  20.407 +#endif
  20.408 +		systemScreenMessage("Movie end");
  20.409 +	}
  20.410 +
  20.411 +	Movie.state = new_state;
  20.412 +
  20.413 +	// checking for movie end
  20.414 +	bool willPause = false;
  20.415 +
  20.416 +	// if the movie's been set to pause at a certain frame
  20.417 +	if (Movie.state != MOVIE_STATE_NONE && Movie.pauseFrame >= 0 && Movie.currentFrame == (uint32)Movie.pauseFrame)
  20.418 +	{
  20.419 +		Movie.pauseFrame = -1;
  20.420 +		willPause		 = true;
  20.421 +	}
  20.422 +
  20.423 +	if (Movie.state == MOVIE_STATE_END)
  20.424 +	{
  20.425 +		if (Movie.currentFrame == Movie.header.length_frames)
  20.426 +		{
  20.427 +#if (defined(WIN32) && !defined(SDL))
  20.428 +			if (theApp.movieOnEndPause)
  20.429 +			{
  20.430 +				willPause = true;
  20.431 +			}
  20.432 +#else
  20.433 +			// SDL FIXME
  20.434 +#endif
  20.435 +
  20.436 +#if (defined(WIN32) && !defined(SDL))
  20.437 +			switch (theApp.movieOnEndBehavior)
  20.438 +			{
  20.439 +			case 1:
  20.440 +				// the old behavior
  20.441 +				//VBAMovieRestart();
  20.442 +				break;
  20.443 +			case 2:
  20.444 +#else
  20.445 +			// SDL FIXME
  20.446 +#endif
  20.447 +				if (Movie.RecordedThisSession)
  20.448 +				{
  20.449 +					// if user has been recording this movie since the last time it started playing,
  20.450 +					// they probably don't want the movie to end now during playback,
  20.451 +					// so switch back to recording when it reaches the end
  20.452 +					VBAMovieSwitchToRecording();
  20.453 +					systemScreenMessage("Recording resumed");
  20.454 +					willPause = true;
  20.455 +				}
  20.456 +#if (defined(WIN32) && !defined(SDL))
  20.457 +				break;
  20.458 +			case 3:
  20.459 +				// keep open
  20.460 +				break;
  20.461 +			case 0:
  20.462 +				// fall through
  20.463 +			default:
  20.464 +				// close movie
  20.465 +				//VBAMovieStop(false);
  20.466 +				break;
  20.467 +			}
  20.468 +#else
  20.469 +				// SDL FIXME
  20.470 +#endif
  20.471 +		}
  20.472 +#if 1
  20.473 +		else if (Movie.currentFrame > Movie.header.length_frames)
  20.474 +		{
  20.475 +#if (defined(WIN32) && !defined(SDL))
  20.476 +			switch (theApp.movieOnEndBehavior)
  20.477 +			{
  20.478 +			case 1:
  20.479 +				// FIXME: this should be delayed till the current frame ends
  20.480 +				VBAMovieRestart();
  20.481 +				break;
  20.482 +			case 2:
  20.483 +				// nothing
  20.484 +				break;
  20.485 +			case 3:
  20.486 +				// keep open
  20.487 +				break;
  20.488 +			case 0:
  20.489 +				// fall through
  20.490 +			default:
  20.491 +				// close movie
  20.492 +				VBAMovieStop(false);
  20.493 +				break;
  20.494 +			}
  20.495 +#else
  20.496 +			// SDLFIXME
  20.497 +#endif
  20.498 +		}
  20.499 +#endif
  20.500 +	} // end if (Movie.state == MOVIE_STATE_END)
  20.501 +
  20.502 +	if (willPause)
  20.503 +	{
  20.504 +		systemSetPause(true);
  20.505 +	}
  20.506 +}
  20.507 +
  20.508 +void VBAMovieInit()
  20.509 +{
  20.510 +	memset(&Movie, 0, sizeof(Movie));
  20.511 +	Movie.state		 = MOVIE_STATE_NONE;
  20.512 +	Movie.pauseFrame = -1;
  20.513 +
  20.514 +	resetSignaled	  = false;
  20.515 +	resetSignaledLast = false;
  20.516 +}
  20.517 +
  20.518 +void VBAMovieGetRomInfo(const SMovie &movieInfo, char romTitle [12], uint32 &romGameCode, uint16 &checksum, uint8 &crc)
  20.519 +{
  20.520 +	if (systemCartridgeType == 0) // GBA
  20.521 +	{
  20.522 +		extern u8 *bios, *rom;
  20.523 +		memcpy(romTitle, &rom[0xa0], 12); // GBA TITLE
  20.524 +		memcpy(&romGameCode, &rom[0xac], 4); // GBA ROM GAME CODE
  20.525 +		if ((movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0)
  20.526 +			checksum = utilCalcBIOSChecksum(bios, 4);  // GBA BIOS CHECKSUM
  20.527 +		else
  20.528 +			checksum = 0;
  20.529 +		crc = rom[0xbd]; // GBA ROM CRC
  20.530 +	}
  20.531 +	else // non-GBA
  20.532 +	{
  20.533 +		extern u8 *gbRom;
  20.534 +		memcpy(romTitle, &gbRom[0x134], 12); // GB TITLE (note this can be 15 but is truncated to 12)
  20.535 +		romGameCode = (uint32)gbRom[0x146]; // GB ROM UNIT CODE
  20.536 +
  20.537 +		checksum = (gbRom[0x14e] << 8) | gbRom[0x14f]; // GB ROM CHECKSUM, read from big-endian
  20.538 +		crc		 = gbRom[0x14d]; // GB ROM CRC
  20.539 +	}
  20.540 +}
  20.541 +
  20.542 +#ifdef SDL
  20.543 +static void GetBatterySaveName(char *buffer)
  20.544 +{
  20.545 +	extern char batteryDir[2048], filename[2048];     // from SDL.cpp
  20.546 +	extern char *sdlGetFilename(char *name);     // from SDL.cpp
  20.547 +	if (batteryDir[0])
  20.548 +		sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
  20.549 +	else
  20.550 +		sprintf(buffer, "%s.sav", filename);
  20.551 +}
  20.552 +
  20.553 +#endif
  20.554 +
  20.555 +static void SetPlayEmuSettings()
  20.556 +{
  20.557 +	prevEmulatorType = gbEmulatorType;
  20.558 +	gbEmulatorType	 = Movie.header.gbEmulatorType;
  20.559 +
  20.560 +#if (defined(WIN32) && !defined(SDL))
  20.561 +//    theApp.removeIntros   = false;
  20.562 +	theApp.skipBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0;
  20.563 +	theApp.useBiosFile	= (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0;
  20.564 +#else
  20.565 +	extern int	 saveType, sdlRtcEnable, sdlFlashSize;   // from SDL.cpp
  20.566 +	extern bool8 useBios, skipBios, removeIntros;     // from SDL.cpp
  20.567 +	useBios		 = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0;
  20.568 +	skipBios	 = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0;
  20.569 +	removeIntros = false /*(Movie.header.optionFlags & MOVIE_SETTING_REMOVEINTROS) != 0*/;
  20.570 +#endif
  20.571 +
  20.572 +	extern void SetPrefetchHack(bool);
  20.573 +	if (systemCartridgeType == 0)    // lag disablement applies only to GBA
  20.574 +		SetPrefetchHack((Movie.header.optionFlags & MOVIE_SETTING_LAGHACK) != 0);
  20.575 +
  20.576 +	gbNullInputHackTempEnabled = ((Movie.header.optionFlags & MOVIE_SETTING_GBINPUTHACK) != 0);
  20.577 +
  20.578 +	// some GB/GBC games depend on the sound rate, so just use the highest one
  20.579 +	systemSoundSetQuality(1);
  20.580 +	useOldFrameTiming = false;
  20.581 +
  20.582 +	extern int32 gbDMASpeedVersion;
  20.583 +	if ((Movie.header.optionFlags & MOVIE_SETTING_GBCFF55FIX) != 0)
  20.584 +		gbDMASpeedVersion = 1;
  20.585 +	else
  20.586 +		gbDMASpeedVersion = 0;     // old CGB HDMA5 timing was used
  20.587 +
  20.588 +	extern int32 gbEchoRAMFixOn;
  20.589 +	if ((Movie.header.optionFlags & MOVIE_SETTING_GBECHORAMFIX) != 0)
  20.590 +		gbEchoRAMFixOn = 1;
  20.591 +	else
  20.592 +		gbEchoRAMFixOn = 0;
  20.593 +
  20.594 +#if (defined(WIN32) && !defined(SDL))
  20.595 +	rtcEnable((Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0);
  20.596 +	theApp.winSaveType	= Movie.header.saveType;
  20.597 +	theApp.winFlashSize = Movie.header.flashSize;
  20.598 +
  20.599 +	prevBorder	   = gbBorderOn;
  20.600 +	prevWinBorder  = theApp.winGbBorderOn;
  20.601 +	prevBorderAuto = gbBorderAutomatic;
  20.602 +	if ((gbEmulatorType == 2 || gbEmulatorType == 5)
  20.603 +	    && !theApp.hideMovieBorder) // games played in SGB mode can have a border
  20.604 +	{
  20.605 +		gbBorderOn = true;
  20.606 +		theApp.winGbBorderOn = true;
  20.607 +		gbBorderAutomatic	 = false;
  20.608 +	}
  20.609 +	else
  20.610 +	{
  20.611 +		gbBorderOn = false;
  20.612 +		theApp.winGbBorderOn = false;
  20.613 +		gbBorderAutomatic	 = false;
  20.614 +		if (theApp.hideMovieBorder)
  20.615 +		{
  20.616 +			theApp.hideMovieBorder = false;
  20.617 +			prevBorder = false;     // it might be expected behaviour that it stays hidden after the movie
  20.618 +		}
  20.619 +	}
  20.620 +	systemGbBorderOn();
  20.621 +#else
  20.622 +	sdlRtcEnable = (Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0;
  20.623 +	saveType	 = Movie.header.saveType;
  20.624 +	sdlFlashSize = Movie.header.flashSize;
  20.625 +#endif
  20.626 +}
  20.627 +
  20.628 +static void HardResetAndSRAMClear()
  20.629 +{
  20.630 +#if (defined(WIN32) && !defined(SDL))
  20.631 +	winEraseBatteryFile(); // delete the damn SRAM file and keep it from being resurrected from RAM
  20.632 +	MainWnd *temp = ((MainWnd *)theApp.m_pMainWnd);
  20.633 +	if (!temp->winFileRun(true)) // restart running the game
  20.634 +	{
  20.635 +		temp->winFileClose();
  20.636 +	}
  20.637 +#else
  20.638 +	char fname [1024];
  20.639 +	GetBatterySaveName(fname);
  20.640 +	remove(fname);     // delete the damn SRAM file
  20.641 +
  20.642 +	// Henceforth, emuCleanUp means "clear out SRAM"
  20.643 +	//theEmulator.emuCleanUp();     // keep it from being resurrected from RAM <--This is wrong, it'll deallocate all variables --Felipe
  20.644 +
  20.645 +	/// FIXME the correct SDL code to call for a full restart isn't in a function yet
  20.646 +	theEmulator.emuReset(false);
  20.647 +#endif
  20.648 +}
  20.649 +
  20.650 +int VBAMovieOpen(const char *filename, bool8 read_only)
  20.651 +{
  20.652 +	loadingMovie = true;
  20.653 +	uint8 movieReadOnly = read_only ? 1 : 0;
  20.654 +
  20.655 +	FILE * file;
  20.656 +	STREAM stream;
  20.657 +	int	   result;
  20.658 +	int	   fn;
  20.659 +
  20.660 +	char movie_filename[_MAX_PATH];
  20.661 +#ifdef WIN32
  20.662 +	_fullpath(movie_filename, filename, _MAX_PATH);
  20.663 +#else
  20.664 +	// SDL FIXME: convert to fullpath
  20.665 +	strncpy(movie_filename, filename, _MAX_PATH);
  20.666 +	movie_filename[_MAX_PATH - 1] = '\0';
  20.667 +#endif
  20.668 +
  20.669 +	if (movie_filename[0] == '\0')
  20.670 +	{ loadingMovie = false; return MOVIE_FILE_NOT_FOUND; }
  20.671 +
  20.672 +	if (!emulating)
  20.673 +	{ loadingMovie = false; return MOVIE_UNKNOWN_ERROR; }
  20.674 +
  20.675 +//	bool alreadyOpen = (Movie.file != NULL && _stricmp(movie_filename, Movie.filename) == 0);
  20.676 +
  20.677 +//	if (alreadyOpen)
  20.678 +	change_state(MOVIE_STATE_NONE);     // have to stop current movie before trying to re-open it
  20.679 +
  20.680 +	if (!(file = fopen(movie_filename, "rb+")))
  20.681 +		if (!(file = fopen(movie_filename, "rb")))
  20.682 +		{ loadingMovie = false; return MOVIE_FILE_NOT_FOUND; }
  20.683 +	//else
  20.684 +	//	movieReadOnly = 2; // we have to open the movie twice, no need to do this both times
  20.685 +
  20.686 +//	if (!alreadyOpen)
  20.687 +//		change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one
  20.688 +//
  20.689 +//	if (!(file = fopen(movie_filename, "rb+")))
  20.690 +//		if(!(file = fopen(movie_filename, "rb")))
  20.691 +//			{loadingMovie = false; return MOVIE_FILE_NOT_FOUND;}
  20.692 +//		else
  20.693 +//			movieReadOnly = 2;
  20.694 +
  20.695 +	// clear out the current movie
  20.696 +	VBAMovieInit();
  20.697 +
  20.698 +	// read header
  20.699 +	if ((result = read_movie_header(file, Movie)) != MOVIE_SUCCESS)
  20.700 +	{
  20.701 +		fclose(file);
  20.702 +		{ loadingMovie = false; return result; }
  20.703 +	}
  20.704 +
  20.705 +	// set emulator settings that make the movie more likely to stay synchronized
  20.706 +	SetPlayEmuSettings();
  20.707 +
  20.708 +//	extern bool systemLoadBIOS();
  20.709 +//	if (!systemLoadBIOS())
  20.710 +//	{ loadingMovie = false; return MOVIE_UNKNOWN_ERROR; }
  20.711 +
  20.712 +	// read the metadata / author info from file
  20.713 +	fread(Movie.authorInfo, 1, MOVIE_METADATA_SIZE, file);
  20.714 +	fn = dup(fileno(file)); // XXX: why does this fail?? it returns -1 but errno == 0
  20.715 +	fclose(file);
  20.716 +
  20.717 +	// apparently this lseek is necessary
  20.718 +	lseek(fn, Movie.header.offset_to_savestate, SEEK_SET);
  20.719 +	if (!(stream = utilGzReopen(fn, "rb")))
  20.720 +		if (!(stream = utilGzOpen(movie_filename, "rb")))
  20.721 +		{ loadingMovie = false; return MOVIE_FILE_NOT_FOUND; }
  20.722 +		else
  20.723 +			fn = dup(fileno(file));
  20.724 +	// in case the above dup failed but opening the file normally doesn't fail
  20.725 +
  20.726 +	if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT)
  20.727 +	{
  20.728 +		// load the snapshot
  20.729 +		result = theEmulator.emuReadStateFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT;
  20.730 +
  20.731 +		// FIXME: Kludge for conversion
  20.732 +		remember_input_state();
  20.733 +	}
  20.734 +	else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM)
  20.735 +	{
  20.736 +		// 'soft' reset:
  20.737 +		theEmulator.emuReset(false);
  20.738 +
  20.739 +		// load the SRAM
  20.740 +		result = theEmulator.emuReadBatteryFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT;
  20.741 +	}
  20.742 +	else
  20.743 +	{
  20.744 +		HardResetAndSRAMClear();
  20.745 +	}
  20.746 +
  20.747 +	utilGzClose(stream);
  20.748 +
  20.749 +	if (result != MOVIE_SUCCESS)
  20.750 +	{ loadingMovie = false; return result; }
  20.751 +
  20.752 +//	if (!(file = fopen(movie_filename, /*read_only ? "rb" :*/ "rb+"))) // want to be able to switch out of read-only later
  20.753 +//	{
  20.754 +//		if(!Movie.readOnly || !(file = fopen(movie_filename, "rb"))) // try read-only if failed
  20.755 +//			return MOVIE_FILE_NOT_FOUND;
  20.756 +//	}
  20.757 +	if (!(file = fopen(movie_filename, "rb+")))
  20.758 +		if (!(file = fopen(movie_filename, "rb")))
  20.759 +		{ loadingMovie = false; return MOVIE_FILE_NOT_FOUND; }
  20.760 +		else
  20.761 +			movieReadOnly = 2;
  20.762 +
  20.763 +	// recalculate length of movie from the file size
  20.764 +	Movie.bytesPerFrame = bytes_per_frame(Movie);
  20.765 +	fseek(file, 0, SEEK_END);
  20.766 +	long fileSize = ftell(file);
  20.767 +	Movie.header.length_frames = (fileSize - Movie.header.offset_to_controller_data) / Movie.bytesPerFrame;
  20.768 +
  20.769 +	if (fseek(file, Movie.header.offset_to_controller_data, SEEK_SET))
  20.770 +	{ fclose(file); loadingMovie = false; return MOVIE_WRONG_FORMAT; }
  20.771 +
  20.772 +	strcpy(Movie.filename, movie_filename);
  20.773 +	Movie.file = file;
  20.774 +	Movie.inputBufferPtr	  = Movie.inputBuffer;
  20.775 +	Movie.currentFrame		  = 0;
  20.776 +	Movie.readOnly			  = movieReadOnly;
  20.777 +	Movie.RecordedThisSession = false;
  20.778 +
  20.779 +	// read controller data
  20.780 +	uint32 to_read = Movie.bytesPerFrame * Movie.header.length_frames;
  20.781 +	reserve_buffer_space(to_read);
  20.782 +	fread(Movie.inputBuffer, 1, to_read, file);
  20.783 +
  20.784 +	change_state(MOVIE_STATE_PLAY);
  20.785 +
  20.786 +	char messageString[64] = "Movie ";
  20.787 +	bool converted		   = false;
  20.788 +	if (autoConvertMovieWhenPlaying)
  20.789 +	{
  20.790 +		int result = VBAMovieConvertCurrent();
  20.791 +		if (result == MOVIE_SUCCESS)
  20.792 +			strcat(messageString, "converted and ");
  20.793 +		else if (result == MOVIE_WRONG_VERSION)
  20.794 +			strcat(messageString, "higher revision ");
  20.795 +	}
  20.796 +
  20.797 +	if (Movie.state == MOVIE_STATE_PLAY)
  20.798 +		strcat(messageString, "replaying ");
  20.799 +	else
  20.800 +		strcat(messageString, "finished ");
  20.801 +	if (Movie.readOnly)
  20.802 +		strcat(messageString, "(read)");
  20.803 +	else
  20.804 +		strcat(messageString, "(edit)");
  20.805 +	systemScreenMessage(messageString);
  20.806 +
  20.807 +	VBAUpdateButtonPressDisplay();
  20.808 +	VBAUpdateFrameCountDisplay();
  20.809 +	systemRefreshScreen();
  20.810 +
  20.811 +	{ loadingMovie = false; return MOVIE_SUCCESS; }
  20.812 +}
  20.813 +
  20.814 +static void SetRecordEmuSettings()
  20.815 +{
  20.816 +	Movie.header.optionFlags = 0;
  20.817 +#if (defined(WIN32) && !defined(SDL))
  20.818 +	if (theApp.useBiosFile)
  20.819 +		Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE;
  20.820 +	if (theApp.skipBiosFile)
  20.821 +		Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE;
  20.822 +	if (rtcIsEnabled())
  20.823 +		Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE;
  20.824 +	Movie.header.saveType  = theApp.winSaveType;
  20.825 +	Movie.header.flashSize = theApp.winFlashSize;
  20.826 +#else
  20.827 +	extern int	 saveType, sdlRtcEnable, sdlFlashSize;   // from SDL.cpp
  20.828 +	extern bool8 useBios, skipBios;     // from SDL.cpp
  20.829 +	if (useBios)
  20.830 +		Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE;
  20.831 +	if (skipBios)
  20.832 +		Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE;
  20.833 +	if (sdlRtcEnable)
  20.834 +		Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE;
  20.835 +	Movie.header.saveType  = saveType;
  20.836 +	Movie.header.flashSize = sdlFlashSize;
  20.837 +#endif
  20.838 +	prevEmulatorType = Movie.header.gbEmulatorType = gbEmulatorType;
  20.839 +
  20.840 +	if (!memLagTempEnabled)
  20.841 +		Movie.header.optionFlags |= MOVIE_SETTING_LAGHACK;
  20.842 +
  20.843 +	if (gbNullInputHackTempEnabled)
  20.844 +		Movie.header.optionFlags |= MOVIE_SETTING_GBINPUTHACK;
  20.845 +
  20.846 +	Movie.header.optionFlags |= MOVIE_SETTING_GBCFF55FIX;
  20.847 +	extern int32 gbDMASpeedVersion;
  20.848 +	gbDMASpeedVersion = 1;
  20.849 +
  20.850 +	Movie.header.optionFlags |= MOVIE_SETTING_GBECHORAMFIX;
  20.851 +	extern int32 gbEchoRAMFixOn;
  20.852 +	gbEchoRAMFixOn = 1;
  20.853 +
  20.854 +	// some GB/GBC games depend on the sound rate, so just use the highest one
  20.855 +	systemSoundSetQuality(1);
  20.856 +
  20.857 +	useOldFrameTiming = false;
  20.858 +
  20.859 +#if (defined(WIN32) && !defined(SDL))
  20.860 +//    theApp.removeIntros   = false;
  20.861 +
  20.862 +	prevBorder	   = gbBorderOn;
  20.863 +	prevWinBorder  = theApp.winGbBorderOn;
  20.864 +	prevBorderAuto = gbBorderAutomatic;
  20.865 +	if (gbEmulatorType == 2 || gbEmulatorType == 5)     // only games played in SGB mode will have a border
  20.866 +	{
  20.867 +		gbBorderOn = true;
  20.868 +		theApp.winGbBorderOn = true;
  20.869 +		gbBorderAutomatic	 = false;
  20.870 +	}
  20.871 +	else
  20.872 +	{
  20.873 +		gbBorderOn = false;
  20.874 +		theApp.winGbBorderOn = false;
  20.875 +		gbBorderAutomatic	 = false;
  20.876 +	}
  20.877 +	systemGbBorderOn();
  20.878 +#else
  20.879 +	/// SDLFIXME
  20.880 +#endif
  20.881 +}
  20.882 +
  20.883 +uint16 VBAMovieGetCurrentInputOf(int controllerNum, bool normalOnly)
  20.884 +{
  20.885 +	if (controllerNum < 0 || controllerNum >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS)
  20.886 +		return 0;
  20.887 +
  20.888 +	return normalOnly ? (currentButtons[controllerNum] & BUTTON_REGULAR_MASK) : currentButtons[controllerNum];
  20.889 +}
  20.890 +
  20.891 +int VBAMovieCreate(const char *filename, const char *authorInfo, uint8 startFlags, uint8 controllerFlags, uint8 typeFlags)
  20.892 +{
  20.893 +	// make sure at least one controller is enabled
  20.894 +	if ((controllerFlags & MOVIE_CONTROLLERS_ANY_MASK) == 0)
  20.895 +		return MOVIE_WRONG_FORMAT;
  20.896 +
  20.897 +	if (!emulating)
  20.898 +		return MOVIE_UNKNOWN_ERROR;
  20.899 +
  20.900 +	loadingMovie = true;
  20.901 +
  20.902 +	FILE * file;
  20.903 +	STREAM stream;
  20.904 +	int	   fn;
  20.905 +
  20.906 +	char movie_filename [_MAX_PATH];
  20.907 +#ifdef WIN32
  20.908 +	_fullpath(movie_filename, filename, _MAX_PATH);
  20.909 +#else
  20.910 +	// FIXME: convert to fullpath
  20.911 +	strncpy(movie_filename, filename, _MAX_PATH);
  20.912 +	movie_filename[_MAX_PATH - 1] = '\0';
  20.913 +#endif
  20.914 +
  20.915 +	bool alreadyOpen = (Movie.file != NULL && stricmp(movie_filename, Movie.filename) == 0);
  20.916 +
  20.917 +	if (alreadyOpen)
  20.918 +		change_state(MOVIE_STATE_NONE);  // have to stop current movie before trying to re-open it
  20.919 +
  20.920 +	if (movie_filename[0] == '\0')
  20.921 +	{ loadingMovie = false; return MOVIE_FILE_NOT_FOUND; }
  20.922 +
  20.923 +	if (!(file = fopen(movie_filename, "wb")))
  20.924 +	{ loadingMovie = false; return MOVIE_FILE_NOT_FOUND; }
  20.925 +
  20.926 +	if (!alreadyOpen)
  20.927 +		change_state(MOVIE_STATE_NONE);  // stop current movie when we're able to open the other one
  20.928 +
  20.929 +	// clear out the current movie
  20.930 +	VBAMovieInit();
  20.931 +
  20.932 +	// fill in the movie's header
  20.933 +	Movie.header.uid   = (uint32)time(NULL);
  20.934 +	Movie.header.magic = VBM_MAGIC;
  20.935 +	Movie.header.version		 = VBM_VERSION;
  20.936 +	Movie.header.rerecord_count	 = 0;
  20.937 +	Movie.header.length_frames	 = 0;
  20.938 +	Movie.header.startFlags		 = startFlags;
  20.939 +	Movie.header.controllerFlags = controllerFlags;
  20.940 +	Movie.header.typeFlags		 = typeFlags;
  20.941 +	Movie.header.minorVersion	 = VBM_REVISION;
  20.942 +
  20.943 +	// set emulator settings that make the movie more likely to stay synchronized when it's later played back
  20.944 +	SetRecordEmuSettings();
  20.945 +
  20.946 +	// set ROM and BIOS checksums and stuff
  20.947 +	VBAMovieGetRomInfo(Movie, Movie.header.romTitle, Movie.header.romGameCode, Movie.header.romOrBiosChecksum, Movie.header.romCRC);
  20.948 +
  20.949 +	// write the header to file
  20.950 +	write_movie_header(file, Movie);
  20.951 +
  20.952 +	// copy over the metadata / author info
  20.953 +	VBAMovieSetMetadata(authorInfo);
  20.954 +
  20.955 +	// write the metadata / author info to file
  20.956 +	fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file);
  20.957 +
  20.958 +	// write snapshot or SRAM if applicable
  20.959 +	if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT
  20.960 +	    || Movie.header.startFlags & MOVIE_START_FROM_SRAM)
  20.961 +	{
  20.962 +		Movie.header.offset_to_savestate = (uint32)ftell(file);
  20.963 +
  20.964 +		// close the file and reopen it as a stream:
  20.965 +
  20.966 +		fn = dup(fileno(file));
  20.967 +		fclose(file);
  20.968 +
  20.969 +		if (!(stream = utilGzReopen(fn, "ab"))) // append mode to start at end, no seek necessary
  20.970 +		{ loadingMovie = false; return MOVIE_FILE_NOT_FOUND; }
  20.971 +
  20.972 +		// write the save data:
  20.973 +		if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT)
  20.974 +		{
  20.975 +			// save snapshot
  20.976 +			if (!theEmulator.emuWriteStateToStream(stream))
  20.977 +			{
  20.978 +				utilGzClose(stream);
  20.979 +				{ loadingMovie = false; return MOVIE_UNKNOWN_ERROR; }
  20.980 +			}
  20.981 +		}
  20.982 +		else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM)
  20.983 +		{
  20.984 +			// save SRAM
  20.985 +			if (!theEmulator.emuWriteBatteryToStream(stream))
  20.986 +			{
  20.987 +				utilGzClose(stream);
  20.988 +				{ loadingMovie = false; return MOVIE_UNKNOWN_ERROR; }
  20.989 +			}
  20.990 +
  20.991 +			// 'soft' reset:
  20.992 +			theEmulator.emuReset(false);
  20.993 +		}
  20.994 +
  20.995 +		utilGzClose(stream);
  20.996 +
  20.997 +		// reopen the file and seek back to the end
  20.998 +
  20.999 +		if (!(file = fopen(movie_filename, "rb+")))
 20.1000 +		{ loadingMovie = false; return MOVIE_FILE_NOT_FOUND; }
 20.1001 +
 20.1002 +		fseek(file, 0, SEEK_END);
 20.1003 +	}
 20.1004 +	else // no snapshot or SRAM
 20.1005 +	{
 20.1006 +		HardResetAndSRAMClear();
 20.1007 +	}
 20.1008 +
 20.1009 +	Movie.header.offset_to_controller_data = (uint32)ftell(file);
 20.1010 +
 20.1011 +	strcpy(Movie.filename, movie_filename);
 20.1012 +	Movie.file = file;
 20.1013 +	Movie.bytesPerFrame		  = bytes_per_frame(Movie);
 20.1014 +	Movie.inputBufferPtr	  = Movie.inputBuffer;
 20.1015 +	Movie.currentFrame		  = 0;
 20.1016 +	Movie.readOnly			  = false;
 20.1017 +	Movie.RecordedThisSession = true;
 20.1018 +
 20.1019 +	change_state(MOVIE_STATE_RECORD);
 20.1020 +
 20.1021 +	systemScreenMessage("Recording movie...");
 20.1022 +	{ loadingMovie = false; return MOVIE_SUCCESS; }
 20.1023 +}
 20.1024 +
 20.1025 +void VBAUpdateButtonPressDisplay()
 20.1026 +{
 20.1027 +	uint32 keys = currentButtons[0] & BUTTON_REGULAR_RECORDING_MASK;
 20.1028 +
 20.1029 +	const static char KeyMap[]	 =  { 'A', 'B', 's', 'S', '>', '<', '^', 'v', 'R', 'L', '!', '?', '{', '}', 'v', '^' };
 20.1030 +	const static int  KeyOrder[] = { 5, 6, 4, 7, 0, 1, 9, 8, 3, 2, 12, 15, 13, 14, 11, 10 }; // < ^ > v   A B  L R  S s  { = } _
 20.1031 +	                                                                                         // ? !
 20.1032 +	char buffer[256];
 20.1033 +	sprintf(buffer, "                    ");
 20.1034 +
 20.1035 +#ifndef WIN32
 20.1036 +	// don't bother color-coding autofire and such
 20.1037 +	int i;
 20.1038 +	for (i = 0; i < 15; i++)
 20.1039 +	{
 20.1040 +		int j	 = KeyOrder[i];
 20.1041 +		int mask = (1 << (j));
 20.1042 +		buffer[strlen("    ") + i] = ((keys & mask) != 0) ? KeyMap[j] : ' ';
 20.1043 +	}
 20.1044 +
 20.1045 +	systemScreenMessage(buffer, 2, -1);
 20.1046 +#else
 20.1047 +	const bool eraseAll		= !theApp.inputDisplay;
 20.1048 +	uint32	   autoHeldKeys = eraseAll ? 0 : theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK;
 20.1049 +	uint32	   autoFireKeys = eraseAll ? 0 : (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK;
 20.1050 +	uint32	   pressedKeys	= eraseAll ? 0 : keys;
 20.1051 +
 20.1052 +	char colorList[64];
 20.1053 +	memset(colorList, 1, strlen(buffer));
 20.1054 +
 20.1055 +	if (!eraseAll)
 20.1056 +	{
 20.1057 +		for (int i = 0; i < 15; i++)
 20.1058 +		{
 20.1059 +			const int  j		 = KeyOrder[i];
 20.1060 +			const int  mask		 = (1 << (j));
 20.1061 +			bool	   pressed	 = (pressedKeys  & mask) != 0;
 20.1062 +			const bool autoHeld	 = (autoHeldKeys & mask) != 0;
 20.1063 +			const bool autoFired = (autoFireKeys & mask) != 0;
 20.1064 +			const bool erased	 = (lastKeys & mask) != 0 && (!pressed && !autoHeld && !autoFired);
 20.1065 +			extern int textMethod;
 20.1066 +			if (textMethod != 2 && (autoHeld || (autoFired && !pressed) || erased))
 20.1067 +			{
 20.1068 +				int colorNum = 1;     // default is white
 20.1069 +				if (autoHeld)
 20.1070 +					colorNum += (pressed ? 2 : 1);     // yellow if pressed, red if not
 20.1071 +				else if (autoFired)
 20.1072 +					colorNum += 5;     // blue if autofired and not currently pressed
 20.1073 +				else if (erased)
 20.1074 +					colorNum += 8;     // black on black
 20.1075 +
 20.1076 +				colorList[strlen("    ") + i] = colorNum;
 20.1077 +				pressed = true;
 20.1078 +			}
 20.1079 +			buffer[strlen("    ") + i] = pressed ? KeyMap[j] : ' ';
 20.1080 +		}
 20.1081 +	}
 20.1082 +
 20.1083 +	lastKeys  = currentButtons[0];
 20.1084 +	lastKeys |= theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK;
 20.1085 +	lastKeys |= (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK;
 20.1086 +
 20.1087 +	systemScreenMessage(buffer, 2, -1, colorList);
 20.1088 +#endif
 20.1089 +}
 20.1090 +
 20.1091 +void VBAUpdateFrameCountDisplay()
 20.1092 +{
 20.1093 +	const int MAGICAL_NUMBER = 64;  // FIXME: this won't do any better, but only to remind you of sz issues
 20.1094 +	char	  frameDisplayString[MAGICAL_NUMBER];
 20.1095 +	char	  lagFrameDisplayString[MAGICAL_NUMBER];
 20.1096 +	char      extraCountDisplayString[MAGICAL_NUMBER];
 20.1097 +
 20.1098 +#if (defined(WIN32) && !defined(SDL))
 20.1099 +	if (theApp.frameCounter)
 20.1100 +#else
 20.1101 +	/// SDL FIXME
 20.1102 +#endif
 20.1103 +	{
 20.1104 +		switch (Movie.state)
 20.1105 +		{
 20.1106 +		case MOVIE_STATE_PLAY:
 20.1107 +		case MOVIE_STATE_END:
 20.1108 +		{
 20.1109 +			sprintf(frameDisplayString, "%d / %d", Movie.currentFrame, Movie.header.length_frames);
 20.1110 +			if (!Movie.readOnly)
 20.1111 +				strcat(frameDisplayString, " (edit)");
 20.1112 +			break;
 20.1113 +		}
 20.1114 +		case MOVIE_STATE_RECORD:
 20.1115 +		{
 20.1116 +			sprintf(frameDisplayString, "%d (record)", Movie.currentFrame);
 20.1117 +			break;
 20.1118 +		}
 20.1119 +		default:
 20.1120 +		{
 20.1121 +			sprintf(frameDisplayString, "%d (no movie)", systemCounters.frameCount);
 20.1122 +			break;
 20.1123 +		}
 20.1124 +		}
 20.1125 +
 20.1126 +#if (defined(WIN32) && !defined(SDL))
 20.1127 +		if (theApp.lagCounter)
 20.1128 +#else
 20.1129 +		/// SDL FIXME
 20.1130 +#endif
 20.1131 +		{
 20.1132 +//			sprintf(lagFrameDisplayString, " %c %d", systemCounters.laggedLast ? '*' : '|', systemCounters.lagCount);
 20.1133 +			sprintf(lagFrameDisplayString, " | %d%s", systemCounters.lagCount, systemCounters.laggedLast ? " *" : "");
 20.1134 +			strcat(frameDisplayString, lagFrameDisplayString);
 20.1135 +		}
 20.1136 +
 20.1137 +#if (defined(WIN32) && !defined(SDL))
 20.1138 +		if (theApp.extraCounter)
 20.1139 +#else
 20.1140 +		/// SDL FIXME
 20.1141 +#endif
 20.1142 +		{
 20.1143 +			sprintf(extraCountDisplayString, " | %d", systemCounters.frameCount - systemCounters.extraCount);
 20.1144 +			strcat(frameDisplayString, extraCountDisplayString);
 20.1145 +		}
 20.1146 +	}
 20.1147 +#if (defined(WIN32) && !defined(SDL))
 20.1148 +	else
 20.1149 +	{
 20.1150 +		frameDisplayString[0] = '\0';
 20.1151 +	}
 20.1152 +#else
 20.1153 +	/// SDL FIXME
 20.1154 +#endif
 20.1155 +	systemScreenMessage(frameDisplayString, 1, -1);
 20.1156 +}
 20.1157 +
 20.1158 +// this function should only be called once every frame
 20.1159 +void VBAMovieUpdateState()
 20.1160 +{
 20.1161 +	++Movie.currentFrame;
 20.1162 +
 20.1163 +	if (Movie.state == MOVIE_STATE_PLAY)
 20.1164 +	{
 20.1165 +		Movie.inputBufferPtr += Movie.bytesPerFrame;
 20.1166 +		if (Movie.currentFrame >= Movie.header.length_frames)
 20.1167 +		{
 20.1168 +			// the movie ends anyway; what to do next depends on the settings
 20.1169 +			change_state(MOVIE_STATE_END);
 20.1170 +		}
 20.1171 +	}
 20.1172 +	else if (Movie.state == MOVIE_STATE_RECORD)
 20.1173 +	{
 20.1174 +		// use first fseek?
 20.1175 +		fwrite(Movie.inputBufferPtr, 1, Movie.bytesPerFrame, Movie.file);
 20.1176 +		Movie.header.length_frames = Movie.currentFrame;
 20.1177 +		Movie.inputBufferPtr	 += Movie.bytesPerFrame;
 20.1178 +		Movie.RecordedThisSession = true;
 20.1179 +		flush_movie_header();
 20.1180 +	}
 20.1181 +	else if (Movie.state == MOVIE_STATE_END)
 20.1182 +	{
 20.1183 +		change_state(MOVIE_STATE_END);
 20.1184 +	}
 20.1185 +}
 20.1186 +
 20.1187 +void VBAMovieRead(int i, bool /*sensor*/)
 20.1188 +{
 20.1189 +	if (Movie.state != MOVIE_STATE_PLAY)
 20.1190 +		return;
 20.1191 +
 20.1192 +	if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS)
 20.1193 +		return;      // not a controller we're recognizing
 20.1194 +
 20.1195 +	if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i))
 20.1196 +	{
 20.1197 +		currentButtons[i] = Read16(Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i);
 20.1198 +	}
 20.1199 +	else
 20.1200 +	{
 20.1201 +		currentButtons[i] = 0;        // pretend the controller is disconnected
 20.1202 +	}
 20.1203 +
 20.1204 +	if ((currentButtons[i] & BUTTON_MASK_NEW_RESET) != 0)
 20.1205 +		resetSignaled = true;
 20.1206 +}
 20.1207 +
 20.1208 +void VBAMovieWrite(int i, bool /*sensor*/)
 20.1209 +{
 20.1210 +	if (Movie.state != MOVIE_STATE_RECORD)
 20.1211 +		return;
 20.1212 +
 20.1213 +	if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS)
 20.1214 +		return;      // not a controller we're recognizing
 20.1215 +
 20.1216 +	reserve_buffer_space((uint32)((Movie.inputBufferPtr - Movie.inputBuffer) + Movie.bytesPerFrame));
 20.1217 +
 20.1218 +	if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i))
 20.1219 +	{
 20.1220 +		// get the current controller data
 20.1221 +		uint16 buttonData = currentButtons[i];
 20.1222 +
 20.1223 +		// mask away the irrelevent bits
 20.1224 +		buttonData &= BUTTON_REGULAR_MASK | BUTTON_MOTION_MASK;
 20.1225 +
 20.1226 +		// soft-reset "button" for 1 frame if the game is reset while recording
 20.1227 +		if (resetSignaled)
 20.1228 +		{
 20.1229 +			buttonData |= BUTTON_MASK_NEW_RESET;
 20.1230 +		}
 20.1231 +
 20.1232 +		// backward compatibility kludge
 20.1233 +		if (resetSignaledLast)
 20.1234 +		{
 20.1235 +			buttonData |= BUTTON_MASK_OLD_RESET;
 20.1236 +		}
 20.1237 +
 20.1238 +		Write16(buttonData, Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i);
 20.1239 +
 20.1240 +		// and for display
 20.1241 +		currentButtons[i] = buttonData;
 20.1242 +	}
 20.1243 +	else
 20.1244 +	{
 20.1245 +		// pretend the controller is disconnected (otherwise input it gives could cause desync since we're not writing it to the
 20.1246 +		// movie)
 20.1247 +		currentButtons[i] = 0;
 20.1248 +	}
 20.1249 +}
 20.1250 +
 20.1251 +void VBAMovieStop(bool8 suppress_message)
 20.1252 +{
 20.1253 +	if (Movie.state != MOVIE_STATE_NONE)
 20.1254 +	{
 20.1255 +		change_state(MOVIE_STATE_NONE);
 20.1256 +		if (!suppress_message)
 20.1257 +			systemScreenMessage("Movie stop");
 20.1258 +	}
 20.1259 +}
 20.1260 +
 20.1261 +int VBAMovieGetInfo(const char *filename, SMovie *info)
 20.1262 +{
 20.1263 +	assert(info != NULL);
 20.1264 +	if (info == NULL)
 20.1265 +		return -1;
 20.1266 +
 20.1267 +	FILE *	file;
 20.1268 +	int		result;
 20.1269 +	SMovie &local_movie = *info;
 20.1270 +
 20.1271 +	memset(info, 0, sizeof(*info));
 20.1272 +	if (filename[0] == '\0')
 20.1273 +		return MOVIE_FILE_NOT_FOUND;
 20.1274 +	if (!(file = fopen(filename, "rb")))
 20.1275 +		return MOVIE_FILE_NOT_FOUND;
 20.1276 +
 20.1277 +	// read header
 20.1278 +	if ((result = (read_movie_header(file, local_movie))) != MOVIE_SUCCESS)
 20.1279 +	{
 20.1280 +		fclose(file);
 20.1281 +		return result;
 20.1282 +	}
 20.1283 +
 20.1284 +	// read the metadata / author info from file
 20.1285 +	fread(local_movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file);
 20.1286 +
 20.1287 +	strncpy(local_movie.filename, filename, _MAX_PATH);
 20.1288 +	local_movie.filename[_MAX_PATH - 1] = '\0';
 20.1289 +
 20.1290 +	if (Movie.file != NULL && stricmp(local_movie.filename, Movie.filename) == 0) // alreadyOpen
 20.1291 +	{
 20.1292 +		local_movie.bytesPerFrame		 = Movie.bytesPerFrame;
 20.1293 +		local_movie.header.length_frames = Movie.header.length_frames;
 20.1294 +	}
 20.1295 +	else
 20.1296 +	{
 20.1297 +		// recalculate length of movie from the file size
 20.1298 +		local_movie.bytesPerFrame = bytes_per_frame(local_movie);
 20.1299 +		fseek(file, 0, SEEK_END);
 20.1300 +		int fileSize = ftell(file);
 20.1301 +		local_movie.header.length_frames =
 20.1302 +		    (fileSize - local_movie.header.offset_to_controller_data) / local_movie.bytesPerFrame;
 20.1303 +	}
 20.1304 +
 20.1305 +	fclose(file);
 20.1306 +
 20.1307 +	if (access(filename, W_OK))
 20.1308 +		info->readOnly = true;
 20.1309 +
 20.1310 +	return MOVIE_SUCCESS;
 20.1311 +}
 20.1312 +
 20.1313 +bool8 VBAMovieActive()
 20.1314 +{
 20.1315 +	return (Movie.state != MOVIE_STATE_NONE);
 20.1316 +}
 20.1317 +
 20.1318 +bool8 VBAMovieLoading()
 20.1319 +{
 20.1320 +	return loadingMovie;
 20.1321 +}
 20.1322 +
 20.1323 +bool8 VBAMoviePlaying()
 20.1324 +{
 20.1325 +	return (Movie.state == MOVIE_STATE_PLAY);
 20.1326 +}
 20.1327 +
 20.1328 +bool8 VBAMovieRecording()
 20.1329 +{
 20.1330 +	return (Movie.state == MOVIE_STATE_RECORD);
 20.1331 +}
 20.1332 +
 20.1333 +bool8 VBAMovieReadOnly()
 20.1334 +{
 20.1335 +	if (!VBAMovieActive())
 20.1336 +		return false;
 20.1337 +
 20.1338 +	return Movie.readOnly;
 20.1339 +}
 20.1340 +
 20.1341 +void VBAMovieToggleReadOnly()
 20.1342 +{
 20.1343 +	if (!VBAMovieActive())
 20.1344 +		return;
 20.1345 +
 20.1346 +	if (Movie.readOnly != 2)
 20.1347 +	{
 20.1348 +		Movie.readOnly = !Movie.readOnly;
 20.1349 +
 20.1350 +		systemScreenMessage(Movie.readOnly ? "Movie now read-only" : "Movie now editable");
 20.1351 +	}
 20.1352 +	else
 20.1353 +	{
 20.1354 +		systemScreenMessage("Can't toggle read-only movie");
 20.1355 +	}
 20.1356 +}
 20.1357 +
 20.1358 +uint32 VBAMovieGetVersion()
 20.1359 +{
 20.1360 +	if (!VBAMovieActive())
 20.1361 +		return 0;
 20.1362 +
 20.1363 +	return Movie.header.version;
 20.1364 +}
 20.1365 +
 20.1366 +uint32 VBAMovieGetMinorVersion()
 20.1367 +{
 20.1368 +	if (!VBAMovieActive())
 20.1369 +		return 0;
 20.1370 +
 20.1371 +	return Movie.header.minorVersion;
 20.1372 +}
 20.1373 +
 20.1374 +uint32 VBAMovieGetId()
 20.1375 +{
 20.1376 +	if (!VBAMovieActive())
 20.1377 +		return 0;
 20.1378 +
 20.1379 +	return Movie.header.uid;
 20.1380 +}
 20.1381 +
 20.1382 +uint32 VBAMovieGetLength()
 20.1383 +{
 20.1384 +	if (!VBAMovieActive())
 20.1385 +		return 0;
 20.1386 +
 20.1387 +	return Movie.header.length_frames;
 20.1388 +}
 20.1389 +
 20.1390 +uint32 VBAMovieGetFrameCounter()
 20.1391 +{
 20.1392 +	if (!VBAMovieActive())
 20.1393 +		return 0;
 20.1394 +
 20.1395 +	return Movie.currentFrame;
 20.1396 +}
 20.1397 +
 20.1398 +uint32 VBAMovieGetRerecordCount()
 20.1399 +{
 20.1400 +	if (!VBAMovieActive())
 20.1401 +		return 0;
 20.1402 +
 20.1403 +	return Movie.header.rerecord_count;
 20.1404 +}
 20.1405 +
 20.1406 +uint32 VBAMovieSetRerecordCount(uint32 newRerecordCount)
 20.1407 +{
 20.1408 +	uint32 oldRerecordCount = 0;
 20.1409 +	if (!VBAMovieActive())
 20.1410 +		return 0;
 20.1411 +
 20.1412 +	oldRerecordCount = Movie.header.rerecord_count;
 20.1413 +	Movie.header.rerecord_count = newRerecordCount;
 20.1414 +	return oldRerecordCount;
 20.1415 +}
 20.1416 +
 20.1417 +std::string VBAMovieGetAuthorInfo()
 20.1418 +{
 20.1419 +	if (!VBAMovieActive())
 20.1420 +		return "";
 20.1421 +
 20.1422 +	return Movie.authorInfo;
 20.1423 +}
 20.1424 +
 20.1425 +std::string VBAMovieGetFilename()
 20.1426 +{
 20.1427 +	if (!VBAMovieActive())
 20.1428 +		return "";
 20.1429 +
 20.1430 +	return Movie.filename;
 20.1431 +}
 20.1432 +
 20.1433 +void VBAMovieFreeze(uint8 * *buf, uint32 *size)
 20.1434 +{
 20.1435 +	// sanity check
 20.1436 +	if (!VBAMovieActive())
 20.1437 +	{
 20.1438 +		return;
 20.1439 +	}
 20.1440 +
 20.1441 +	*buf  = NULL;
 20.1442 +	*size = 0;
 20.1443 +
 20.1444 +	// compute size needed for the buffer
 20.1445 +	// room for header.uid, currentFrame, and header.length_frames
 20.1446 +	uint32 size_needed = sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames);
 20.1447 +	size_needed += (uint32)(Movie.bytesPerFrame * Movie.header.length_frames);
 20.1448 +	*buf		 = new uint8[size_needed];
 20.1449 +	*size		 = size_needed;
 20.1450 +
 20.1451 +	uint8 *ptr = *buf;
 20.1452 +	if (!ptr)
 20.1453 +	{
 20.1454 +		return;
 20.1455 +	}
 20.1456 +
 20.1457 +	Push32(Movie.header.uid, ptr);
 20.1458 +	Push32(Movie.currentFrame, ptr);
 20.1459 +	Push32(Movie.header.length_frames - 1, ptr);   // HACK: shorten the length by 1 for backward compatibility
 20.1460 +
 20.1461 +	memcpy(ptr, Movie.inputBuffer, Movie.bytesPerFrame * Movie.header.length_frames);
 20.1462 +}
 20.1463 +
 20.1464 +int VBAMovieUnfreeze(const uint8 *buf, uint32 size)
 20.1465 +{
 20.1466 +	// sanity check
 20.1467 +	if (!VBAMovieActive())
 20.1468 +	{
 20.1469 +		return MOVIE_NOT_FROM_A_MOVIE;
 20.1470 +	}
 20.1471 +
 20.1472 +	const uint8 *ptr = buf;
 20.1473 +	if (size < sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames))
 20.1474 +	{
 20.1475 +		return MOVIE_WRONG_FORMAT;
 20.1476 +	}
 20.1477 +
 20.1478 +	uint32 movie_id		 = Pop32(ptr);
 20.1479 +	uint32 current_frame = Pop32(ptr);
 20.1480 +	uint32 end_frame	 = Pop32(ptr) + 1;     // HACK: restore the length for backward compatibility
 20.1481 +	uint32 space_needed	 = Movie.bytesPerFrame * end_frame;
 20.1482 +
 20.1483 +	if (movie_id != Movie.header.uid)
 20.1484 +		return MOVIE_NOT_FROM_THIS_MOVIE;
 20.1485 +
 20.1486 +	if (space_needed > size)
 20.1487 +		return MOVIE_WRONG_FORMAT;
 20.1488 +
 20.1489 +	if (Movie.readOnly)
 20.1490 +	{
 20.1491 +		// here, we are going to keep the input data from the movie file
 20.1492 +		// and simply rewind to the currentFrame pointer
 20.1493 +		// this will cause a desync if the savestate is not in sync // <-- NOT ANYMORE
 20.1494 +		// with the on-disk recording data, but it's easily solved
 20.1495 +		// by loading another savestate or playing the movie from the beginning
 20.1496 +
 20.1497 +		// don't allow loading a state inconsistent with the current movie
 20.1498 +		uint32 length_history = min(current_frame, Movie.header.length_frames);
 20.1499 +		if (end_frame < length_history)
 20.1500 +			return MOVIE_SNAPSHOT_INCONSISTENT;
 20.1501 +
 20.1502 +		uint32 space_shared = Movie.bytesPerFrame * length_history;
 20.1503 +		if (memcmp(Movie.inputBuffer, ptr, space_shared))
 20.1504 +			return MOVIE_SNAPSHOT_INCONSISTENT;
 20.1505 +
 20.1506 +		Movie.currentFrame	 = current_frame;
 20.1507 +		Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames);
 20.1508 +	}
 20.1509 +	else
 20.1510 +	{
 20.1511 +		// here, we are going to take the input data from the savestate
 20.1512 +		// and make it the input data for the current movie, then continue
 20.1513 +		// writing new input data at the currentFrame pointer
 20.1514 +		Movie.currentFrame		   = current_frame;
 20.1515 +		Movie.header.length_frames = end_frame;
 20.1516 +		if (!VBALuaRerecordCountSkip())
 20.1517 +			++Movie.header.rerecord_count;
 20.1518 +
 20.1519 +		Movie.RecordedThisSession = true;
 20.1520 +
 20.1521 +		// do this before calling reserve_buffer_space()
 20.1522 +		Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames);
 20.1523 +		reserve_buffer_space(space_needed);
 20.1524 +		memcpy(Movie.inputBuffer, ptr, space_needed);
 20.1525 +
 20.1526 +		// for consistency, no auto movie conversion here since we don't auto convert the corresponding savestate
 20.1527 +		flush_movie_header();
 20.1528 +		flush_movie_frames();
 20.1529 +	}
 20.1530 +
 20.1531 +	change_state(MOVIE_STATE_PLAY);	// check for movie end
 20.1532 +
 20.1533 +	// necessary!
 20.1534 +	resetSignaled	  = false;
 20.1535 +	resetSignaledLast = false;
 20.1536 +
 20.1537 +	// necessary to check if there's a reset signal at the previous frame
 20.1538 +	if (current_frame > 0)
 20.1539 +	{
 20.1540 +		const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8);
 20.1541 +		for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i)
 20.1542 +		{
 20.1543 +			if ((Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) && (*(Movie.inputBufferPtr+1- Movie.bytesPerFrame) & NEW_RESET))
 20.1544 +			{
 20.1545 +				resetSignaledLast = true;
 20.1546 +				break;
 20.1547 +			}
 20.1548 +		}
 20.1549 +	}
 20.1550 +
 20.1551 +	return MOVIE_SUCCESS;
 20.1552 +}
 20.1553 +
 20.1554 +bool VBAMovieEnded()
 20.1555 +{
 20.1556 +	return (Movie.state == MOVIE_STATE_END);
 20.1557 +//	return (Movie.state != MOVIE_STATE_NONE && Movie.currentFrame >= Movie.header.length_frames);
 20.1558 +}
 20.1559 +
 20.1560 +bool VBAMovieAllowsRerecording()
 20.1561 +{
 20.1562 +	bool allows = (Movie.state != MOVIE_STATE_NONE) && (Movie.currentFrame <= Movie.header.length_frames);
 20.1563 +	return /*!VBAMovieReadOnly() &&*/ allows;
 20.1564 +}
 20.1565 +
 20.1566 +bool VBAMovieSwitchToPlaying()
 20.1567 +{
 20.1568 +	if (!VBAMovieActive())
 20.1569 +		return false;
 20.1570 +
 20.1571 +	if (!Movie.readOnly)
 20.1572 +	{
 20.1573 +		VBAMovieToggleReadOnly();
 20.1574 +	}
 20.1575 +
 20.1576 +	change_state(MOVIE_STATE_PLAY);
 20.1577 +	if (Movie.state == MOVIE_STATE_PLAY)
 20.1578 +		systemScreenMessage("Movie replay (continue)");
 20.1579 +	else
 20.1580 +		systemScreenMessage("Movie end");
 20.1581 +
 20.1582 +	return true;
 20.1583 +}
 20.1584 +
 20.1585 +bool VBAMovieSwitchToRecording()
 20.1586 +{
 20.1587 +	if (!VBAMovieAllowsRerecording())
 20.1588 +		return false;
 20.1589 +
 20.1590 +	if (Movie.readOnly)
 20.1591 +	{
 20.1592 +		VBAMovieToggleReadOnly();
 20.1593 +	}
 20.1594 +
 20.1595 +	if (!VBALuaRerecordCountSkip())
 20.1596 +		++Movie.header.rerecord_count;
 20.1597 +
 20.1598 +	change_state(MOVIE_STATE_RECORD);
 20.1599 +	systemScreenMessage("Movie re-record");
 20.1600 +
 20.1601 +	//truncate_movie(Movie.currentFrame);
 20.1602 +
 20.1603 +	return true;
 20.1604 +}
 20.1605 +
 20.1606 +uint32 VBAMovieGetState()
 20.1607 +{
 20.1608 +	// ?
 20.1609 +	if (!VBAMovieActive())
 20.1610 +		return MOVIE_STATE_NONE;
 20.1611 +
 20.1612 +	return Movie.state;
 20.1613 +}
 20.1614 +
 20.1615 +void VBAMovieSignalReset()
 20.1616 +{
 20.1617 +	if (VBAMovieActive())
 20.1618 +		resetSignaled = true;
 20.1619 +}
 20.1620 +
 20.1621 +void VBAMovieResetIfRequested()
 20.1622 +{
 20.1623 +	if (resetSignaled)
 20.1624 +	{
 20.1625 +		theEmulator.emuReset(false);
 20.1626 +		resetSignaled	  = false;
 20.1627 +		resetSignaledLast = true;
 20.1628 +	}
 20.1629 +	else
 20.1630 +	{
 20.1631 +		resetSignaledLast = false;
 20.1632 +	}
 20.1633 +}
 20.1634 +
 20.1635 +void VBAMovieSetMetadata(const char *info)
 20.1636 +{
 20.1637 +	if (!memcmp(Movie.authorInfo, info, MOVIE_METADATA_SIZE))
 20.1638 +		return;
 20.1639 +
 20.1640 +	memcpy(Movie.authorInfo, info, MOVIE_METADATA_SIZE); // strncpy would omit post-0 bytes
 20.1641 +	Movie.authorInfo[MOVIE_METADATA_SIZE - 1] = '\0';
 20.1642 +
 20.1643 +	if (Movie.file)
 20.1644 +	{
 20.1645 +		// (over-)write the header
 20.1646 +		fseek(Movie.file, 0, SEEK_SET);
 20.1647 +		write_movie_header(Movie.file, Movie);
 20.1648 +
 20.1649 +		// write the metadata / author info to file
 20.1650 +		fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, Movie.file);
 20.1651 +
 20.1652 +		fflush(Movie.file);
 20.1653 +	}
 20.1654 +}
 20.1655 +
 20.1656 +void VBAMovieRestart()
 20.1657 +{
 20.1658 +	if (VBAMovieActive())
 20.1659 +	{
 20.1660 +		systemSoundClearBuffer();
 20.1661 +
 20.1662 +		bool8 modified = Movie.RecordedThisSession;
 20.1663 +
 20.1664 +		VBAMovieStop(true);
 20.1665 +
 20.1666 +		char movieName [_MAX_PATH];
 20.1667 +		strncpy(movieName, Movie.filename, _MAX_PATH);
 20.1668 +		movieName[_MAX_PATH - 1] = '\0';
 20.1669 +		VBAMovieOpen(movieName, Movie.readOnly); // can't just pass in Movie.filename, since VBAMovieOpen clears out Movie's
 20.1670 +		                                         // variables
 20.1671 +
 20.1672 +		Movie.RecordedThisSession = modified;
 20.1673 +
 20.1674 +		systemScreenMessage("Movie replay (restart)");
 20.1675 +	}
 20.1676 +}
 20.1677 +
 20.1678 +int VBAMovieGetPauseAt()
 20.1679 +{
 20.1680 +	return Movie.pauseFrame;
 20.1681 +}
 20.1682 +
 20.1683 +void VBAMovieSetPauseAt(int at)
 20.1684 +{
 20.1685 +	Movie.pauseFrame = at;
 20.1686 +}
 20.1687 +
 20.1688 +///////////////////////
 20.1689 +// movie tools
 20.1690 +
 20.1691 +// FIXME: is it safe to convert/flush a movie while recording it (considering fseek() problem)?
 20.1692 +int VBAMovieConvertCurrent()
 20.1693 +{
 20.1694 +	if (!VBAMovieActive())
 20.1695 +	{
 20.1696 +		return MOVIE_NOTHING;
 20.1697 +	}
 20.1698 +
 20.1699 +	if (Movie.header.minorVersion > VBM_REVISION)
 20.1700 +	{
 20.1701 +		return MOVIE_WRONG_VERSION;
 20.1702 +	}
 20.1703 +
 20.1704 +	if (Movie.header.minorVersion == VBM_REVISION)
 20.1705 +	{
 20.1706 +		return MOVIE_NOTHING;
 20.1707 +	}
 20.1708 +
 20.1709 +	Movie.header.minorVersion = VBM_REVISION;
 20.1710 +
 20.1711 +	if (Movie.header.length_frames == 0) // this could happen
 20.1712 +	{
 20.1713 +		truncate_movie(0);
 20.1714 +		return MOVIE_SUCCESS;
 20.1715 +	}
 20.1716 +
 20.1717 +	// fix movies recorded from snapshots
 20.1718 +	if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT)
 20.1719 +	{
 20.1720 +		uint8 *firstFramePtr = Movie.inputBuffer;
 20.1721 +		for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i)
 20.1722 +		{
 20.1723 +			if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i))
 20.1724 +			{
 20.1725 +				Push16(initialInputs[i], firstFramePtr);
 20.1726 +				// note: this is correct since Push16 advances the dest pointer by sizeof u16
 20.1727 +			}
 20.1728 +		}
 20.1729 +	}
 20.1730 +
 20.1731 +	// convert old resets to new ones
 20.1732 +	const u8 OLD_RESET = u8(BUTTON_MASK_OLD_RESET >> 8);
 20.1733 +	const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8);
 20.1734 +	for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i)
 20.1735 +	{
 20.1736 +		if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i))
 20.1737 +		{
 20.1738 +			uint8 *startPtr = Movie.inputBuffer + sizeof(u16) * i + 1;
 20.1739 +			uint8 *endPtr	= Movie.inputBuffer + Movie.bytesPerFrame * (Movie.header.length_frames - 1);
 20.1740 +			for (; startPtr < endPtr; startPtr += Movie.bytesPerFrame)
 20.1741 +			{
 20.1742 +				if (startPtr[Movie.bytesPerFrame] & OLD_RESET)
 20.1743 +				{
 20.1744 +					startPtr[0] |= NEW_RESET;
 20.1745 +				}
 20.1746 +			}
 20.1747 +		}
 20.1748 +	}
 20.1749 +
 20.1750 +	flush_movie_header();
 20.1751 +	flush_movie_frames();
 20.1752 +	return MOVIE_SUCCESS;
 20.1753 +}
 20.1754 +
 20.1755 +bool VBAMovieTuncateAtCurrentFrame()
 20.1756 +{
 20.1757 +	if (!VBAMovieActive())
 20.1758 +		return false;
 20.1759 +
 20.1760 +	truncate_movie(Movie.currentFrame);
 20.1761 +	change_state(MOVIE_STATE_END);
 20.1762 +	systemScreenMessage("Movie truncated");
 20.1763 +
 20.1764 +	return true;
 20.1765 +}
 20.1766 +
 20.1767 +bool VBAMovieFixHeader()
 20.1768 +{
 20.1769 +	if (!VBAMovieActive())
 20.1770 +		return false;
 20.1771 +
 20.1772 +	flush_movie_header();
 20.1773 +	systemScreenMessage("Movie header fixed");
 20.1774 +	return true;
 20.1775 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/common/movie.h	Sun Mar 04 14:33:52 2012 -0600
    21.3 @@ -0,0 +1,190 @@
    21.4 +#ifndef VBA_MOVIE_H
    21.5 +#define VBA_MOVIE_H
    21.6 +
    21.7 +#if _MSC_VER > 1000
    21.8 +#pragma once
    21.9 +#endif // _MSC_VER > 1000
   21.10 +
   21.11 +#include <ctime>
   21.12 +#include <string>
   21.13 +
   21.14 +#include "../Port.h"
   21.15 +
   21.16 +#define ZLIB
   21.17 +///#ifdef ZLIB
   21.18 +#ifndef WIN32
   21.19 +#include "zlib.h"
   21.20 +#endif
   21.21 +
   21.22 +#ifndef MOVIE_SUCCESS
   21.23 +#  define MOVIE_SUCCESS 1
   21.24 +#  define MOVIE_NOTHING 0
   21.25 +#  define MOVIE_WRONG_FORMAT (-1)
   21.26 +#  define MOVIE_WRONG_VERSION (-2)
   21.27 +#  define MOVIE_FILE_NOT_FOUND (-3)
   21.28 +#  define MOVIE_NOT_FROM_THIS_MOVIE (-4)
   21.29 +#  define MOVIE_NOT_FROM_A_MOVIE (-5)
   21.30 +#  define MOVIE_SNAPSHOT_INCONSISTENT (-6)
   21.31 +#  define MOVIE_UNKNOWN_ERROR (-7)
   21.32 +#endif
   21.33 +
   21.34 +#define VBM_MAGIC (0x1a4D4256) // VBM0x1a
   21.35 +#define VBM_VERSION (1)
   21.36 +#define VBM_HEADER_SIZE (64)
   21.37 +#define CONTROLLER_DATA_SIZE (2)
   21.38 +#define BUFFER_GROWTH_SIZE (4096)
   21.39 +#define MOVIE_METADATA_SIZE (192)
   21.40 +#define MOVIE_METADATA_AUTHOR_SIZE (64)
   21.41 +
   21.42 +// revision 1 uses (?) insted of (!) as reset
   21.43 +#define VBM_REVISION   (1)
   21.44 +
   21.45 +#define MOVIE_START_FROM_SNAPSHOT   (1<<0)
   21.46 +#define MOVIE_START_FROM_SRAM       (1<<1)
   21.47 +
   21.48 +#define MOVIE_CONTROLLER(i)         (1<<(i))
   21.49 +#define MOVIE_CONTROLLERS_ANY_MASK  (MOVIE_CONTROLLER(0)|MOVIE_CONTROLLER(1)|MOVIE_CONTROLLER(2)|MOVIE_CONTROLLER(3))
   21.50 +#define MOVIE_NUM_OF_POSSIBLE_CONTROLLERS   (4)
   21.51 +
   21.52 +#define MOVIE_TYPE_GBA              (1<<0)
   21.53 +#define MOVIE_TYPE_GBC              (1<<1)
   21.54 +#define MOVIE_TYPE_SGB              (1<<2)
   21.55 +
   21.56 +#define MOVIE_SETTING_USEBIOSFILE   (1<<0)
   21.57 +#define MOVIE_SETTING_SKIPBIOSFILE  (1<<1)
   21.58 +#define MOVIE_SETTING_RTCENABLE     (1<<2)
   21.59 +#define MOVIE_SETTING_GBINPUTHACK   (1<<3)
   21.60 +#define MOVIE_SETTING_LAGHACK       (1<<4)
   21.61 +#define MOVIE_SETTING_GBCFF55FIX    (1<<5)
   21.62 +#define MOVIE_SETTING_GBECHORAMFIX  (1<<6)
   21.63 +
   21.64 +#define STREAM gzFile
   21.65 +/*#define READ_STREAM(p,l,s) gzread (s,p,l)
   21.66 + #define WRITE_STREAM(p,l,s) gzwrite (s,p,l)
   21.67 + #define OPEN_STREAM(f,m) gzopen (f,m)
   21.68 + #define REOPEN_STREAM(f,m) gzdopen (f,m)
   21.69 + #define FIND_STREAM(f)	gztell(f)
   21.70 + #define REVERT_STREAM(f,o,s)  gzseek(f,o,s)
   21.71 + #define CLOSE_STREAM(s) gzclose (s)
   21.72 + #else
   21.73 + #define STREAM FILE *
   21.74 + #define READ_STREAM(p,l,s) fread (p,1,l,s)
   21.75 + #define WRITE_STREAM(p,l,s) fwrite (p,1,l,s)
   21.76 + #define OPEN_STREAM(f,m) fopen (f,m)
   21.77 + #define REOPEN_STREAM(f,m) fdopen (f,m)
   21.78 + #define FIND_STREAM(f)	ftell(f)
   21.79 + #define REVERT_STREAM(f,o,s)	 fseek(f,o,s)
   21.80 + #define CLOSE_STREAM(s) fclose (s)
   21.81 + #endif*/
   21.82 +
   21.83 +enum MovieState
   21.84 +{
   21.85 +	MOVIE_STATE_NONE = 0,
   21.86 +	MOVIE_STATE_PLAY,
   21.87 +	MOVIE_STATE_RECORD,
   21.88 +	MOVIE_STATE_END
   21.89 +};
   21.90 +
   21.91 +struct SMovieFileHeader
   21.92 +{
   21.93 +	uint32 magic;       // VBM0x1a
   21.94 +	uint32 version;     // 1
   21.95 +	int32  uid;         // used to match savestates to a particular movie
   21.96 +	uint32 length_frames;
   21.97 +	uint32 rerecord_count;
   21.98 +	uint8  startFlags;
   21.99 +	uint8  controllerFlags;
  21.100 +	uint8  typeFlags;
  21.101 +	uint8  optionFlags;
  21.102 +	uint32 saveType;        // emulator setting value
  21.103 +	uint32 flashSize;       // emulator setting value
  21.104 +	uint32 gbEmulatorType;  // emulator setting value
  21.105 +	char   romTitle [12];
  21.106 +	uint8  minorVersion;	// minor version/revision of the current movie version
  21.107 +	uint8  romCRC;						// the CRC of the ROM used while recording
  21.108 +	uint16 romOrBiosChecksum;			// the Checksum of the ROM used while recording, or a CRC of the BIOS if GBA
  21.109 +	uint32 romGameCode;					// the Game Code of the ROM used while recording, or "\0\0\0\0" if not GBA
  21.110 +	uint32 offset_to_savestate;         // offset to the savestate or SRAM inside file, set to 0 if unused
  21.111 +	uint32 offset_to_controller_data;   // offset to the controller data inside file
  21.112 +};
  21.113 +
  21.114 +struct SMovie
  21.115 +{
  21.116 +	enum   MovieState state;
  21.117 +	char   filename[/*_MAX_PATH*/ 260]; // FIXME: should use a string instead
  21.118 +	FILE*  file;
  21.119 +	uint8  readOnly;
  21.120 +	int32  pauseFrame;	// FIXME: byte size
  21.121 +
  21.122 +	SMovieFileHeader header;
  21.123 +	char  authorInfo[MOVIE_METADATA_SIZE];
  21.124 +
  21.125 +	uint32 currentFrame;    // should == length_frame when recording, and be < length_frames when playing
  21.126 +	uint32 bytesPerFrame;
  21.127 +	uint8* inputBuffer;
  21.128 +	uint32 inputBufferSize;
  21.129 +	uint8* inputBufferPtr;
  21.130 +
  21.131 +	// bool8 doesn't make much sense if it is meant to solve any portability problem,
  21.132 +	//   because there's no guarantee that true == 1 and false == 0 (or TRUE == 1 and FALSE == 0) on all platforms.
  21.133 +	//   while using user-defined boolean types might impact on performance.
  21.134 +	//   the more reliable (and faster!) way to maintain cross-platform I/O compatibility is
  21.135 +	//   to manually map from/to built-in boolean types to/from fixed-sized types value by value ONLY when doing I/O
  21.136 +	//   e.g. bool(true) <-> u8(1) and <-> bool(false) <-> u8(0), BOOL(TRUE) <-> s32(-1) and BOOL(FALSE) <-> s32(0) etc.
  21.137 +	bool8 RecordedThisSession;
  21.138 +};
  21.139 +
  21.140 +// methods used by the user-interface code
  21.141 +int VBAMovieOpen(const char *filename, bool8 read_only);
  21.142 +int VBAMovieCreate(const char *filename, const char *authorInfo, uint8 startFlags, uint8 controllerFlags, uint8 typeFlags);
  21.143 +int VBAMovieGetInfo(const char *filename, SMovie*info);
  21.144 +void VBAMovieGetRomInfo(const SMovie &movieInfo, char romTitle[12], uint32 &romGameCode, uint16 &checksum, uint8 &crc);
  21.145 +void VBAMovieStop(bool8 suppress_message);
  21.146 +const char *VBAChooseMovieFilename(bool8 read_only);
  21.147 +
  21.148 +// methods used by the emulation
  21.149 +void VBAMovieInit();
  21.150 +void VBAMovieUpdateState();
  21.151 +void VBAMovieRead(int controllerNum = 0, bool sensor = false);
  21.152 +void VBAMovieWrite(int controllerNum = 0, bool sensor = false);
  21.153 +void VBAUpdateButtonPressDisplay();
  21.154 +void VBAUpdateFrameCountDisplay();
  21.155 +//bool8 VBAMovieRewind (uint32 at_frame);
  21.156 +void VBAMovieFreeze(uint8 **buf, uint32 *size);
  21.157 +int VBAMovieUnfreeze(const uint8 *buf, uint32 size);
  21.158 +void VBAMovieRestart();
  21.159 +
  21.160 +// accessor functions
  21.161 +bool8 VBAMovieActive();
  21.162 +bool8 VBAMovieLoading();
  21.163 +bool8 VBAMoviePlaying();
  21.164 +bool8 VBAMovieRecording();
  21.165 +// the following accessors return 0/false if !VBAMovieActive()
  21.166 +uint8 VBAMovieReadOnly();
  21.167 +uint32 VBAMovieGetVersion();
  21.168 +uint32 VBAMovieGetMinorVersion();
  21.169 +uint32 VBAMovieGetId();
  21.170 +uint32 VBAMovieGetLength();
  21.171 +uint32 VBAMovieGetFrameCounter();
  21.172 +uint32 VBAMovieGetState();
  21.173 +uint32 VBAMovieGetRerecordCount ();
  21.174 +uint32 VBAMovieSetRerecordCount (uint32 newRerecordCount);
  21.175 +std::string VBAMovieGetAuthorInfo();
  21.176 +std::string VBAMovieGetFilename();
  21.177 +
  21.178 +uint16 VBAMovieGetCurrentInputOf(int controllerNum, bool normalOnly = true);
  21.179 +void VBAMovieSignalReset();
  21.180 +void VBAMovieResetIfRequested();
  21.181 +void VBAMovieSetMetadata(const char *info);
  21.182 +void VBAMovieToggleReadOnly();
  21.183 +bool VBAMovieEnded();
  21.184 +bool VBAMovieAllowsRerecording();
  21.185 +bool VBAMovieSwitchToPlaying();
  21.186 +bool VBAMovieSwitchToRecording();
  21.187 +int  VBAMovieGetPauseAt();
  21.188 +void VBAMovieSetPauseAt(int at);
  21.189 +int  VBAMovieConvertCurrent();
  21.190 +bool VBAMovieTuncateAtCurrentFrame();
  21.191 +bool VBAMovieFixHeader();
  21.192 +
  21.193 +#endif // VBA_MOVIE_H
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/common/nesvideos-piece.cpp	Sun Mar 04 14:33:52 2012 -0600
    22.3 @@ -0,0 +1,525 @@
    22.4 +#include <cmath>
    22.5 +#include <cstdio>
    22.6 +#include <string>
    22.7 +#include <vector>
    22.8 +
    22.9 +/* Note: This module assumes everyone uses RGB15 as display depth */
   22.10 +
   22.11 +static std::string VIDEO_CMD =
   22.12 +    "mencoder - -o test0.avi"
   22.13 +    " -noskip -mc 0"
   22.14 +    " -ovc lavc"
   22.15 +    " -oac mp3lame"
   22.16 +    " -lameopts preset=256:aq=2:mode=3"
   22.17 +    " -lavcopts vcodec=ffv1:context=0:format=BGR32:coder=0:vstrict=-1"
   22.18 +    " >& mencoder.log";
   22.19 +
   22.20 +static void FlushWrite(FILE* fp, const unsigned char*buf, unsigned length);
   22.21 +
   22.22 +#define BGR24 (0x42475218)  // BGR24 fourcc
   22.23 +#define BGR16 (0x42475210)  // BGR16 fourcc
   22.24 +#define BGR15 (0x4247520F)  // BGR15 fourcc
   22.25 +
   22.26 +static FILE* (*openFunc)  (const char*, const char*) = NULL;
   22.27 +static int (*closeFunc) (FILE*) = NULL;
   22.28 +
   22.29 +#if (defined(WIN32) || defined(win32)) // capital is standard, but check for either
   22.30 + #include <cstdlib>
   22.31 + #define popen _popen;
   22.32 + #define pclose _pclose;
   22.33 +#endif
   22.34 +
   22.35 +#define u32(n) (n)&255,((n)>>8)&255,((n)>>16)&255,((n)>>24)&255
   22.36 +#define u16(n) (n)&255,((n)>>8)&255
   22.37 +#define s4(s) s[0],s[1],s[2],s[3]
   22.38 +
   22.39 +static const unsigned FPS_SCALE = (0x1000000);
   22.40 +
   22.41 +// general-purpose A/V sync debugging, ignored unless explicitly enabled with NESVideoEnableDebugging
   22.42 +static void (*debugVideoMessageFunc)(const char *msg) = NULL;
   22.43 +static void (*debugAudioMessageFunc)(const char *msg) = NULL;
   22.44 +// logo adds 1 "frame" to audio, so offset that (A/V frames shouldn't necessarily match up depending on the rates, but should at least make them start out matching in case they do)
   22.45 +static unsigned audioFramesWritten=0, videoFramesWritten=1;
   22.46 +static double audioSecondsWritten=0, videoSecondsWritten=0;
   22.47 +
   22.48 +
   22.49 +static class AVI
   22.50 +{
   22.51 +    FILE* avifp;
   22.52 +    
   22.53 +    bool KnowVideo;
   22.54 +    unsigned width;
   22.55 +    unsigned height;
   22.56 +    unsigned fps_scaled;
   22.57 +    std::vector<unsigned char> VideoBuffer;
   22.58 +    
   22.59 +    bool KnowAudio;
   22.60 +    unsigned rate;
   22.61 +    unsigned chans;
   22.62 +    unsigned bits;
   22.63 +    std::vector<unsigned char> AudioBuffer;
   22.64 +    
   22.65 +public:
   22.66 +    AVI() :
   22.67 +        avifp(NULL),
   22.68 +        KnowVideo(false),
   22.69 +        KnowAudio(false)
   22.70 +    {
   22.71 +    }
   22.72 +    ~AVI()
   22.73 +    {
   22.74 +        if(avifp) closeFunc(avifp);
   22.75 +    }
   22.76 +    
   22.77 +    void Audio(unsigned r,unsigned b,unsigned c,
   22.78 +               const unsigned char*d, unsigned nsamples)
   22.79 +    {
   22.80 +        if(!KnowAudio)
   22.81 +        {
   22.82 +            rate = r;
   22.83 +            chans = c;
   22.84 +            bits = b;
   22.85 +            KnowAudio = true;
   22.86 +            CheckFlushing();
   22.87 +        }
   22.88 +        unsigned bytes = nsamples*chans*(bits/8);
   22.89 +
   22.90 +		if(debugAudioMessageFunc)
   22.91 +		{
   22.92 +			audioFramesWritten++;
   22.93 +			audioSecondsWritten += (double)nsamples / (double)rate; // += bytes times seconds per byte
   22.94 +			char temp [64];
   22.95 +			sprintf(temp, "A: %.2lf s, %d f", audioSecondsWritten, audioFramesWritten);
   22.96 +			debugAudioMessageFunc(temp);
   22.97 +		}
   22.98 +
   22.99 +        if(KnowVideo)
  22.100 +            SendAudioFrame(d, bytes);
  22.101 +        else
  22.102 +        {
  22.103 +            AudioBuffer.insert(AudioBuffer.end(), d, d+bytes);
  22.104 +            fprintf(stderr, "Buffering %u bytes of audio\n", bytes);
  22.105 +        }
  22.106 +    }
  22.107 +    void Video(unsigned w,unsigned h,unsigned f, const unsigned char*d)
  22.108 +    {
  22.109 +        if(!KnowVideo)
  22.110 +        {
  22.111 +            width=w;
  22.112 +            height=h;
  22.113 +            fps_scaled=f;
  22.114 +            KnowVideo = true;
  22.115 +            CheckFlushing();
  22.116 +        }
  22.117 +        
  22.118 +        unsigned bytes = width*height*2;
  22.119 +        
  22.120 +        //std::vector<unsigned char> tmp(bytes, 'k');
  22.121 +        //d = &tmp[0];
  22.122 +
  22.123 +		if(debugVideoMessageFunc)
  22.124 +		{
  22.125 +			videoFramesWritten++;
  22.126 +			videoSecondsWritten += (double)FPS_SCALE / (double)fps_scaled; // += seconds per frame
  22.127 +			char temp [64];
  22.128 +			sprintf(temp, "V: %.2lf s, %d f", videoSecondsWritten, videoFramesWritten);
  22.129 +			debugVideoMessageFunc(temp);
  22.130 +		}
  22.131 +
  22.132 +        if(KnowAudio)
  22.133 +            SendVideoFrame(d, bytes);
  22.134 +        else
  22.135 +        {
  22.136 +            VideoBuffer.insert(VideoBuffer.end(), d, d+bytes);
  22.137 +            fprintf(stderr, "Buffering %u bytes of video\n", bytes);
  22.138 +        }
  22.139 +    }
  22.140 +
  22.141 +private:
  22.142 +    void CheckFlushing()
  22.143 +    {
  22.144 +        //AudioBuffer.clear();
  22.145 +        //VideoBuffer.clear();
  22.146 +        
  22.147 +        if(KnowAudio && KnowVideo)
  22.148 +        {
  22.149 +            unsigned last_offs;
  22.150 +            
  22.151 +            // Flush Audio
  22.152 +            
  22.153 +            last_offs = 0;
  22.154 +            while(last_offs < AudioBuffer.size())
  22.155 +            {
  22.156 +                unsigned bytes = rate / (fps_scaled / FPS_SCALE);
  22.157 +                bytes *= chans*(bits/8);
  22.158 +                
  22.159 +                unsigned remain = AudioBuffer.size() - last_offs;
  22.160 +                if(bytes > remain) bytes = remain;
  22.161 +                if(!bytes) break;
  22.162 +                
  22.163 +                unsigned begin = last_offs;
  22.164 +                last_offs += bytes;
  22.165 +                SendAudioFrame(&AudioBuffer[begin], bytes);
  22.166 +            }
  22.167 +            AudioBuffer.erase(AudioBuffer.begin(), AudioBuffer.begin()+last_offs);
  22.168 +            
  22.169 +            // Flush Video
  22.170 +            
  22.171 +            last_offs = 0;
  22.172 +            while(last_offs < VideoBuffer.size())
  22.173 +            {
  22.174 +                unsigned bytes  = width*height*2;
  22.175 +                unsigned remain = VideoBuffer.size() - last_offs;
  22.176 +                if(bytes > remain) bytes = remain;
  22.177 +                if(!bytes)break;
  22.178 +                
  22.179 +                unsigned begin = last_offs;
  22.180 +                last_offs += bytes;
  22.181 +                SendVideoFrame(&VideoBuffer[begin], bytes);
  22.182 +            }
  22.183 +            VideoBuffer.erase(VideoBuffer.begin(), VideoBuffer.begin()+last_offs);
  22.184 +        }
  22.185 +    }
  22.186 +    
  22.187 +    void SendVideoFrame(const unsigned char* vidbuf, unsigned framesize)
  22.188 +    {
  22.189 +        CheckBegin();
  22.190 +        
  22.191 +        //fprintf(stderr, "Writing 00dc of %u bytes\n", framesize);
  22.192 +        
  22.193 +        const unsigned char header[] = { s4("00dc"), u32(framesize) };
  22.194 +        FlushWrite(avifp, header, sizeof(header));
  22.195 +        FlushWrite(avifp, vidbuf, framesize);
  22.196 +    }
  22.197 +
  22.198 +    void SendAudioFrame(const unsigned char* audbuf, unsigned framesize)
  22.199 +    {
  22.200 +        CheckBegin();
  22.201 +        
  22.202 +        //fprintf(stderr, "Writing 01wb of %u bytes\n", framesize);
  22.203 +        
  22.204 +        const unsigned char header[] = { s4("01wb"), u32(framesize) };
  22.205 +        FlushWrite(avifp, header, sizeof(header));
  22.206 +        FlushWrite(avifp, audbuf, framesize);
  22.207 +    }
  22.208 +
  22.209 +    void CheckBegin()
  22.210 +    {
  22.211 +        if(avifp) return;
  22.212 +        
  22.213 +		if(!openFunc) openFunc = popen; // default
  22.214 +		if(!closeFunc) closeFunc = pclose; // default
  22.215 +
  22.216 +        avifp = openFunc(VIDEO_CMD.c_str(), "wb");
  22.217 +        if(!avifp) return;
  22.218 +
  22.219 +        const unsigned fourcc = BGR16;
  22.220 +        const unsigned framesize = width*height*2;
  22.221 +        
  22.222 +        const unsigned aud_rate  = rate;
  22.223 +        const unsigned aud_chans = chans;
  22.224 +        const unsigned aud_bits  = bits;
  22.225 +
  22.226 +        const unsigned nframes    = 0; //unknown
  22.227 +        const unsigned scale      = FPS_SCALE;
  22.228 +        const unsigned scaled_fps = fps_scaled;
  22.229 +        
  22.230 +        const unsigned SIZE_strh_vids = 4 + 4*2 + 2*2 + 8*4 + 2*4;
  22.231 +        const unsigned SIZE_strf_vids = 4*3 + 2*2 + 4*6;
  22.232 +        const unsigned SIZE_strl_vids = 4+ 4+(4+SIZE_strh_vids) + 4+(4+SIZE_strf_vids);
  22.233 +
  22.234 +        const unsigned SIZE_strh_auds = 4 + 4*3 + 2*2 + 4*8 + 2*4;
  22.235 +        const unsigned SIZE_strf_auds = 2*2 + 4*2 + 2*3;
  22.236 +        const unsigned SIZE_strl_auds = 4+ 4+(4+SIZE_strh_auds) + 4+(4+SIZE_strf_auds);
  22.237 +        
  22.238 +        const unsigned SIZE_avih = 4*12;
  22.239 +        const unsigned SIZE_hdrl = 4+4+ (4+SIZE_avih) + 4 + (4+SIZE_strl_vids) + 4 + (4+SIZE_strl_auds);
  22.240 +        const unsigned SIZE_movi = 4 + nframes*(4+4+framesize);
  22.241 +        const unsigned SIZE_avi = 4+4+ (4+SIZE_hdrl) + 4 + (4+SIZE_movi);
  22.242 +        
  22.243 +        const unsigned char AVIheader[] =
  22.244 +        {
  22.245 +            s4("RIFF"),
  22.246 +            u32(SIZE_avi),
  22.247 +            s4("AVI "),   
  22.248 +            
  22.249 +            // HEADER
  22.250 +
  22.251 +            s4("LIST"),   
  22.252 +            u32(SIZE_hdrl),
  22.253 +             s4("hdrl"),   
  22.254 +             
  22.255 +             s4("avih"),
  22.256 +             u32(SIZE_avih),
  22.257 +              u32(0),
  22.258 +              u32(0),
  22.259 +              u32(0),
  22.260 +              u32(0),
  22.261 +              u32(nframes),
  22.262 +              u32(0),
  22.263 +              u32(2), // two streams
  22.264 +              u32(0),
  22.265 +              u32(0),
  22.266 +              u32(0),
  22.267 +              u32(0),
  22.268 +              u32(0),
  22.269 +             
  22.270 +             // VIDEO HEADER
  22.271 +             
  22.272 +             s4("LIST"),
  22.273 +             u32(SIZE_strl_vids),
  22.274 +              s4("strl"),   
  22.275 +              
  22.276 +               s4("strh"),
  22.277 +               u32(SIZE_strh_vids),
  22.278 +                s4("vids"),
  22.279 +                u32(0),
  22.280 +                u32(0),
  22.281 +                u16(0),
  22.282 +                u16(0),
  22.283 +                u32(0),
  22.284 +                u32(scale),
  22.285 +                u32(scaled_fps),
  22.286 +                u32(0),
  22.287 +                u32(0),
  22.288 +                u32(0),
  22.289 +                u32(0),
  22.290 +                u32(0),
  22.291 +                u16(0),
  22.292 +                u16(0),
  22.293 +                u16(0),
  22.294 +                u16(0),
  22.295 +               
  22.296 +               s4("strf"),
  22.297 +               u32(SIZE_strf_vids),
  22.298 +                u32(0),
  22.299 +                u32(width),
  22.300 +                u32(height),
  22.301 +                u16(0),
  22.302 +                u16(0),
  22.303 +                u32(fourcc),
  22.304 +                u32(0),
  22.305 +                u32(0),
  22.306 +                u32(0),
  22.307 +                u32(0),
  22.308 +                u32(0),
  22.309 +             
  22.310 +             // AUDIO HEADER
  22.311 +             
  22.312 +             s4("LIST"),
  22.313 +             u32(SIZE_strl_auds),
  22.314 +              s4("strl"),   
  22.315 +              
  22.316 +               s4("strh"),
  22.317 +               u32(SIZE_strh_auds),
  22.318 +                s4("auds"),
  22.319 +                u32(0), //fourcc
  22.320 +                u32(0), //handler
  22.321 +                u32(0), //flags
  22.322 +                u16(0), //prio
  22.323 +                u16(0), //lang
  22.324 +                u32(0), //init frames
  22.325 +                u32(1), //scale
  22.326 +                u32(aud_rate),
  22.327 +                u32(0), //start
  22.328 +                u32(0), //rate*length
  22.329 +                u32(1048576), //suggested bufsize
  22.330 +                u32(0), //quality
  22.331 +                u32(aud_chans * (aud_bits / 8)), //sample size
  22.332 +                u16(0), //frame size
  22.333 +                u16(0),
  22.334 +                u16(0),
  22.335 +                u16(0),
  22.336 +               
  22.337 +               s4("strf"),
  22.338 +               u32(SIZE_strf_auds),
  22.339 +                u16(1), // pcm format
  22.340 +                u16(aud_chans),
  22.341 +                u32(aud_rate),
  22.342 +                u32(aud_rate * aud_chans * (aud_bits/8)), // samples per second
  22.343 +                u16(aud_chans * (aud_bits/8)), //block align
  22.344 +                u16(aud_bits), //bits
  22.345 +                u16(0), //cbSize
  22.346 +
  22.347 +            // MOVIE
  22.348 +
  22.349 +            s4("LIST"),
  22.350 +            u32(SIZE_movi),
  22.351 +             s4("movi")
  22.352 +        };
  22.353 +          
  22.354 +        FlushWrite(avifp, AVIheader, sizeof(AVIheader));
  22.355 +    }
  22.356 +} AVI;
  22.357 +
  22.358 +extern "C"
  22.359 +{
  22.360 +    int LoggingEnabled = 0; /* 0=no, 1=yes, 2=recording! */
  22.361 +
  22.362 +    const char* NESVideoGetVideoCmd()
  22.363 +    {
  22.364 +        return VIDEO_CMD.c_str();
  22.365 +    }
  22.366 +    void NESVideoSetVideoCmd(const char *cmd)
  22.367 +    {
  22.368 +        VIDEO_CMD = cmd;
  22.369 +    }
  22.370 +	void NESVideoEnableDebugging( void videoMessageFunc(const char *msg), void audioMessageFunc(const char *msg) )
  22.371 +	{
  22.372 +		debugVideoMessageFunc = videoMessageFunc;
  22.373 +		debugAudioMessageFunc = audioMessageFunc;
  22.374 +	}
  22.375 +	void NESVideoSetFileFuncs( FILE* open(const char *,const char *), int close(FILE*) )
  22.376 +	{
  22.377 +		openFunc = open;
  22.378 +		closeFunc = close;
  22.379 +	}
  22.380 +
  22.381 +    void NESVideoLoggingVideo
  22.382 +        (const void*data, unsigned width,unsigned height,
  22.383 +         unsigned fps_scaled
  22.384 +        )
  22.385 +    {
  22.386 +        if(LoggingEnabled < 2) return;
  22.387 +        
  22.388 +        unsigned LogoFrames = fps_scaled >> 24;
  22.389 +
  22.390 +        static bool First = true;
  22.391 +        if(First)
  22.392 +        {
  22.393 +            First=false;
  22.394 +            /* Bisqwit's logo addition routine. */
  22.395 +            /* If you don't have his files, this function does nothing
  22.396 +             * and it does not matter at all.
  22.397 +             */
  22.398 +            
  22.399 +            const char *background =
  22.400 +                width==320 ? "logo320_240"
  22.401 +              : width==160 ? "logo160_144"
  22.402 +              : width==240 ? "logo240_160"
  22.403 +              : height>224 ? "logo256_240"
  22.404 +              :              "logo256_224";
  22.405 +            
  22.406 +            /* Note: This should be 1 second long. */
  22.407 +            for(unsigned frame = 0; frame < LogoFrames; ++frame)
  22.408 +            {
  22.409 +                char Buf[4096];
  22.410 +                sprintf(Buf, "/shares/home/bisqwit/povray/nesvlogo/%s_f%u.tga",
  22.411 +                    background, frame);
  22.412 +                
  22.413 +                FILE*fp = fopen(Buf, "rb");
  22.414 +                if(!fp) // write blackness when missing frames to keep the intro 1 second long:
  22.415 +				{
  22.416 +			        unsigned bytes = width*height*2;
  22.417 +					unsigned char* buf = (unsigned char*)malloc(bytes);
  22.418 +					if(buf)
  22.419 +					{
  22.420 +						memset(buf,0,bytes);
  22.421 +						AVI.Video(width,height,fps_scaled, buf);
  22.422 +						if(debugVideoMessageFunc) videoFramesWritten--;
  22.423 +						free(buf);
  22.424 +					}
  22.425 +				}
  22.426 +				else // write 1 frame of the logo:
  22.427 +				{
  22.428 +					int idlen = fgetc(fp);
  22.429 +					/* Silently ignore all other header data.
  22.430 +					 * These files are assumed to be uncompressed BGR24 tga files with Y swapped.
  22.431 +					 * Even their geometry is assumed to match perfectly.
  22.432 +					 */
  22.433 +					fseek(fp, 1+1+2+2+1+ /*org*/2+2+ /*geo*/2+2+ 1+1+idlen, SEEK_CUR);
  22.434 +
  22.435 +					bool yflip=true;
  22.436 +					std::vector<unsigned char> data(width*height*3);
  22.437 +					for(unsigned y=height; y-->0; )
  22.438 +						fread(&data[y*width*3], 1, width*3, fp);
  22.439 +					fclose(fp);
  22.440 +	                
  22.441 +					std::vector<unsigned short> result(width*height);
  22.442 +					for(unsigned pos=0, max=result.size(); pos<max; ++pos)
  22.443 +					{
  22.444 +						unsigned usepos = pos;
  22.445 +						if(yflip)
  22.446 +						{
  22.447 +							unsigned y = pos/width;
  22.448 +							usepos = (usepos%width) + (height-y-1)*width;
  22.449 +						}
  22.450 +	                    
  22.451 +						unsigned B = data[usepos*3+0];
  22.452 +						unsigned G = data[usepos*3+1];
  22.453 +						unsigned R = data[usepos*3+2];
  22.454 +						result[pos] = ((B*31/255)<<0)
  22.455 +									| ((G*63/255)<<5)
  22.456 +									| ((R*31/255)<<11);
  22.457 +					}
  22.458 +					AVI.Video(width,height,fps_scaled, (const unsigned char*)&result[0]);
  22.459 +					if(debugVideoMessageFunc) videoFramesWritten--;
  22.460 +				}
  22.461 +            }
  22.462 +        }
  22.463 +        AVI.Video(width,height,fps_scaled,  (const unsigned char*) data);
  22.464 +    }
  22.465 +
  22.466 +    void NESVideoLoggingAudio
  22.467 +        (const void*data,
  22.468 +         unsigned rate, unsigned bits, unsigned chans,
  22.469 +         unsigned nsamples)
  22.470 +    {
  22.471 +        if(LoggingEnabled < 2) return;
  22.472 +
  22.473 +        static bool First = true;
  22.474 +        if(First)
  22.475 +        {
  22.476 +            First=false;
  22.477 +            
  22.478 +			const unsigned n = rate; // assumes 1 second of logo to write silence for
  22.479 +            if(n > 0)
  22.480 +			{
  22.481 +				unsigned bytes = n*chans*(bits/8);
  22.482 +				unsigned char* buf = (unsigned char*)malloc(bytes);
  22.483 +				if(buf)
  22.484 +				{
  22.485 +					memset(buf,0,bytes);
  22.486 +					AVI.Audio(rate,bits,chans, buf, n);
  22.487 +					free(buf);
  22.488 +				}
  22.489 +			}
  22.490 +        }
  22.491 +        
  22.492 +        AVI.Audio(rate,bits,chans, (const unsigned char*) data, nsamples);
  22.493 +    }
  22.494 +} /* extern "C" */
  22.495 +
  22.496 +
  22.497 +
  22.498 +static void FlushWrite(FILE* fp, const unsigned char*buf, unsigned length)
  22.499 +{
  22.500 +///	unsigned failures = 0;
  22.501 +///	const static int FAILURE_THRESH = 8092; // don't want to loop infinitely if we keep failing to make progress - actually maybe you would want this, so the checking is disabled
  22.502 +    while(length > 0 /*&& failures < FAILURE_THRESH*/)
  22.503 +    {
  22.504 +        unsigned written = fwrite(buf, 1, length, fp);
  22.505 +///		if(written == 0)
  22.506 +///			failures++;
  22.507 +///		else
  22.508 +///		{
  22.509 +			length -= written;
  22.510 +			buf += written;
  22.511 +///			failures = 0;
  22.512 +///		}
  22.513 +    }
  22.514 +///	if(failures >= FAILURE_THRESH)
  22.515 +///	{
  22.516 +///		fprintf(stderr, "FlushWrite() failed to write %d bytes %d times - giving up.", length, failures);
  22.517 +///		LoggingEnabled = 0;
  22.518 +///	}
  22.519 +}
  22.520 +
  22.521 +// for the UB tech
  22.522 +#undef BGR24
  22.523 +#undef BGR16
  22.524 +#undef BGR15
  22.525 +
  22.526 +#undef u32
  22.527 +#undef u16
  22.528 +#undef s4
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/common/nesvideos-piece.h	Sun Mar 04 14:33:52 2012 -0600
    23.3 @@ -0,0 +1,48 @@
    23.4 +#ifndef NESVPIECEhh
    23.5 +#define NESVPIECEhh
    23.6 +
    23.7 +#define NESVIDEOS_LOGGING 1
    23.8 +
    23.9 +#ifdef __cplusplus
   23.10 +extern "C" {
   23.11 +#endif
   23.12 +
   23.13 +/* Is video logging enabled? 0=no, 1=yes, 2=active. Default value: 0 */ 
   23.14 +extern int LoggingEnabled; 
   23.15 +
   23.16 +/* Get and set the video recording command (shell command) */ 
   23.17 +extern const char* NESVideoGetVideoCmd(); 
   23.18 +extern void NESVideoSetVideoCmd(const char *cmd);
   23.19 +
   23.20 +/* Tells to use these functions for obtaining/releasing FILE pointers for writing - if not specified, popen/pclose are used. */
   23.21 +extern void NESVideoSetFileFuncs( FILE* openFunc(const char *,const char *), int closeFunc(FILE*) );
   23.22 +
   23.23 +/* Tells to call these functions per frame with amounts (seconds and frames) of video and audio progress */
   23.24 +extern void NESVideoEnableDebugging( void videoMessageFunc(const char *msg), void audioMessageFunc(const char *msg) );
   23.25 +
   23.26 +/* Save 1 frame of video. (Assumed to be 16-bit RGB) */ 
   23.27 +/* FPS is scaled by 24 bits (*0x1000000) */
   23.28 +/* Does not do anything if LoggingEnabled<2. */ 
   23.29 +extern void NESVideoLoggingVideo
   23.30 +    (const void*data, unsigned width, unsigned height,
   23.31 +     unsigned fps_scaled); 
   23.32 +
   23.33 +/* Save N bytes of audio. bytes_per_second is required on the first call. */ 
   23.34 +/* Does not do anything if LoggingEnabled<2. */ 
   23.35 +/* The interval of calling this function is not important, as long as all the audio
   23.36 + * data is eventually written without too big delay (5 seconds is too big)
   23.37 + * This function may be called multiple times per video frame, or once per a few video
   23.38 + * frames, or anything in between. Just that all audio data must be written exactly once,
   23.39 + * and in order. */ 
   23.40 +extern void NESVideoLoggingAudio
   23.41 +    (const void*data,
   23.42 +     unsigned rate, unsigned bits, unsigned chans,
   23.43 +     unsigned nsamples);
   23.44 +/* nsamples*chans*(bits/8) = bytes in *data. */
   23.45 +/*     rate*chans*(bits/8) = bytes per second. */
   23.46 +
   23.47 +#ifdef __cplusplus
   23.48 +}
   23.49 +#endif
   23.50 +
   23.51 +#endif
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/common/unzip.cpp	Sun Mar 04 14:33:52 2012 -0600
    24.3 @@ -0,0 +1,1208 @@
    24.4 +/* unzip.c -- IO on .zip files using zlib
    24.5 +   Version 0.15 beta, Mar 19th, 1998,
    24.6 +
    24.7 +   Read unzip.h for more info
    24.8 + */
    24.9 +
   24.10 +#include <cstdio>
   24.11 +#include <cstdlib>
   24.12 +#include <cstring>
   24.13 +#include "zlib.h"
   24.14 +#include "unzip.h"
   24.15 +
   24.16 +#ifdef NO_ERRNO_H
   24.17 +extern int errno;
   24.18 +#else
   24.19 +#   include <cerrno>
   24.20 +#endif
   24.21 +
   24.22 +#ifndef local
   24.23 +#  define local static
   24.24 +#endif
   24.25 +/* compile with -Dlocal if your debugger can't find static symbols */
   24.26 +
   24.27 +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
   24.28 +    !defined(CASESENSITIVITYDEFAULT_NO)
   24.29 +#define CASESENSITIVITYDEFAULT_NO
   24.30 +#endif
   24.31 +
   24.32 +#ifndef UNZ_BUFSIZE
   24.33 +#define UNZ_BUFSIZE (16384)
   24.34 +#endif
   24.35 +
   24.36 +#ifndef UNZ_MAXFILENAMEINZIP
   24.37 +#define UNZ_MAXFILENAMEINZIP (256)
   24.38 +#endif
   24.39 +
   24.40 +#ifndef ALLOC
   24.41 +# define ALLOC(size) (malloc(size))
   24.42 +#endif
   24.43 +#ifndef TRYFREE
   24.44 +# define TRYFREE(p) {if (p) \
   24.45 +						 free(p);}
   24.46 +#endif
   24.47 +
   24.48 +#define SIZECENTRALDIRITEM (0x2e)
   24.49 +#define SIZEZIPLOCALHEADER (0x1e)
   24.50 +
   24.51 +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
   24.52 +
   24.53 +#ifndef SEEK_CUR
   24.54 +#define SEEK_CUR    1
   24.55 +#endif
   24.56 +
   24.57 +#ifndef SEEK_END
   24.58 +#define SEEK_END    2
   24.59 +#endif
   24.60 +
   24.61 +#ifndef SEEK_SET
   24.62 +#define SEEK_SET    0
   24.63 +#endif
   24.64 +
   24.65 +const char unz_copyright[] =
   24.66 +    " unzip 0.15 Copyright 1998 Gilles Vollant ";
   24.67 +
   24.68 +/* unz_file_info_interntal contain internal info about a file in zipfile*/
   24.69 +typedef struct unz_file_info_internal_s
   24.70 +{
   24.71 +	uLong offset_curfile; /* relative offset of local header 4 bytes */
   24.72 +} unz_file_info_internal;
   24.73 +
   24.74 +/* file_in_zip_read_info_s contain internal information about a file in zipfile,
   24.75 +    when reading and decompress it */
   24.76 +typedef struct
   24.77 +{
   24.78 +	char *   read_buffer;           /* internal buffer for compressed data */
   24.79 +	z_stream stream;                /* zLib stream structure for inflate */
   24.80 +
   24.81 +	uLong pos_in_zipfile;           /* position in byte on the zipfile, for fseek*/
   24.82 +	uLong stream_initialised;       /* flag set if stream structure is initialised*/
   24.83 +
   24.84 +	uLong offset_local_extrafield;    /* offset of the local extra field */
   24.85 +	uInt  size_local_extrafield;    /* size of the local extra field */
   24.86 +	uLong pos_local_extrafield;       /* position in the local extra field in read*/
   24.87 +
   24.88 +	uLong crc32;                    /* crc32 of all data uncompressed */
   24.89 +	uLong crc32_wait;               /* crc32 we must obtain after decompress all */
   24.90 +	uLong rest_read_compressed;     /* number of byte to be decompressed */
   24.91 +	uLong rest_read_uncompressed;    /*number of byte to be obtained after decomp*/
   24.92 +	FILE* file;                     /* io structore of the zipfile */
   24.93 +	uLong compression_method;       /* compression method (0==store) */
   24.94 +	uLong byte_before_the_zipfile;    /* byte before the zipfile, (>0 for sfx)*/
   24.95 +} file_in_zip_read_info_s;
   24.96 +
   24.97 +/* unz_s contain internal information about the zipfile
   24.98 + */
   24.99 +typedef struct
  24.100 +{
  24.101 +	FILE*file;                      /* io structore of the zipfile */
  24.102 +	unz_global_info gi;           /* public global information */
  24.103 +	uLong byte_before_the_zipfile;    /* byte before the zipfile, (>0 for sfx)*/
  24.104 +	uLong num_file;                 /* number of the current file in the zipfile*/
  24.105 +	uLong pos_in_central_dir;       /* pos of the current file in the central dir*/
  24.106 +	uLong current_file_ok;          /* flag about the usability of the current file*/
  24.107 +	uLong central_pos;              /* position of the beginning of the central dir*/
  24.108 +
  24.109 +	uLong size_central_dir;         /* size of the central directory  */
  24.110 +	uLong offset_central_dir;       /* offset of start of central directory with
  24.111 +									                               respect to the starting disk number */
  24.112 +
  24.113 +	unz_file_info cur_file_info;     /* public info about the current file in zip*/
  24.114 +	unz_file_info_internal  cur_file_info_internal;    /* private info about it*/
  24.115 +	file_in_zip_read_info_s*pfile_in_zip_read;  /* structure about the current
  24.116 +												   file if we are decompressing it */
  24.117 +} unz_s;
  24.118 +
  24.119 +/* ===========================================================================
  24.120 +     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
  24.121 +   for end of file.
  24.122 +   IN assertion: the stream s has been sucessfully opened for reading.
  24.123 + */
  24.124 +
  24.125 +local int unzlocal_getByte(FILE *fin, int *pi)
  24.126 +{
  24.127 +	unsigned char c;
  24.128 +	int err = fread(&c, 1, 1, fin);
  24.129 +	if (err == 1)
  24.130 +	{
  24.131 +		*pi = (int)c;
  24.132 +		return UNZ_OK;
  24.133 +	}
  24.134 +	else
  24.135 +	{
  24.136 +		if (ferror(fin))
  24.137 +			return UNZ_ERRNO;
  24.138 +		else
  24.139 +			return UNZ_EOF;
  24.140 +	}
  24.141 +}
  24.142 +
  24.143 +/* ===========================================================================
  24.144 +   Reads a long in LSB order from the given gz_stream. Sets
  24.145 + */
  24.146 +local int unzlocal_getShort(FILE *fin, uLong *pX)
  24.147 +{
  24.148 +	uLong x ;
  24.149 +	int   i;
  24.150 +	int   err;
  24.151 +
  24.152 +	err = unzlocal_getByte(fin, &i);
  24.153 +	x   = (uLong)i;
  24.154 +
  24.155 +	if (err == UNZ_OK)
  24.156 +		err = unzlocal_getByte(fin, &i);
  24.157 +	x += ((uLong)i)<<8;
  24.158 +
  24.159 +	if (err == UNZ_OK)
  24.160 +		*pX = x;
  24.161 +	else
  24.162 +		*pX = 0;
  24.163 +	return err;
  24.164 +}
  24.165 +
  24.166 +local int unzlocal_getLong(FILE *fin, uLong *pX)
  24.167 +{
  24.168 +	uLong x ;
  24.169 +	int   i;
  24.170 +	int   err;
  24.171 +
  24.172 +	err = unzlocal_getByte(fin, &i);
  24.173 +	x   = (uLong)i;
  24.174 +
  24.175 +	if (err == UNZ_OK)
  24.176 +		err = unzlocal_getByte(fin, &i);
  24.177 +	x += ((uLong)i)<<8;
  24.178 +
  24.179 +	if (err == UNZ_OK)
  24.180 +		err = unzlocal_getByte(fin, &i);
  24.181 +	x += ((uLong)i)<<16;
  24.182 +
  24.183 +	if (err == UNZ_OK)
  24.184 +		err = unzlocal_getByte(fin, &i);
  24.185 +	x += ((uLong)i)<<24;
  24.186 +
  24.187 +	if (err == UNZ_OK)
  24.188 +		*pX = x;
  24.189 +	else
  24.190 +		*pX = 0;
  24.191 +	return err;
  24.192 +}
  24.193 +
  24.194 +/* My own strcmpi / strcasecmp */
  24.195 +local int strcmpcasenosensitive_internal(const char *fileName1,
  24.196 +                                         const char *fileName2)
  24.197 +{
  24.198 +	for (;;)
  24.199 +	{
  24.200 +		char c1 = *(fileName1++);
  24.201 +		char c2 = *(fileName2++);
  24.202 +		if ((c1 >= 'a') && (c1 <= 'z'))
  24.203 +			c1 -= 0x20;
  24.204 +		if ((c2 >= 'a') && (c2 <= 'z'))
  24.205 +			c2 -= 0x20;
  24.206 +		if (c1 == '\0')
  24.207 +			return ((c2 == '\0') ? 0 : -1);
  24.208 +		if (c2 == '\0')
  24.209 +			return 1;
  24.210 +		if (c1 < c2)
  24.211 +			return -1;
  24.212 +		if (c1 > c2)
  24.213 +			return 1;
  24.214 +	}
  24.215 +}
  24.216 +
  24.217 +#ifdef  CASESENSITIVITYDEFAULT_NO
  24.218 +#define CASESENSITIVITYDEFAULTVALUE 2
  24.219 +#else
  24.220 +#define CASESENSITIVITYDEFAULTVALUE 1
  24.221 +#endif
  24.222 +
  24.223 +#ifndef STRCMPCASENOSENTIVEFUNCTION
  24.224 +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
  24.225 +#endif
  24.226 +
  24.227 +/*
  24.228 +   Compare two filename (fileName1,fileName2).
  24.229 +   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
  24.230 +   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
  24.231 +                                                                or strcasecmp)
  24.232 +   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
  24.233 +        (like 1 on Unix, 2 on Windows)
  24.234 +
  24.235 + */
  24.236 +extern int ZEXPORT unzStringFileNameCompare(const char *fileName1,
  24.237 +                                            const char *fileName2,
  24.238 +                                            int iCaseSensitivity)
  24.239 +{
  24.240 +	if (iCaseSensitivity == 0)
  24.241 +		iCaseSensitivity = CASESENSITIVITYDEFAULTVALUE;
  24.242 +
  24.243 +	if (iCaseSensitivity == 1)
  24.244 +		return strcmp(fileName1, fileName2);
  24.245 +
  24.246 +	return STRCMPCASENOSENTIVEFUNCTION(fileName1, fileName2);
  24.247 +}
  24.248 +
  24.249 +#define BUFREADCOMMENT (0x400)
  24.250 +
  24.251 +/*
  24.252 +   Locate the Central directory of a zipfile (at the end, just before
  24.253 +    the global comment)
  24.254 + */
  24.255 +local uLong unzlocal_SearchCentralDir(FILE *fin)
  24.256 +{
  24.257 +	unsigned char*buf;
  24.258 +	uLong         uSizeFile;
  24.259 +	uLong         uBackRead;
  24.260 +	uLong         uMaxBack  = 0xffff; /* maximum size of global comment */
  24.261 +	uLong         uPosFound = 0;
  24.262 +
  24.263 +	if (fseek(fin, 0, SEEK_END) != 0)
  24.264 +		return 0;
  24.265 +
  24.266 +	uSizeFile = ftell(fin);
  24.267 +
  24.268 +	if (uMaxBack > uSizeFile)
  24.269 +		uMaxBack = uSizeFile;
  24.270 +
  24.271 +	buf = (unsigned char *)ALLOC(BUFREADCOMMENT+4);
  24.272 +	if (buf == NULL)
  24.273 +		return 0;
  24.274 +
  24.275 +	uBackRead = 4;
  24.276 +	while (uBackRead < uMaxBack)
  24.277 +	{
  24.278 +		uLong uReadSize, uReadPos ;
  24.279 +		int   i;
  24.280 +		if (uBackRead+BUFREADCOMMENT > uMaxBack)
  24.281 +			uBackRead = uMaxBack;
  24.282 +		else
  24.283 +			uBackRead += BUFREADCOMMENT;
  24.284 +		uReadPos = uSizeFile-uBackRead ;
  24.285 +
  24.286 +		uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
  24.287 +		            (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
  24.288 +		if (fseek(fin, uReadPos, SEEK_SET) != 0)
  24.289 +			break;
  24.290 +
  24.291 +		if (fread(buf, (uInt)uReadSize, 1, fin) != 1)
  24.292 +			break;
  24.293 +
  24.294 +		for (i = (int)uReadSize-3; (i--) > 0;)
  24.295 +			if (((*(buf+i)) == 0x50) && ((*(buf+i+1)) == 0x4b) &&
  24.296 +			    ((*(buf+i+2)) == 0x05) && ((*(buf+i+3)) == 0x06))
  24.297 +			{
  24.298 +				uPosFound = uReadPos+i;
  24.299 +				break;
  24.300 +			}
  24.301 +
  24.302 +		if (uPosFound != 0)
  24.303 +			break;
  24.304 +	}
  24.305 +	TRYFREE(buf);
  24.306 +	return uPosFound;
  24.307 +}
  24.308 +
  24.309 +/*
  24.310 +   Open a Zip file. path contain the full pathname (by example,
  24.311 +     on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
  24.312 +         "zlib/zlib109.zip".
  24.313 +         If the zipfile cannot be opened (file don't exist or in not valid), the
  24.314 +           return value is NULL.
  24.315 +     Else, the return value is a unzFile Handle, usable with other function
  24.316 +           of this unzip package.
  24.317 + */
  24.318 +extern unzFile ZEXPORT unzOpen(const char *path)
  24.319 +{
  24.320 +	unz_s  us;
  24.321 +	unz_s *s;
  24.322 +	uLong  central_pos, uL;
  24.323 +	FILE * fin ;
  24.324 +
  24.325 +	uLong number_disk;              /* number of the current dist, used for
  24.326 +									                               spaning ZIP, unsupported, always 0*/
  24.327 +	uLong number_disk_with_CD;      /* number the the disk with central dir, used
  24.328 +									                               for spaning ZIP, unsupported, always 0*/
  24.329 +	uLong number_entry_CD;          /* total number of entries in
  24.330 +									   the central dir
  24.331 +									   (same than number_entry on nospan) */
  24.332 +
  24.333 +	int err = UNZ_OK;
  24.334 +
  24.335 +	if (unz_copyright[0] != ' ')
  24.336 +		return NULL;
  24.337 +
  24.338 +	fin = fopen(path, "rb");
  24.339 +	if (fin == NULL)
  24.340 +		return NULL;
  24.341 +
  24.342 +	central_pos = unzlocal_SearchCentralDir(fin);
  24.343 +	if (central_pos == 0)
  24.344 +		err = UNZ_ERRNO;
  24.345 +
  24.346 +	if (fseek(fin, central_pos, SEEK_SET) != 0)
  24.347 +		err = UNZ_ERRNO;
  24.348 +
  24.349 +	/* the signature, already checked */
  24.350 +	if (unzlocal_getLong(fin, &uL) != UNZ_OK)
  24.351 +		err = UNZ_ERRNO;
  24.352 +
  24.353 +	/* number of this disk */
  24.354 +	if (unzlocal_getShort(fin, &number_disk) != UNZ_OK)
  24.355 +		err = UNZ_ERRNO;
  24.356 +
  24.357 +	/* number of the disk with the start of the central directory */
  24.358 +	if (unzlocal_getShort(fin, &number_disk_with_CD) != UNZ_OK)
  24.359 +		err = UNZ_ERRNO;
  24.360 +
  24.361 +	/* total number of entries in the central dir on this disk */
  24.362 +	if (unzlocal_getShort(fin, &us.gi.number_entry) != UNZ_OK)
  24.363 +		err = UNZ_ERRNO;
  24.364 +
  24.365 +	/* total number of entries in the central dir */
  24.366 +	if (unzlocal_getShort(fin, &number_entry_CD) != UNZ_OK)
  24.367 +		err = UNZ_ERRNO;
  24.368 +
  24.369 +	if ((number_entry_CD != us.gi.number_entry) ||
  24.370 +	    (number_disk_with_CD != 0) ||
  24.371 +	    (number_disk != 0))
  24.372 +		err = UNZ_BADZIPFILE;
  24.373 +
  24.374 +	/* size of the central directory */
  24.375 +	if (unzlocal_getLong(fin, &us.size_central_dir) != UNZ_OK)
  24.376 +		err = UNZ_ERRNO;
  24.377 +
  24.378 +	/* offset of start of central directory with respect to the
  24.379 +	      starting disk number */
  24.380 +	if (unzlocal_getLong(fin, &us.offset_central_dir) != UNZ_OK)
  24.381 +		err = UNZ_ERRNO;
  24.382 +
  24.383 +	/* zipfile comment length */
  24.384 +	if (unzlocal_getShort(fin, &us.gi.size_comment) != UNZ_OK)
  24.385 +		err = UNZ_ERRNO;
  24.386 +
  24.387 +	if ((central_pos < us.offset_central_dir+us.size_central_dir) &&
  24.388 +	    (err == UNZ_OK))
  24.389 +		err = UNZ_BADZIPFILE;
  24.390 +
  24.391 +	if (err != UNZ_OK)
  24.392 +	{
  24.393 +		fclose(fin);
  24.394 +		return NULL;
  24.395 +	}
  24.396 +
  24.397 +	us.file = fin;
  24.398 +	us.byte_before_the_zipfile = central_pos -
  24.399 +	                             (us.offset_central_dir+us.size_central_dir);
  24.400 +	us.central_pos       = central_pos;
  24.401 +	us.pfile_in_zip_read = NULL;
  24.402 +
  24.403 +	s  = (unz_s *)ALLOC(sizeof(unz_s));
  24.404 +	*s = us;
  24.405 +	unzGoToFirstFile((unzFile)s);
  24.406 +	return (unzFile)s;
  24.407 +}
  24.408 +
  24.409 +/*
  24.410 +   Close a ZipFile opened with unzipOpen.
  24.411 +   If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
  24.412 +    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
  24.413 +   return UNZ_OK if there is no problem. */
  24.414 +extern int ZEXPORT unzClose(unzFile file)
  24.415 +{
  24.416 +	unz_s*s;
  24.417 +	if (file == NULL)
  24.418 +		return UNZ_PARAMERROR;
  24.419 +	s = (unz_s *)file;
  24.420 +
  24.421 +	if (s->pfile_in_zip_read != NULL)
  24.422 +		unzCloseCurrentFile(file);
  24.423 +
  24.424 +	fclose(s->file);
  24.425 +	TRYFREE(s);
  24.426 +	return UNZ_OK;
  24.427 +}
  24.428 +
  24.429 +/*
  24.430 +   Write info about the ZipFile in the *pglobal_info structure.
  24.431 +   No preparation of the structure is needed
  24.432 +   return UNZ_OK if there is no problem. */
  24.433 +extern int ZEXPORT unzGetGlobalInfo(unzFile file,
  24.434 +                                    unz_global_info *pglobal_info)
  24.435 +{
  24.436 +	unz_s*s;
  24.437 +	if (file == NULL)
  24.438 +		return UNZ_PARAMERROR;
  24.439 +	s = (unz_s *)file;
  24.440 +	*pglobal_info = s->gi;
  24.441 +	return UNZ_OK;
  24.442 +}
  24.443 +
  24.444 +/*
  24.445 +   Translate date/time from Dos format to tm_unz (readable more easilty)
  24.446 + */
  24.447 +local void unzlocal_DosDateToTmuDate(uLong ulDosDate, tm_unz *ptm)
  24.448 +{
  24.449 +	uLong uDate;
  24.450 +	uDate        = (uLong)(ulDosDate>>16);
  24.451 +	ptm->tm_mday = (uInt)(uDate&0x1f) ;
  24.452 +	ptm->tm_mon  =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;
  24.453 +	ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
  24.454 +
  24.455 +	ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
  24.456 +	ptm->tm_min  =  (uInt) ((ulDosDate&0x7E0)/0x20) ;
  24.457 +	ptm->tm_sec  =  (uInt) (2*(ulDosDate&0x1f)) ;
  24.458 +}
  24.459 +
  24.460 +/*
  24.461 +   Get Info about the current file in the zipfile, with internal only info
  24.462 + */
  24.463 +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
  24.464 +                                                  unz_file_info *pfile_info,
  24.465 +                                                  unz_file_info_internal
  24.466 +                                                  *pfile_info_internal,
  24.467 +                                                  char *szFileName,
  24.468 +                                                  uLong fileNameBufferSize,
  24.469 +                                                  void *extraField,
  24.470 +                                                  uLong extraFieldBufferSize,
  24.471 +                                                  char *szComment,
  24.472 +                                                  uLong commentBufferSize));
  24.473 +
  24.474 +local int unzlocal_GetCurrentFileInfoInternal(unzFile file,
  24.475 +                                              unz_file_info *pfile_info,
  24.476 +                                              unz_file_info_internal *pfile_info_internal,
  24.477 +                                              char *szFileName,
  24.478 +                                              uLong fileNameBufferSize,
  24.479 +                                              void *extraField,
  24.480 +                                              uLong extraFieldBufferSize,
  24.481 +                                              char *szComment,
  24.482 +                                              uLong commentBufferSize)
  24.483 +{
  24.484 +	unz_s*        s;
  24.485 +	unz_file_info file_info;
  24.486 +	unz_file_info_internal file_info_internal;
  24.487 +	int   err = UNZ_OK;
  24.488 +	uLong uMagic;
  24.489 +	long  lSeek = 0;
  24.490 +
  24.491 +	if (file == NULL)
  24.492 +		return UNZ_PARAMERROR;
  24.493 +	s = (unz_s *)file;
  24.494 +	if (fseek(s->file, s->pos_in_central_dir+s->byte_before_the_zipfile, SEEK_SET) != 0)
  24.495 +		err = UNZ_ERRNO;
  24.496 +
  24.497 +	/* we check the magic */
  24.498 +	if (err == UNZ_OK)
  24.499 +		if (unzlocal_getLong(s->file, &uMagic) != UNZ_OK)
  24.500 +			err = UNZ_ERRNO;
  24.501 +		else if (uMagic != 0x02014b50)
  24.502 +			err = UNZ_BADZIPFILE;
  24.503 +
  24.504 +	if (unzlocal_getShort(s->file, &file_info.version) != UNZ_OK)
  24.505 +		err = UNZ_ERRNO;
  24.506 +
  24.507 +	if (unzlocal_getShort(s->file, &file_info.version_needed) != UNZ_OK)
  24.508 +		err = UNZ_ERRNO;
  24.509 +
  24.510 +	if (unzlocal_getShort(s->file, &file_info.flag) != UNZ_OK)
  24.511 +		err = UNZ_ERRNO;
  24.512 +
  24.513 +	if (unzlocal_getShort(s->file, &file_info.compression_method) != UNZ_OK)
  24.514 +		err = UNZ_ERRNO;
  24.515 +
  24.516 +	if (unzlocal_getLong(s->file, &file_info.dosDate) != UNZ_OK)
  24.517 +		err = UNZ_ERRNO;
  24.518 +
  24.519 +	unzlocal_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date);
  24.520 +
  24.521 +	if (unzlocal_getLong(s->file, &file_info.crc) != UNZ_OK)
  24.522 +		err = UNZ_ERRNO;
  24.523 +
  24.524 +	if (unzlocal_getLong(s->file, &file_info.compressed_size) != UNZ_OK)
  24.525 +		err = UNZ_ERRNO;
  24.526 +
  24.527 +	if (unzlocal_getLong(s->file, &file_info.uncompressed_size) != UNZ_OK)
  24.528 +		err = UNZ_ERRNO;
  24.529 +
  24.530 +	if (unzlocal_getShort(s->file, &file_info.size_filename) != UNZ_OK)
  24.531 +		err = UNZ_ERRNO;
  24.532 +
  24.533 +	if (unzlocal_getShort(s->file, &file_info.size_file_extra) != UNZ_OK)
  24.534 +		err = UNZ_ERRNO;
  24.535 +
  24.536 +	if (unzlocal_getShort(s->file, &file_info.size_file_comment) != UNZ_OK)
  24.537 +		err = UNZ_ERRNO;
  24.538 +
  24.539 +	if (unzlocal_getShort(s->file, &file_info.disk_num_start) != UNZ_OK)
  24.540 +		err = UNZ_ERRNO;
  24.541 +
  24.542 +	if (unzlocal_getShort(s->file, &file_info.internal_fa) != UNZ_OK)
  24.543 +		err = UNZ_ERRNO;
  24.544 +
  24.545 +	if (unzlocal_getLong(s->file, &file_info.external_fa) != UNZ_OK)
  24.546 +		err = UNZ_ERRNO;
  24.547 +
  24.548 +	if (unzlocal_getLong(s->file, &file_info_internal.offset_curfile) != UNZ_OK)
  24.549 +		err = UNZ_ERRNO;
  24.550 +
  24.551 +	lSeek += file_info.size_filename;
  24.552 +	if ((err == UNZ_OK) && (szFileName != NULL))
  24.553 +	{
  24.554 +		uLong uSizeRead ;
  24.555 +		if (file_info.size_filename < fileNameBufferSize)
  24.556 +		{
  24.557 +			*(szFileName+file_info.size_filename) = '\0';
  24.558 +			uSizeRead = file_info.size_filename;
  24.559 +		}
  24.560 +		else
  24.561 +			uSizeRead = fileNameBufferSize;
  24.562 +
  24.563 +		if ((file_info.size_filename > 0) && (fileNameBufferSize > 0))
  24.564 +			if (fread(szFileName, (uInt)uSizeRead, 1, s->file) != 1)
  24.565 +				err = UNZ_ERRNO;
  24.566 +		lSeek -= uSizeRead;
  24.567 +	}
  24.568 +
  24.569 +	if ((err == UNZ_OK) && (extraField != NULL))
  24.570 +	{
  24.571 +		uLong uSizeRead ;
  24.572 +		if (file_info.size_file_extra < extraFieldBufferSize)
  24.573 +			uSizeRead = file_info.size_file_extra;
  24.574 +		else
  24.575 +			uSizeRead = extraFieldBufferSize;
  24.576 +
  24.577 +		if (lSeek != 0)
  24.578 +			if (fseek(s->file, lSeek, SEEK_CUR) == 0)
  24.579 +				lSeek = 0;
  24.580 +			else
  24.581 +				err = UNZ_ERRNO;
  24.582 +		if ((file_info.size_file_extra > 0) && (extraFieldBufferSize > 0))
  24.583 +			if (fread(extraField, (uInt)uSizeRead, 1, s->file) != 1)
  24.584 +				err = UNZ_ERRNO;
  24.585 +		lSeek += file_info.size_file_extra - uSizeRead;
  24.586 +	}
  24.587 +	else
  24.588 +		lSeek += file_info.size_file_extra;
  24.589 +
  24.590 +	if ((err == UNZ_OK) && (szComment != NULL))
  24.591 +	{
  24.592 +		uLong uSizeRead ;
  24.593 +		if (file_info.size_file_comment < commentBufferSize)
  24.594 +		{
  24.595 +			*(szComment+file_info.size_file_comment) = '\0';
  24.596 +			uSizeRead = file_info.size_file_comment;
  24.597 +		}
  24.598 +		else
  24.599 +			uSizeRead = commentBufferSize;
  24.600 +
  24.601 +		if (lSeek != 0)
  24.602 +			if (fseek(s->file, lSeek, SEEK_CUR) == 0)
  24.603 +				lSeek = 0;
  24.604 +			else
  24.605 +				err = UNZ_ERRNO;
  24.606 +		if ((file_info.size_file_comment > 0) && (commentBufferSize > 0))
  24.607 +			if (fread(szComment, (uInt)uSizeRead, 1, s->file) != 1)
  24.608 +				err = UNZ_ERRNO;
  24.609 +		lSeek += file_info.size_file_comment - uSizeRead;
  24.610 +	}
  24.611 +	else
  24.612 +		lSeek += file_info.size_file_comment;
  24.613 +
  24.614 +	if ((err == UNZ_OK) && (pfile_info != NULL))
  24.615 +		*pfile_info = file_info;
  24.616 +
  24.617 +	if ((err == UNZ_OK) && (pfile_info_internal != NULL))
  24.618 +		*pfile_info_internal = file_info_internal;
  24.619 +
  24.620 +	return err;
  24.621 +}
  24.622 +
  24.623 +/*
  24.624 +   Write info about the ZipFile in the *pglobal_info structure.
  24.625 +   No preparation of the structure is needed
  24.626 +   return UNZ_OK if there is no problem.
  24.627 + */
  24.628 +extern int ZEXPORT unzGetCurrentFileInfo(unzFile file,
  24.629 +                                         unz_file_info *pfile_info,
  24.630 +                                         char *szFileName,
  24.631 +                                         uLong fileNameBufferSize,
  24.632 +                                         void *extraField,
  24.633 +                                         uLong extraFieldBufferSize,
  24.634 +                                         char *szComment,
  24.635 +                                         uLong commentBufferSize)
  24.636 +{
  24.637 +	return unzlocal_GetCurrentFileInfoInternal(file, pfile_info, NULL,
  24.638 +	                                           szFileName, fileNameBufferSize,
  24.639 +	                                           extraField, extraFieldBufferSize,
  24.640 +	                                           szComment, commentBufferSize);
  24.641 +}
  24.642 +
  24.643 +/*
  24.644 +   Set the current file of the zipfile to the first file.
  24.645 +   return UNZ_OK if there is no problem
  24.646 + */
  24.647 +extern int ZEXPORT unzGoToFirstFile(unzFile file)
  24.648 +{
  24.649 +	int   err = UNZ_OK;
  24.650 +	unz_s*s;
  24.651 +	if (file == NULL)
  24.652 +		return UNZ_PARAMERROR;
  24.653 +	s = (unz_s *)file;
  24.654 +	s->pos_in_central_dir = s->offset_central_dir;
  24.655 +	s->num_file = 0;
  24.656 +	err         = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info,
  24.657 +	                                                  &s->cur_file_info_internal,
  24.658 +	                                                  NULL, 0, NULL, 0, NULL, 0);
  24.659 +	s->current_file_ok = (err == UNZ_OK);
  24.660 +	return err;
  24.661 +}
  24.662 +
  24.663 +/*
  24.664 +   Set the current file of the zipfile to the next file.
  24.665 +   return UNZ_OK if there is no problem
  24.666 +   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
  24.667 + */
  24.668 +extern int ZEXPORT unzGoToNextFile(unzFile file)
  24.669 +{
  24.670 +	unz_s*s;
  24.671 +	int   err;
  24.672 +
  24.673 +	if (file == NULL)
  24.674 +		return UNZ_PARAMERROR;
  24.675 +	s = (unz_s *)file;
  24.676 +	if (!s->current_file_ok)
  24.677 +		return UNZ_END_OF_LIST_OF_FILE;
  24.678 +	if (s->num_file+1 == s->gi.number_entry)
  24.679 +		return UNZ_END_OF_LIST_OF_FILE;
  24.680 +
  24.681 +	s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
  24.682 +	                         s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
  24.683 +	s->num_file++;
  24.684 +	err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info,
  24.685 +	                                          &s->cur_file_info_internal,
  24.686 +	                                          NULL, 0, NULL, 0, NULL, 0);
  24.687 +	s->current_file_ok = (err == UNZ_OK);
  24.688 +	return err;
  24.689 +}
  24.690 +
  24.691 +/*
  24.692 +   Try locate the file szFileName in the zipfile.
  24.693 +   For the iCaseSensitivity signification, see unzipStringFileNameCompare
  24.694 +
  24.695 +   return value :
  24.696 +   UNZ_OK if the file is found. It becomes the current file.
  24.697 +   UNZ_END_OF_LIST_OF_FILE if the file is not found
  24.698 + */
  24.699 +extern int ZEXPORT unzLocateFile(unzFile file,
  24.700 +                                 const char *szFileName,
  24.701 +                                 int iCaseSensitivity)
  24.702 +{
  24.703 +	unz_s*s;
  24.704 +	int   err;
  24.705 +
  24.706 +	uLong num_fileSaved;
  24.707 +	uLong pos_in_central_dirSaved;
  24.708 +
  24.709 +	if (file == NULL)
  24.710 +		return UNZ_PARAMERROR;
  24.711 +
  24.712 +	if (strlen(szFileName) >= UNZ_MAXFILENAMEINZIP)
  24.713 +		return UNZ_PARAMERROR;
  24.714 +
  24.715 +	s = (unz_s *)file;
  24.716 +	if (!s->current_file_ok)
  24.717 +		return UNZ_END_OF_LIST_OF_FILE;
  24.718 +
  24.719 +	num_fileSaved = s->num_file;
  24.720 +	pos_in_central_dirSaved = s->pos_in_central_dir;
  24.721 +
  24.722 +	err = unzGoToFirstFile(file);
  24.723 +
  24.724 +	while (err == UNZ_OK)
  24.725 +	{
  24.726 +		char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
  24.727 +		unzGetCurrentFileInfo(file, NULL,
  24.728 +		                      szCurrentFileName, sizeof(szCurrentFileName)-1,
  24.729 +		                      NULL, 0, NULL, 0);
  24.730 +		if (unzStringFileNameCompare(szCurrentFileName,
  24.731 +		                             szFileName, iCaseSensitivity) == 0)
  24.732 +			return UNZ_OK;
  24.733 +		err = unzGoToNextFile(file);
  24.734 +	}
  24.735 +
  24.736 +	s->num_file = num_fileSaved ;
  24.737 +	s->pos_in_central_dir = pos_in_central_dirSaved ;
  24.738 +	return err;
  24.739 +}
  24.740 +
  24.741 +/*
  24.742 +   Read the local header of the current zipfile
  24.743 +   Check the coherency of the local header and info in the end of central
  24.744 +        directory about this file
  24.745 +   store in *piSizeVar the size of extra info in local header
  24.746 +        (filename and size of extra field data)
  24.747 + */
  24.748 +local int unzlocal_CheckCurrentFileCoherencyHeader(unz_s *s,
  24.749 +                                                   uInt *piSizeVar,
  24.750 +                                                   uLong *poffset_local_extrafield,
  24.751 +                                                   uInt *psize_local_extrafield)
  24.752 +{
  24.753 +	uLong uMagic, uData, uFlags;
  24.754 +	uLong size_filename;
  24.755 +	uLong size_extra_field;
  24.756 +	int   err = UNZ_OK;
  24.757 +
  24.758 +	*piSizeVar = 0;
  24.759 +	*poffset_local_extrafield = 0;
  24.760 +	*psize_local_extrafield   = 0;
  24.761 +
  24.762 +	if (fseek(s->file, s->cur_file_info_internal.offset_curfile +
  24.763 +	          s->byte_before_the_zipfile, SEEK_SET) != 0)
  24.764 +		return UNZ_ERRNO;
  24.765 +
  24.766 +	if (err == UNZ_OK)
  24.767 +		if (unzlocal_getLong(s->file, &uMagic) != UNZ_OK)
  24.768 +			err = UNZ_ERRNO;
  24.769 +		else if (uMagic != 0x04034b50)
  24.770 +			err = UNZ_BADZIPFILE;
  24.771 +
  24.772 +	if (unzlocal_getShort(s->file, &uData) != UNZ_OK)
  24.773 +		err = UNZ_ERRNO;
  24.774 +/*
  24.775 +        else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
  24.776 +                err=UNZ_BADZIPFILE;
  24.777 + */
  24.778 +	if (unzlocal_getShort(s->file, &uFlags) != UNZ_OK)
  24.779 +		err = UNZ_ERRNO;
  24.780 +
  24.781 +	if (unzlocal_getShort(s->file, &uData) != UNZ_OK)
  24.782 +		err = UNZ_ERRNO;
  24.783 +	else if ((err == UNZ_OK) && (uData != s->cur_file_info.compression_method))
  24.784 +		err = UNZ_BADZIPFILE;
  24.785 +
  24.786 +	if ((err == UNZ_OK) && (s->cur_file_info.compression_method != 0) &&
  24.787 +	    (s->cur_file_info.compression_method != Z_DEFLATED))
  24.788 +		err = UNZ_BADZIPFILE;
  24.789 +
  24.790 +	if (unzlocal_getLong(s->file, &uData) != UNZ_OK)    /* date/time */
  24.791 +		err = UNZ_ERRNO;
  24.792 +
  24.793 +	if (unzlocal_getLong(s->file, &uData) != UNZ_OK)    /* crc */
  24.794 +		err = UNZ_ERRNO;
  24.795 +	else if ((err == UNZ_OK) && (uData != s->cur_file_info.crc) &&
  24.796 +	         ((uFlags & 8) == 0))
  24.797 +		err = UNZ_BADZIPFILE;
  24.798 +
  24.799 +	if (unzlocal_getLong(s->file, &uData) != UNZ_OK)    /* size compr */
  24.800 +		err = UNZ_ERRNO;
  24.801 +	else if ((err == UNZ_OK) && (uData != s->cur_file_info.compressed_size) &&
  24.802 +	         ((uFlags & 8) == 0))
  24.803 +		err = UNZ_BADZIPFILE;
  24.804 +
  24.805 +	if (unzlocal_getLong(s->file, &uData) != UNZ_OK)    /* size uncompr */
  24.806 +		err = UNZ_ERRNO;
  24.807 +	else if ((err == UNZ_OK) && (uData != s->cur_file_info.uncompressed_size) &&
  24.808 +	         ((uFlags & 8) == 0))
  24.809 +		err = UNZ_BADZIPFILE;
  24.810 +
  24.811 +	if (unzlocal_getShort(s->file, &size_filename) != UNZ_OK)
  24.812 +		err = UNZ_ERRNO;
  24.813 +	else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename))
  24.814 +		err = UNZ_BADZIPFILE;
  24.815 +
  24.816 +	*piSizeVar += (uInt)size_filename;
  24.817 +
  24.818 +	if (unzlocal_getShort(s->file, &size_extra_field) != UNZ_OK)
  24.819 +		err = UNZ_ERRNO;
  24.820 +	*poffset_local_extrafield = s->cur_file_info_internal.offset_curfile +
  24.821 +	                            SIZEZIPLOCALHEADER + size_filename;
  24.822 +	*psize_local_extrafield = (uInt)size_extra_field;
  24.823 +
  24.824 +	*piSizeVar += (uInt)size_extra_field;
  24.825 +
  24.826 +	return err;
  24.827 +}
  24.828 +
  24.829 +/*
  24.830 +   Open for reading data the current file in the zipfile.
  24.831 +   If there is no error and the file is opened, the return value is UNZ_OK.
  24.832 + */
  24.833 +extern int ZEXPORT unzOpenCurrentFile(unzFile file)
  24.834 +{
  24.835 +	int   err = UNZ_OK;
  24.836 +	int   Store;
  24.837 +	uInt  iSizeVar;
  24.838 +	unz_s*s;
  24.839 +	file_in_zip_read_info_s*pfile_in_zip_read_info;
  24.840 +	uLong offset_local_extrafield;      /* offset of the local extra field */
  24.841 +	uInt  size_local_extrafield;        /* size of the local extra field */
  24.842 +
  24.843 +	if (file == NULL)
  24.844 +		return UNZ_PARAMERROR;
  24.845 +	s = (unz_s *)file;
  24.846 +	if (!s->current_file_ok)
  24.847 +		return UNZ_PARAMERROR;
  24.848 +
  24.849 +	if (s->pfile_in_zip_read != NULL)
  24.850 +		unzCloseCurrentFile(file);
  24.851 +
  24.852 +	if (unzlocal_CheckCurrentFileCoherencyHeader(s, &iSizeVar,
  24.853 +	                                             &offset_local_extrafield, &size_local_extrafield) != UNZ_OK)
  24.854 +		return UNZ_BADZIPFILE;
  24.855 +
  24.856 +	pfile_in_zip_read_info = (file_in_zip_read_info_s *)
  24.857 +	                         ALLOC(sizeof(file_in_zip_read_info_s));
  24.858 +	if (pfile_in_zip_read_info == NULL)
  24.859 +		return UNZ_INTERNALERROR;
  24.860 +
  24.861 +	pfile_in_zip_read_info->read_buffer = (char *)ALLOC(UNZ_BUFSIZE);
  24.862 +	pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
  24.863 +	pfile_in_zip_read_info->size_local_extrafield   = size_local_extrafield;
  24.864 +	pfile_in_zip_read_info->pos_local_extrafield    = 0;
  24.865 +
  24.866 +	if (pfile_in_zip_read_info->read_buffer == NULL)
  24.867 +	{
  24.868 +		TRYFREE(pfile_in_zip_read_info);
  24.869 +		return UNZ_INTERNALERROR;
  24.870 +	}
  24.871 +
  24.872 +	pfile_in_zip_read_info->stream_initialised = 0;
  24.873 +
  24.874 +	if ((s->cur_file_info.compression_method != 0) &&
  24.875 +	    (s->cur_file_info.compression_method != Z_DEFLATED))
  24.876 +		err = UNZ_BADZIPFILE;
  24.877 +	Store = s->cur_file_info.compression_method == 0;
  24.878 +
  24.879 +	pfile_in_zip_read_info->crc32_wait         = s->cur_file_info.crc;
  24.880 +	pfile_in_zip_read_info->crc32              = 0;
  24.881 +	pfile_in_zip_read_info->compression_method =
  24.882 +	    s->cur_file_info.compression_method;
  24.883 +	pfile_in_zip_read_info->file = s->file;
  24.884 +	pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile;
  24.885 +
  24.886 +	pfile_in_zip_read_info->stream.total_out = 0;
  24.887 +
  24.888 +	if (!Store)
  24.889 +	{
  24.890 +		pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
  24.891 +		pfile_in_zip_read_info->stream.zfree  = (free_func)0;
  24.892 +		pfile_in_zip_read_info->stream.opaque = (voidpf)0;
  24.893 +
  24.894 +		err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
  24.895 +		if (err == Z_OK)
  24.896 +			pfile_in_zip_read_info->stream_initialised = 1;
  24.897 +		/* windowBits is passed < 0 to tell that there is no zlib header.
  24.898 +		 * Note that in this case inflate *requires* an extra "dummy" byte
  24.899 +		 * after the compressed stream in order to complete decompression and
  24.900 +		 * return Z_STREAM_END.
  24.901 +		 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
  24.902 +		 * size of both compressed and uncompressed data
  24.903 +		 */
  24.904 +	}
  24.905 +	pfile_in_zip_read_info->rest_read_compressed =
  24.906 +	    s->cur_file_info.compressed_size ;
  24.907 +	pfile_in_zip_read_info->rest_read_uncompressed =
  24.908 +	    s->cur_file_info.uncompressed_size ;
  24.909 +
  24.910 +	pfile_in_zip_read_info->pos_in_zipfile =
  24.911 +	    s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
  24.912 +	    iSizeVar;
  24.913 +
  24.914 +	pfile_in_zip_read_info->stream.avail_in = (uInt)0;
  24.915 +
  24.916 +	s->pfile_in_zip_read = pfile_in_zip_read_info;
  24.917 +	return UNZ_OK;
  24.918 +}
  24.919 +
  24.920 +/*
  24.921 +   Read bytes from the current file.
  24.922 +   buf contain buffer where data must be copied
  24.923 +   len the size of buf.
  24.924 +
  24.925 +   return the number of byte copied if somes bytes are copied
  24.926 +   return 0 if the end of file was reached
  24.927 +   return <0 with error code if there is an error
  24.928 +    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
  24.929 + */
  24.930 +extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len)
  24.931 +{
  24.932 +	int   err   = UNZ_OK;
  24.933 +	uInt  iRead = 0;
  24.934 +	unz_s*s;
  24.935 +	file_in_zip_read_info_s*pfile_in_zip_read_info;
  24.936 +	if (file == NULL)
  24.937 +		return UNZ_PARAMERROR;
  24.938 +	s = (unz_s *)file;
  24.939 +	pfile_in_zip_read_info = s->pfile_in_zip_read;
  24.940 +
  24.941 +	if (pfile_in_zip_read_info == NULL)
  24.942 +		return UNZ_PARAMERROR;
  24.943 +
  24.944 +	if ((pfile_in_zip_read_info->read_buffer == NULL))
  24.945 +		return UNZ_END_OF_LIST_OF_FILE;
  24.946 +	if (len == 0)
  24.947 +		return 0;
  24.948 +
  24.949 +	pfile_in_zip_read_info->stream.next_out = (Bytef *)buf;
  24.950 +
  24.951 +	pfile_in_zip_read_info->stream.avail_out = (uInt)len;
  24.952 +
  24.953 +	if (len > pfile_in_zip_read_info->rest_read_uncompressed)
  24.954 +		pfile_in_zip_read_info->stream.avail_out =
  24.955 +		    (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
  24.956 +
  24.957 +	while (pfile_in_zip_read_info->stream.avail_out > 0)
  24.958 +	{
  24.959 +		if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
  24.960 +		    (pfile_in_zip_read_info->rest_read_compressed > 0))
  24.961 +		{
  24.962 +			uInt uReadThis = UNZ_BUFSIZE;
  24.963 +			if (pfile_in_zip_read_info->rest_read_compressed < uReadThis)
  24.964 +				uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
  24.965 +			if (uReadThis == 0)
  24.966 +				return UNZ_EOF;
  24.967 +			if (fseek(pfile_in_zip_read_info->file,
  24.968 +			          pfile_in_zip_read_info->pos_in_zipfile +
  24.969 +			          pfile_in_zip_read_info->byte_before_the_zipfile, SEEK_SET) != 0)
  24.970 +				return UNZ_ERRNO;
  24.971 +			if (fread(pfile_in_zip_read_info->read_buffer, uReadThis, 1,
  24.972 +			          pfile_in_zip_read_info->file) != 1)
  24.973 +				return UNZ_ERRNO;
  24.974 +			pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
  24.975 +
  24.976 +			pfile_in_zip_read_info->rest_read_compressed -= uReadThis;
  24.977 +
  24.978 +			pfile_in_zip_read_info->stream.next_in =
  24.979 +			    (Bytef *)pfile_in_zip_read_info->read_buffer;
  24.980 +			pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
  24.981 +		}
  24.982 +
  24.983 +		if (pfile_in_zip_read_info->compression_method == 0)
  24.984 +		{
  24.985 +			uInt uDoCopy, i ;
  24.986 +			if (pfile_in_zip_read_info->stream.avail_out <
  24.987 +			    pfile_in_zip_read_info->stream.avail_in)
  24.988 +				uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
  24.989 +			else
  24.990 +				uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
  24.991 +
  24.992 +			for (i = 0; i < uDoCopy; i++)
  24.993 +				*(pfile_in_zip_read_info->stream.next_out+i) =
  24.994 +				    *(pfile_in_zip_read_info->stream.next_in+i);
  24.995 +
  24.996 +			pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
  24.997 +			                                      pfile_in_zip_read_info->stream.next_out,
  24.998 +			                                      uDoCopy);
  24.999 +			pfile_in_zip_read_info->rest_read_uncompressed -= uDoCopy;
 24.1000 +			pfile_in_zip_read_info->stream.avail_in        -= uDoCopy;
 24.1001 +			pfile_in_zip_read_info->stream.avail_out       -= uDoCopy;
 24.1002 +			pfile_in_zip_read_info->stream.next_out        += uDoCopy;
 24.1003 +			pfile_in_zip_read_info->stream.next_in         += uDoCopy;
 24.1004 +			pfile_in_zip_read_info->stream.total_out       += uDoCopy;
 24.1005 +			iRead += uDoCopy;
 24.1006 +		}
 24.1007 +		else
 24.1008 +		{
 24.1009 +			uLong        uTotalOutBefore, uTotalOutAfter;
 24.1010 +			const Bytef *bufBefore;
 24.1011 +			uLong        uOutThis;
 24.1012 +			int flush = Z_SYNC_FLUSH;
 24.1013 +
 24.1014 +			uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
 24.1015 +			bufBefore       = pfile_in_zip_read_info->stream.next_out;
 24.1016 +
 24.1017 +			/*
 24.1018 +			   if ((pfile_in_zip_read_info->rest_read_uncompressed ==
 24.1019 +			         pfile_in_zip_read_info->stream.avail_out) &&
 24.1020 +			        (pfile_in_zip_read_info->rest_read_compressed == 0))
 24.1021 +			        flush = Z_FINISH;
 24.1022 +			 */
 24.1023 +			err = inflate(&pfile_in_zip_read_info->stream, flush);
 24.1024 +
 24.1025 +			uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
 24.1026 +			uOutThis       = uTotalOutAfter-uTotalOutBefore;
 24.1027 +
 24.1028 +			pfile_in_zip_read_info->crc32 =
 24.1029 +			    crc32(pfile_in_zip_read_info->crc32, bufBefore,
 24.1030 +			          (uInt)(uOutThis));
 24.1031 +
 24.1032 +			pfile_in_zip_read_info->rest_read_uncompressed -=
 24.1033 +			    uOutThis;
 24.1034 +
 24.1035 +			iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
 24.1036 +
 24.1037 +			if (err == Z_STREAM_END)
 24.1038 +				return (iRead == 0) ? UNZ_EOF : iRead;
 24.1039 +			if (err != Z_OK)
 24.1040 +				break;
 24.1041 +		}
 24.1042 +	}
 24.1043 +
 24.1044 +	if (err == Z_OK)
 24.1045 +		return iRead;
 24.1046 +	return err;
 24.1047 +}
 24.1048 +
 24.1049 +/*
 24.1050 +   Give the current position in uncompressed data
 24.1051 + */
 24.1052 +extern z_off_t ZEXPORT unztell(unzFile file)
 24.1053 +{
 24.1054 +	unz_s*s;
 24.1055 +	file_in_zip_read_info_s*pfile_in_zip_read_info;
 24.1056 +	if (file == NULL)
 24.1057 +		return UNZ_PARAMERROR;
 24.1058 +	s = (unz_s *)file;
 24.1059 +	pfile_in_zip_read_info = s->pfile_in_zip_read;
 24.1060 +
 24.1061 +	if (pfile_in_zip_read_info == NULL)
 24.1062 +		return UNZ_PARAMERROR;
 24.1063 +
 24.1064 +	return (z_off_t)pfile_in_zip_read_info->stream.total_out;
 24.1065 +}
 24.1066 +
 24.1067 +/*
 24.1068 +   return 1 if the end of file was reached, 0 elsewhere
 24.1069 + */
 24.1070 +extern int ZEXPORT unzeof(unzFile file)
 24.1071 +{
 24.1072 +	unz_s*s;
 24.1073 +	file_in_zip_read_info_s*pfile_in_zip_read_info;
 24.1074 +	if (file == NULL)
 24.1075 +		return UNZ_PARAMERROR;
 24.1076 +	s = (unz_s *)file;
 24.1077 +	pfile_in_zip_read_info = s->pfile_in_zip_read;
 24.1078 +
 24.1079 +	if (pfile_in_zip_read_info == NULL)
 24.1080 +		return UNZ_PARAMERROR;
 24.1081 +
 24.1082 +	if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
 24.1083 +		return 1;
 24.1084 +	else
 24.1085 +		return 0;
 24.1086 +}
 24.1087 +
 24.1088 +/*
 24.1089 +   Read extra field from the current file (opened by unzOpenCurrentFile)
 24.1090 +   This is the local-header version of the extra field (sometimes, there is
 24.1091 +    more info in the local-header version than in the central-header)
 24.1092 +
 24.1093 +   if buf==NULL, it return the size of the local extra field that can be read
 24.1094 +
 24.1095 +   if buf!=NULL, len is the size of the buffer, the extra header is copied in
 24.1096 +        buf.
 24.1097 +   the return value is the number of bytes copied in buf, or (if <0)
 24.1098 +        the error code
 24.1099 + */
 24.1100 +extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len)
 24.1101 +{
 24.1102 +	unz_s*s;
 24.1103 +	file_in_zip_read_info_s*pfile_in_zip_read_info;
 24.1104 +	uInt  read_now;
 24.1105 +	uLong size_to_read;
 24.1106 +
 24.1107 +	if (file == NULL)
 24.1108 +		return UNZ_PARAMERROR;
 24.1109 +	s = (unz_s *)file;
 24.1110 +	pfile_in_zip_read_info = s->pfile_in_zip_read;
 24.1111 +
 24.1112 +	if (pfile_in_zip_read_info == NULL)
 24.1113 +		return UNZ_PARAMERROR;
 24.1114 +
 24.1115 +	size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
 24.1116 +	                pfile_in_zip_read_info->pos_local_extrafield);
 24.1117 +
 24.1118 +	if (buf == NULL)
 24.1119 +		return (int)size_to_read;
 24.1120 +
 24.1121 +	if (len > size_to_read)
 24.1122 +		read_now = (uInt)size_to_read;
 24.1123 +	else
 24.1124 +		read_now = (uInt)len ;
 24.1125 +
 24.1126 +	if (read_now == 0)
 24.1127 +		return 0;
 24.1128 +
 24.1129 +	if (fseek(pfile_in_zip_read_info->file,
 24.1130 +	          pfile_in_zip_read_info->offset_local_extrafield +
 24.1131 +	          pfile_in_zip_read_info->pos_local_extrafield, SEEK_SET) != 0)
 24.1132 +		return UNZ_ERRNO;
 24.1133 +
 24.1134 +	if (fread(buf, (uInt)size_to_read, 1, pfile_in_zip_read_info->file) != 1)
 24.1135 +		return UNZ_ERRNO;
 24.1136 +
 24.1137 +	return (int)read_now;
 24.1138 +}
 24.1139 +
 24.1140 +/*
 24.1141 +   Close the file in zip opened with unzipOpenCurrentFile
 24.1142 +   Return UNZ_CRCERROR if all the file was read but the CRC is not good
 24.1143 + */
 24.1144 +extern int ZEXPORT unzCloseCurrentFile(unzFile file)
 24.1145 +{
 24.1146 +	int err = UNZ_OK;
 24.1147 +
 24.1148 +	unz_s*s;
 24.1149 +	file_in_zip_read_info_s*pfile_in_zip_read_info;
 24.1150 +	if (file == NULL)
 24.1151 +		return UNZ_PARAMERROR;
 24.1152 +	s = (unz_s *)file;
 24.1153 +	pfile_in_zip_read_info = s->pfile_in_zip_read;
 24.1154 +
 24.1155 +	if (pfile_in_zip_read_info == NULL)
 24.1156 +		return UNZ_PARAMERROR;
 24.1157 +
 24.1158 +	if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
 24.1159 +	{
 24.1160 +		if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
 24.1161 +			err = UNZ_CRCERROR;
 24.1162 +	}
 24.1163 +
 24.1164 +	TRYFREE(pfile_in_zip_read_info->read_buffer);
 24.1165 +	pfile_in_zip_read_info->read_buffer = NULL;
 24.1166 +	if (pfile_in_zip_read_info->stream_initialised)
 24.1167 +		inflateEnd(&pfile_in_zip_read_info->stream);
 24.1168 +
 24.1169 +	pfile_in_zip_read_info->stream_initialised = 0;
 24.1170 +	TRYFREE(pfile_in_zip_read_info);
 24.1171 +
 24.1172 +	s->pfile_in_zip_read = NULL;
 24.1173 +
 24.1174 +	return err;
 24.1175 +}
 24.1176 +
 24.1177 +/*
 24.1178 +   Get the global comment string of the ZipFile, in the szComment buffer.
 24.1179 +   uSizeBuf is the size of the szComment buffer.
 24.1180 +   return the number of byte copied or an error code <0
 24.1181 + */
 24.1182 +extern int ZEXPORT unzGetGlobalComment(unzFile file,
 24.1183 +                                       char *szComment,
 24.1184 +                                       uLong uSizeBuf)
 24.1185 +{
 24.1186 +	//int err=UNZ_OK;
 24.1187 +	unz_s*s;
 24.1188 +	uLong uReadThis ;
 24.1189 +	if (file == NULL)
 24.1190 +		return UNZ_PARAMERROR;
 24.1191 +	s = (unz_s *)file;
 24.1192 +
 24.1193 +	uReadThis = uSizeBuf;
 24.1194 +	if (uReadThis > s->gi.size_comment)
 24.1195 +		uReadThis = s->gi.size_comment;
 24.1196 +
 24.1197 +	if (fseek(s->file, s->central_pos+22, SEEK_SET) != 0)
 24.1198 +		return UNZ_ERRNO;
 24.1199 +
 24.1200 +	if (uReadThis > 0)
 24.1201 +	{
 24.1202 +		*szComment = '\0';
 24.1203 +		if (fread(szComment, (uInt)uReadThis, 1, s->file) != 1)
 24.1204 +			return UNZ_ERRNO;
 24.1205 +	}
 24.1206 +
 24.1207 +	if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
 24.1208 +		*(szComment+s->gi.size_comment) = '\0';
 24.1209 +	return (int)uReadThis;
 24.1210 +}
 24.1211 +
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/common/unzip.h	Sun Mar 04 14:33:52 2012 -0600
    25.3 @@ -0,0 +1,275 @@
    25.4 +/* unzip.h -- IO for uncompress .zip files using zlib 
    25.5 +   Version 0.15 beta, Mar 19th, 1998,
    25.6 +
    25.7 +   Copyright (C) 1998 Gilles Vollant
    25.8 +
    25.9 +   This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
   25.10 +     WinZip, InfoZip tools and compatible.
   25.11 +   Encryption and multi volume ZipFile (span) are not supported.
   25.12 +   Old compressions used by old PKZip 1.x are not supported
   25.13 +
   25.14 +   THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
   25.15 +   CAN CHANGE IN FUTURE VERSION !!
   25.16 +   I WAIT FEEDBACK at mail info@winimage.com
   25.17 +   Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
   25.18 +
   25.19 +   Condition of use and distribution are the same than zlib :
   25.20 +
   25.21 +  This software is provided 'as-is', without any express or implied
   25.22 +  warranty.  In no event will the authors be held liable for any damages
   25.23 +  arising from the use of this software.
   25.24 +
   25.25 +  Permission is granted to anyone to use this software for any purpose,
   25.26 +  including commercial applications, and to alter it and redistribute it
   25.27 +  freely, subject to the following restrictions:
   25.28 +
   25.29 +  1. The origin of this software must not be misrepresented; you must not
   25.30 +     claim that you wrote the original software. If you use this software
   25.31 +     in a product, an acknowledgment in the product documentation would be
   25.32 +     appreciated but is not required.
   25.33 +  2. Altered source versions must be plainly marked as such, and must not be
   25.34 +     misrepresented as being the original software.
   25.35 +  3. This notice may not be removed or altered from any source distribution.
   25.36 +
   25.37 +
   25.38 +*/
   25.39 +/* for more info about .ZIP format, see 
   25.40 +      ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
   25.41 +   PkWare has also a specification at :
   25.42 +      ftp://ftp.pkware.com/probdesc.zip */
   25.43 +
   25.44 +#ifndef _unz_H
   25.45 +#define _unz_H
   25.46 +
   25.47 +#ifdef __cplusplus
   25.48 +extern "C" {
   25.49 +#endif
   25.50 +
   25.51 +#ifndef _ZLIB_H
   25.52 +#include "zlib.h"
   25.53 +#endif
   25.54 +
   25.55 +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
   25.56 +/* like the STRICT of WIN32, we define a pointer that cannot be converted
   25.57 +    from (void*) without cast */
   25.58 +typedef struct TagunzFile__ { int unused; } unzFile__; 
   25.59 +typedef unzFile__ *unzFile;
   25.60 +#else
   25.61 +typedef voidp unzFile;
   25.62 +#endif
   25.63 +
   25.64 +
   25.65 +#define UNZ_OK                                  (0)
   25.66 +#define UNZ_END_OF_LIST_OF_FILE (-100)
   25.67 +#define UNZ_ERRNO               (Z_ERRNO)
   25.68 +#define UNZ_EOF                 (0)
   25.69 +#define UNZ_PARAMERROR                  (-102)
   25.70 +#define UNZ_BADZIPFILE                  (-103)
   25.71 +#define UNZ_INTERNALERROR               (-104)
   25.72 +#define UNZ_CRCERROR                    (-105)
   25.73 +
   25.74 +/* tm_unz contain date/time info */
   25.75 +typedef struct tm_unz_s 
   25.76 +{
   25.77 +        uInt tm_sec;            /* seconds after the minute - [0,59] */
   25.78 +        uInt tm_min;            /* minutes after the hour - [0,59] */
   25.79 +        uInt tm_hour;           /* hours since midnight - [0,23] */
   25.80 +        uInt tm_mday;           /* day of the month - [1,31] */
   25.81 +        uInt tm_mon;            /* months since January - [0,11] */
   25.82 +        uInt tm_year;           /* years - [1980..2044] */
   25.83 +} tm_unz;
   25.84 +
   25.85 +/* unz_global_info structure contain global data about the ZIPfile
   25.86 +   These data comes from the end of central dir */
   25.87 +typedef struct unz_global_info_s
   25.88 +{
   25.89 +        uLong number_entry;         /* total number of entries in
   25.90 +                                       the central dir on this disk */
   25.91 +        uLong size_comment;         /* size of the global comment of the zipfile */
   25.92 +} unz_global_info;
   25.93 +
   25.94 +
   25.95 +/* unz_file_info contain information about a file in the zipfile */
   25.96 +typedef struct unz_file_info_s
   25.97 +{
   25.98 +    uLong version;              /* version made by                 2 bytes */
   25.99 +    uLong version_needed;       /* version needed to extract       2 bytes */
  25.100 +    uLong flag;                 /* general purpose bit flag        2 bytes */
  25.101 +    uLong compression_method;   /* compression method              2 bytes */
  25.102 +    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
  25.103 +    uLong crc;                  /* crc-32                          4 bytes */
  25.104 +    uLong compressed_size;      /* compressed size                 4 bytes */ 
  25.105 +    uLong uncompressed_size;    /* uncompressed size               4 bytes */ 
  25.106 +    uLong size_filename;        /* filename length                 2 bytes */
  25.107 +    uLong size_file_extra;      /* extra field length              2 bytes */
  25.108 +    uLong size_file_comment;    /* file comment length             2 bytes */
  25.109 +
  25.110 +    uLong disk_num_start;       /* disk number start               2 bytes */
  25.111 +    uLong internal_fa;          /* internal file attributes        2 bytes */
  25.112 +    uLong external_fa;          /* external file attributes        4 bytes */
  25.113 +
  25.114 +    tm_unz tmu_date;
  25.115 +} unz_file_info;
  25.116 +
  25.117 +extern int ZEXPORT  unzStringFileNameCompare OF ((const char* fileName1,
  25.118 +                                                 const char* fileName2,
  25.119 +                                                 int iCaseSensitivity));
  25.120 +/*
  25.121 +   Compare two filename (fileName1,fileName2).
  25.122 +   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
  25.123 +   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
  25.124 +                                                                or strcasecmp)
  25.125 +   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
  25.126 +        (like 1 on Unix, 2 on Windows)
  25.127 +*/
  25.128 +
  25.129 +
  25.130 +extern unzFile ZEXPORT  unzOpen OF((const char *path));
  25.131 +/*
  25.132 +  Open a Zip file. path contain the full pathname (by example,
  25.133 +     on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
  25.134 +         "zlib/zlib111.zip".
  25.135 +         If the zipfile cannot be opened (file don't exist or in not valid), the
  25.136 +           return value is NULL.
  25.137 +     Else, the return value is a unzFile Handle, usable with other function
  25.138 +           of this unzip package.
  25.139 +*/
  25.140 +
  25.141 +extern int ZEXPORT  unzClose OF((unzFile file));
  25.142 +/*
  25.143 +  Close a ZipFile opened with unzipOpen.
  25.144 +  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
  25.145 +    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
  25.146 +  return UNZ_OK if there is no problem. */
  25.147 +
  25.148 +extern int ZEXPORT  unzGetGlobalInfo OF((unzFile file,
  25.149 +                                        unz_global_info *pglobal_info));
  25.150 +/*
  25.151 +  Write info about the ZipFile in the *pglobal_info structure.
  25.152 +  No preparation of the structure is needed
  25.153 +  return UNZ_OK if there is no problem. */
  25.154 +
  25.155 +
  25.156 +extern int ZEXPORT  unzGetGlobalComment OF((unzFile file,
  25.157 +                                           char *szComment,
  25.158 +                                           uLong uSizeBuf));
  25.159 +/*
  25.160 +  Get the global comment string of the ZipFile, in the szComment buffer.
  25.161 +  uSizeBuf is the size of the szComment buffer.
  25.162 +  return the number of byte copied or an error code <0
  25.163 +*/
  25.164 +
  25.165 +
  25.166 +/***************************************************************************/
  25.167 +/* Unzip package allow you browse the directory of the zipfile */
  25.168 +
  25.169 +extern int ZEXPORT  unzGoToFirstFile OF((unzFile file));
  25.170 +/*
  25.171 +  Set the current file of the zipfile to the first file.
  25.172 +  return UNZ_OK if there is no problem
  25.173 +*/
  25.174 +
  25.175 +extern int ZEXPORT  unzGoToNextFile OF((unzFile file));
  25.176 +/*
  25.177 +  Set the current file of the zipfile to the next file.
  25.178 +  return UNZ_OK if there is no problem
  25.179 +  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
  25.180 +*/
  25.181 +
  25.182 +extern int ZEXPORT  unzLocateFile OF((unzFile file, 
  25.183 +                                     const char *szFileName,
  25.184 +                                     int iCaseSensitivity));
  25.185 +/*
  25.186 +  Try locate the file szFileName in the zipfile.
  25.187 +  For the iCaseSensitivity signification, see unzStringFileNameCompare
  25.188 +
  25.189 +  return value :
  25.190 +  UNZ_OK if the file is found. It becomes the current file.
  25.191 +  UNZ_END_OF_LIST_OF_FILE if the file is not found
  25.192 +*/
  25.193 +
  25.194 +
  25.195 +extern int ZEXPORT  unzGetCurrentFileInfo OF((unzFile file,
  25.196 +                                             unz_file_info *pfile_info,
  25.197 +                                             char *szFileName,
  25.198 +                                             uLong fileNameBufferSize,
  25.199 +                                             void *extraField,
  25.200 +                                             uLong extraFieldBufferSize,
  25.201 +                                             char *szComment,
  25.202 +                                             uLong commentBufferSize));
  25.203 +/*
  25.204 +  Get Info about the current file
  25.205 +  if pfile_info!=NULL, the *pfile_info structure will contain somes info about
  25.206 +            the current file
  25.207 +  if szFileName!=NULL, the filemane string will be copied in szFileName
  25.208 +                        (fileNameBufferSize is the size of the buffer)
  25.209 +  if extraField!=NULL, the extra field information will be copied in extraField
  25.210 +                        (extraFieldBufferSize is the size of the buffer).
  25.211 +                        This is the Central-header version of the extra field
  25.212 +  if szComment!=NULL, the comment string of the file will be copied in szComment
  25.213 +                        (commentBufferSize is the size of the buffer)
  25.214 +*/
  25.215 +
  25.216 +/***************************************************************************/
  25.217 +/* for reading the content of the current zipfile, you can open it, read data
  25.218 +   from it, and close it (you can close it before reading all the file)
  25.219 +   */
  25.220 +
  25.221 +extern int ZEXPORT  unzOpenCurrentFile OF((unzFile file));
  25.222 +/*
  25.223 +  Open for reading data the current file in the zipfile.
  25.224 +  If there is no error, the return value is UNZ_OK.
  25.225 +*/
  25.226 +
  25.227 +extern int ZEXPORT  unzCloseCurrentFile OF((unzFile file));
  25.228 +/*
  25.229 +  Close the file in zip opened with unzOpenCurrentFile
  25.230 +  Return UNZ_CRCERROR if all the file was read but the CRC is not good
  25.231 +*/
  25.232 +
  25.233 +                                                                                                
  25.234 +extern int ZEXPORT  unzReadCurrentFile OF((unzFile file, 
  25.235 +                                          voidp buf,
  25.236 +                                          unsigned len));
  25.237 +/*
  25.238 +  Read bytes from the current file (opened by unzOpenCurrentFile)
  25.239 +  buf contain buffer where data must be copied
  25.240 +  len the size of buf.
  25.241 +
  25.242 +  return the number of byte copied if somes bytes are copied
  25.243 +  return 0 if the end of file was reached
  25.244 +  return <0 with error code if there is an error
  25.245 +    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
  25.246 +*/
  25.247 +
  25.248 +extern z_off_t ZEXPORT  unztell OF((unzFile file));
  25.249 +/*
  25.250 +  Give the current position in uncompressed data
  25.251 +*/
  25.252 +
  25.253 +extern int ZEXPORT  unzeof OF((unzFile file));
  25.254 +/*
  25.255 +  return 1 if the end of file was reached, 0 elsewhere 
  25.256 +*/
  25.257 +
  25.258 +extern int ZEXPORT  unzGetLocalExtrafield OF((unzFile file,
  25.259 +                                             voidp buf,
  25.260 +                                             unsigned len));
  25.261 +/*
  25.262 +  Read extra field from the current file (opened by unzOpenCurrentFile)
  25.263 +  This is the local-header version of the extra field (sometimes, there is
  25.264 +    more info in the local-header version than in the central-header)
  25.265 +
  25.266 +  if buf==NULL, it return the size of the local extra field
  25.267 +
  25.268 +  if buf!=NULL, len is the size of the buffer, the extra header is copied in
  25.269 +        buf.
  25.270 +  the return value is the number of bytes copied in buf, or (if <0) 
  25.271 +        the error code
  25.272 +*/
  25.273 +
  25.274 +#ifdef __cplusplus
  25.275 +}
  25.276 +#endif
  25.277 +
  25.278 +#endif /* _unz_H */
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/common/vbalua.h	Sun Mar 04 14:33:52 2012 -0600
    26.3 @@ -0,0 +1,52 @@
    26.4 +#ifndef VBA_LUA_H
    26.5 +#define VBA_LUA_H
    26.6 +
    26.7 +#if _MSC_VER > 1000
    26.8 +#pragma once
    26.9 +#endif // _MSC_VER > 1000
   26.10 +
   26.11 +enum LuaCallID
   26.12 +{
   26.13 +	LUACALL_BEFOREEMULATION,
   26.14 +	LUACALL_AFTEREMULATION,
   26.15 +	LUACALL_BEFOREEXIT,
   26.16 +
   26.17 +	LUACALL_COUNT
   26.18 +};
   26.19 +void CallRegisteredLuaFunctions(LuaCallID calltype);
   26.20 +
   26.21 +enum LuaMemHookType
   26.22 +{
   26.23 +	LUAMEMHOOK_WRITE,
   26.24 +	LUAMEMHOOK_READ,
   26.25 +	LUAMEMHOOK_EXEC,
   26.26 +	LUAMEMHOOK_WRITE_SUB,
   26.27 +	LUAMEMHOOK_READ_SUB,
   26.28 +	LUAMEMHOOK_EXEC_SUB,
   26.29 +
   26.30 +	LUAMEMHOOK_COUNT
   26.31 +};
   26.32 +void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType);
   26.33 +
   26.34 +// Just forward function declarations
   26.35 +
   26.36 +void VBALuaFrameBoundary();
   26.37 +int VBALoadLuaCode(const char *filename);
   26.38 +int VBAReloadLuaCode();
   26.39 +void VBALuaStop();
   26.40 +int VBALuaRunning();
   26.41 +
   26.42 +int VBALuaUsingJoypad(int);
   26.43 +int VBALuaReadJoypad(int);
   26.44 +int VBALuaSpeed();
   26.45 +bool8 VBALuaRerecordCountSkip();
   26.46 +
   26.47 +void VBALuaGui(uint8 *screen, int ppl, int width, int height);
   26.48 +void VBALuaClearGui();
   26.49 +
   26.50 +char* VBAGetLuaScriptName();
   26.51 +
   26.52 +// And some interesting REVERSE declarations!
   26.53 +char *VBAGetFreezeFilename(int slot);
   26.54 +
   26.55 +#endif // VBA_LUA_H
    27.1 --- a/src/gb/gbCheats.cpp	Sat Mar 03 12:06:10 2012 -0600
    27.2 +++ b/src/gb/gbCheats.cpp	Sun Mar 04 14:33:52 2012 -0600
    27.3 @@ -21,457 +21,457 @@
    27.4  
    27.5  void gbCheatUpdateMap()
    27.6  {
    27.7 -	memset(gbCheatMap, 0, 0x10000);
    27.8 +  memset(gbCheatMap, 0, 0x10000);
    27.9  
   27.10 -	for (int i = 0; i < gbCheatNumber; i++)
   27.11 -	{
   27.12 -		if (gbCheatList[i].enabled)
   27.13 -			gbCheatMap[gbCheatList[i].address] = true;
   27.14 -	}
   27.15 +  for (int i = 0; i < gbCheatNumber; i++)
   27.16 +    {
   27.17 +      if (gbCheatList[i].enabled)
   27.18 +	gbCheatMap[gbCheatList[i].address] = true;
   27.19 +    }
   27.20  }
   27.21  
   27.22  void gbCheatsSaveGame(gzFile gzFile)
   27.23  {
   27.24 -	utilWriteInt(gzFile, gbCheatNumber);
   27.25 -	if (gbCheatNumber)
   27.26 -		utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
   27.27 +  utilWriteInt(gzFile, gbCheatNumber);
   27.28 +  if (gbCheatNumber)
   27.29 +    utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
   27.30  }
   27.31  
   27.32  void gbCheatsReadGame(gzFile gzFile, int version)
   27.33  {
   27.34 -	if (version <= 8)
   27.35 +  if (version <= 8)
   27.36 +    {
   27.37 +      int gbGgOn = utilReadInt(gzFile);
   27.38 +
   27.39 +      if (gbGgOn)
   27.40  	{
   27.41 -		int gbGgOn = utilReadInt(gzFile);
   27.42 -
   27.43 -		if (gbGgOn)
   27.44 -		{
   27.45 -			int       n = utilReadInt(gzFile);
   27.46 -			gbXxCheat tmpCheat;
   27.47 -			for (int i = 0; i < n; i++)
   27.48 -			{
   27.49 -				utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));
   27.50 -				gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
   27.51 -			}
   27.52 -		}
   27.53 -
   27.54 -		int gbGsOn = utilReadInt(gzFile);
   27.55 -
   27.56 -		if (gbGsOn)
   27.57 -		{
   27.58 -			int       n = utilReadInt(gzFile);
   27.59 -			gbXxCheat tmpCheat;
   27.60 -			for (int i = 0; i < n; i++)
   27.61 -			{
   27.62 -				utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));
   27.63 -				gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
   27.64 -			}
   27.65 -		}
   27.66 -	}
   27.67 -	else
   27.68 -	{
   27.69 -		gbCheatNumber = utilReadInt(gzFile);
   27.70 -
   27.71 -		if (gbCheatNumber)
   27.72 -		{
   27.73 -			utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
   27.74 -		}
   27.75 +	  int       n = utilReadInt(gzFile);
   27.76 +	  gbXxCheat tmpCheat;
   27.77 +	  for (int i = 0; i < n; i++)
   27.78 +	    {
   27.79 +	      utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));
   27.80 +	      gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
   27.81 +	    }
   27.82  	}
   27.83  
   27.84 -	gbCheatUpdateMap();
   27.85 +      int gbGsOn = utilReadInt(gzFile);
   27.86 +
   27.87 +      if (gbGsOn)
   27.88 +	{
   27.89 +	  int       n = utilReadInt(gzFile);
   27.90 +	  gbXxCheat tmpCheat;
   27.91 +	  for (int i = 0; i < n; i++)
   27.92 +	    {
   27.93 +	      utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));
   27.94 +	      gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
   27.95 +	    }
   27.96 +	}
   27.97 +    }
   27.98 +  else
   27.99 +    {
  27.100 +      gbCheatNumber = utilReadInt(gzFile);
  27.101 +
  27.102 +      if (gbCheatNumber)
  27.103 +	{
  27.104 +	  utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
  27.105 +	}
  27.106 +    }
  27.107 +
  27.108 +  gbCheatUpdateMap();
  27.109  }
  27.110  
  27.111  void gbCheatsSaveCheatList(const char *file)
  27.112  {
  27.113 -	if (gbCheatNumber == 0)
  27.114 -		return;
  27.115 -	FILE *f = fopen(file, "wb");
  27.116 -	if (f == NULL)
  27.117 -		return;
  27.118 -	int version = 1;
  27.119 -	fwrite(&version, 1, sizeof(version), f);
  27.120 -	int type = 1;
  27.121 -	fwrite(&type, 1, sizeof(type), f);
  27.122 -	fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f);
  27.123 -	fwrite(gbCheatList, 1, sizeof(gbCheatList), f);
  27.124 -	fclose(f);
  27.125 +  if (gbCheatNumber == 0)
  27.126 +    return;
  27.127 +  FILE *f = fopen(file, "wb");
  27.128 +  if (f == NULL)
  27.129 +    return;
  27.130 +  int version = 1;
  27.131 +  fwrite(&version, 1, sizeof(version), f);
  27.132 +  int type = 1;
  27.133 +  fwrite(&type, 1, sizeof(type), f);
  27.134 +  fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f);
  27.135 +  fwrite(gbCheatList, 1, sizeof(gbCheatList), f);
  27.136 +  fclose(f);
  27.137  }
  27.138  
  27.139  bool gbCheatsLoadCheatList(const char *file)
  27.140  {
  27.141 -	gbCheatNumber = 0;
  27.142 +  gbCheatNumber = 0;
  27.143  
  27.144 -	gbCheatUpdateMap();
  27.145 +  gbCheatUpdateMap();
  27.146  
  27.147 -	int count = 0;
  27.148 +  int count = 0;
  27.149  
  27.150 -	FILE *f = fopen(file, "rb");
  27.151 +  FILE *f = fopen(file, "rb");
  27.152  
  27.153 -	if (f == NULL)
  27.154 -		return false;
  27.155 +  if (f == NULL)
  27.156 +    return false;
  27.157  
  27.158 -	int version = 0;
  27.159 +  int version = 0;
  27.160  
  27.161 -	if (fread(&version, 1, sizeof(version), f) != sizeof(version))
  27.162 -	{
  27.163 -		fclose(f);
  27.164 -		return false;
  27.165 -	}
  27.166 +  if (fread(&version, 1, sizeof(version), f) != sizeof(version))
  27.167 +    {
  27.168 +      fclose(f);
  27.169 +      return false;
  27.170 +    }
  27.171  
  27.172 -	if (version != 1)
  27.173 -	{
  27.174 -		systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,
  27.175 -		              N_("Unsupported cheat list version %d"), version);
  27.176 -		fclose(f);
  27.177 -		return false;
  27.178 -	}
  27.179 +  if (version != 1)
  27.180 +    {
  27.181 +      systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,
  27.182 +		    N_("Unsupported cheat list version %d"), version);
  27.183 +      fclose(f);
  27.184 +      return false;
  27.185 +    }
  27.186  
  27.187 -	int type = 0;
  27.188 -	if (fread(&type, 1, sizeof(type), f) != sizeof(type))
  27.189 -	{
  27.190 -		fclose(f);
  27.191 -		return false;
  27.192 -	}
  27.193 +  int type = 0;
  27.194 +  if (fread(&type, 1, sizeof(type), f) != sizeof(type))
  27.195 +    {
  27.196 +      fclose(f);
  27.197 +      return false;
  27.198 +    }
  27.199  
  27.200 -	if (type != 1)
  27.201 -	{
  27.202 -		systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,
  27.203 -		              N_("Unsupported cheat list type %d"), type);
  27.204 -		fclose(f);
  27.205 -		return false;
  27.206 -	}
  27.207 +  if (type != 1)
  27.208 +    {
  27.209 +      systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,
  27.210 +		    N_("Unsupported cheat list type %d"), type);
  27.211 +      fclose(f);
  27.212 +      return false;
  27.213 +    }
  27.214  
  27.215 -	if (fread(&count, 1, sizeof(count), f) != sizeof(count))
  27.216 -	{
  27.217 -		fclose(f);
  27.218 -		return false;
  27.219 -	}
  27.220 +  if (fread(&count, 1, sizeof(count), f) != sizeof(count))
  27.221 +    {
  27.222 +      fclose(f);
  27.223 +      return false;
  27.224 +    }
  27.225  
  27.226 -	if (fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList))
  27.227 -	{
  27.228 -		fclose(f);
  27.229 -		return false;
  27.230 -	}
  27.231 +  if (fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList))
  27.232 +    {
  27.233 +      fclose(f);
  27.234 +      return false;
  27.235 +    }
  27.236  
  27.237 -	fclose(f);
  27.238 -	gbCheatNumber = count;
  27.239 -	gbCheatUpdateMap();
  27.240 +  fclose(f);
  27.241 +  gbCheatNumber = count;
  27.242 +  gbCheatUpdateMap();
  27.243  
  27.244 -	return true;
  27.245 +  return true;
  27.246  }
  27.247  
  27.248  bool gbVerifyGsCode(const char *code)
  27.249  {
  27.250 -	int len = strlen(code);
  27.251 +  int len = strlen(code);
  27.252  
  27.253 -	if (len == 0)
  27.254 -		return true;
  27.255 +  if (len == 0)
  27.256 +    return true;
  27.257  
  27.258 -	if (len != 8)
  27.259 -		return false;
  27.260 +  if (len != 8)
  27.261 +    return false;
  27.262  
  27.263 -	for (int i = 0; i < 8; i++)
  27.264 -		if (!GBCHEAT_IS_HEX(code[i]))
  27.265 -			return false;
  27.266 +  for (int i = 0; i < 8; i++)
  27.267 +    if (!GBCHEAT_IS_HEX(code[i]))
  27.268 +      return false;
  27.269  
  27.270 -	int address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
  27.271 -	              GBCHEAT_HEX_VALUE(code[7]) << 8 |
  27.272 -	              GBCHEAT_HEX_VALUE(code[4]) << 4 |
  27.273 -	              GBCHEAT_HEX_VALUE(code[5]);
  27.274 +  int address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
  27.275 +    GBCHEAT_HEX_VALUE(code[7]) << 8 |
  27.276 +    GBCHEAT_HEX_VALUE(code[4]) << 4 |
  27.277 +    GBCHEAT_HEX_VALUE(code[5]);
  27.278  
  27.279 -	if (address < 0xa000 ||
  27.280 -	    address > 0xdfff)
  27.281 -		return false;
  27.282 +  if (address < 0xa000 ||
  27.283 +      address > 0xdfff)
  27.284 +    return false;
  27.285  
  27.286 -	return true;
  27.287 +  return true;
  27.288  }
  27.289  
  27.290  void gbAddGsCheat(const char *code, const char *desc)
  27.291  {
  27.292 -	if (gbCheatNumber > 99)
  27.293 -	{
  27.294 -		systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
  27.295 -		              N_("Maximum number of cheats reached."));
  27.296 -		return;
  27.297 -	}
  27.298 +  if (gbCheatNumber > 99)
  27.299 +    {
  27.300 +      systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
  27.301 +		    N_("Maximum number of cheats reached."));
  27.302 +      return;
  27.303 +    }
  27.304  
  27.305 -	if (!gbVerifyGsCode(code))
  27.306 -	{
  27.307 -		systemMessage(MSG_INVALID_GAMESHARK_CODE,
  27.308 -		              N_("Invalid GameShark code: %s"), code);
  27.309 -		return;
  27.310 -	}
  27.311 +  if (!gbVerifyGsCode(code))
  27.312 +    {
  27.313 +      systemMessage(MSG_INVALID_GAMESHARK_CODE,
  27.314 +		    N_("Invalid GameShark code: %s"), code);
  27.315 +      return;
  27.316 +    }
  27.317  
  27.318 -	int i = gbCheatNumber;
  27.319 +  int i = gbCheatNumber;
  27.320  
  27.321 -	strcpy(gbCheatList[i].cheatCode, code);
  27.322 -	strcpy(gbCheatList[i].cheatDesc, desc);
  27.323 +  strcpy(gbCheatList[i].cheatCode, code);
  27.324 +  strcpy(gbCheatList[i].cheatDesc, desc);
  27.325  
  27.326 -	gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 |
  27.327 -	                      GBCHEAT_HEX_VALUE(code[1]);
  27.328 +  gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 |
  27.329 +    GBCHEAT_HEX_VALUE(code[1]);
  27.330  
  27.331 -	gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 |
  27.332 -	                       GBCHEAT_HEX_VALUE(code[3]);
  27.333 +  gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 |
  27.334 +    GBCHEAT_HEX_VALUE(code[3]);
  27.335  
  27.336 -	gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
  27.337 -	                         GBCHEAT_HEX_VALUE(code[7]) << 8 |
  27.338 -	                         GBCHEAT_HEX_VALUE(code[4]) << 4 |
  27.339 -	                         GBCHEAT_HEX_VALUE(code[5]);
  27.340 +  gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
  27.341 +    GBCHEAT_HEX_VALUE(code[7]) << 8 |
  27.342 +    GBCHEAT_HEX_VALUE(code[4]) << 4 |
  27.343 +    GBCHEAT_HEX_VALUE(code[5]);
  27.344  
  27.345 -	gbCheatList[i].compare = 0;
  27.346 +  gbCheatList[i].compare = 0;
  27.347  
  27.348 -	gbCheatList[i].enabled = true;
  27.349 +  gbCheatList[i].enabled = true;
  27.350  
  27.351 -	gbCheatMap[gbCheatList[i].address] = true;
  27.352 +  gbCheatMap[gbCheatList[i].address] = true;
  27.353  
  27.354 -	gbCheatNumber++;
  27.355 +  gbCheatNumber++;
  27.356  }
  27.357  
  27.358  bool gbVerifyGgCode(const char *code)
  27.359  {
  27.360 -	int len = strlen(code);
  27.361 +  int len = strlen(code);
  27.362  
  27.363 -	if (len != 11 &&
  27.364 -	    len != 7 &&
  27.365 -	    len != 6 &&
  27.366 -	    len != 0)
  27.367 -		return false;
  27.368 +  if (len != 11 &&
  27.369 +      len != 7 &&
  27.370 +      len != 6 &&
  27.371 +      len != 0)
  27.372 +    return false;
  27.373  
  27.374 -	if (len == 0)
  27.375 -		return true;
  27.376 +  if (len == 0)
  27.377 +    return true;
  27.378  
  27.379 -	if (!GBCHEAT_IS_HEX(code[0]))
  27.380 -		return false;
  27.381 -	if (!GBCHEAT_IS_HEX(code[1]))
  27.382 -		return false;
  27.383 -	if (!GBCHEAT_IS_HEX(code[2]))
  27.384 -		return false;
  27.385 -	if (code[3] != '-')
  27.386 -		return false;
  27.387 -	if (!GBCHEAT_IS_HEX(code[4]))
  27.388 -		return false;
  27.389 -	if (!GBCHEAT_IS_HEX(code[5]))
  27.390 -		return false;
  27.391 -	if (!GBCHEAT_IS_HEX(code[6]))
  27.392 -		return false;
  27.393 -	if (code[7] != 0)
  27.394 +  if (!GBCHEAT_IS_HEX(code[0]))
  27.395 +    return false;
  27.396 +  if (!GBCHEAT_IS_HEX(code[1]))
  27.397 +    return false;
  27.398 +  if (!GBCHEAT_IS_HEX(code[2]))
  27.399 +    return false;
  27.400 +  if (code[3] != '-')
  27.401 +    return false;
  27.402 +  if (!GBCHEAT_IS_HEX(code[4]))
  27.403 +    return false;
  27.404 +  if (!GBCHEAT_IS_HEX(code[5]))
  27.405 +    return false;
  27.406 +  if (!GBCHEAT_IS_HEX(code[6]))
  27.407 +    return false;
  27.408 +  if (code[7] != 0)
  27.409 +    {
  27.410 +      if (code[7] != '-')
  27.411 +	return false;
  27.412 +      if (code[8] != 0)
  27.413  	{
  27.414 -		if (code[7] != '-')
  27.415 -			return false;
  27.416 -		if (code[8] != 0)
  27.417 -		{
  27.418 -			if (!GBCHEAT_IS_HEX(code[8]))
  27.419 -				return false;
  27.420 -			if (!GBCHEAT_IS_HEX(code[9]))
  27.421 -				return false;
  27.422 -			if (!GBCHEAT_IS_HEX(code[10]))
  27.423 -				return false;
  27.424 -		}
  27.425 +	  if (!GBCHEAT_IS_HEX(code[8]))
  27.426 +	    return false;
  27.427 +	  if (!GBCHEAT_IS_HEX(code[9]))
  27.428 +	    return false;
  27.429 +	  if (!GBCHEAT_IS_HEX(code[10]))
  27.430 +	    return false;
  27.431  	}
  27.432 +    }
  27.433  
  27.434 -	//  int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
  27.435 -	//    GBCHEAT_HEX_VALUE(code[1]);
  27.436 +  //  int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
  27.437 +  //    GBCHEAT_HEX_VALUE(code[1]);
  27.438  
  27.439 -	int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
  27.440 -	              (GBCHEAT_HEX_VALUE(code[4]) << 4) +
  27.441 -	              (GBCHEAT_HEX_VALUE(code[5])) +
  27.442 -	              ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
  27.443 +  int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
  27.444 +    (GBCHEAT_HEX_VALUE(code[4]) << 4) +
  27.445 +    (GBCHEAT_HEX_VALUE(code[5])) +
  27.446 +    ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
  27.447  
  27.448 -	if (address >= 0x8000 && address <= 0x9fff)
  27.449 -		return false;
  27.450 +  if (address >= 0x8000 && address <= 0x9fff)
  27.451 +    return false;
  27.452  
  27.453 -	if (address >= 0xc000)
  27.454 -		return false;
  27.455 +  if (address >= 0xc000)
  27.456 +    return false;
  27.457  
  27.458 -	if (code[7] == 0 || code[8] == '0')
  27.459 -		return true;
  27.460 +  if (code[7] == 0 || code[8] == '0')
  27.461 +    return true;
  27.462  
  27.463 -	int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
  27.464 -	              (GBCHEAT_HEX_VALUE(code[10]));
  27.465 -	compare  = compare ^ 0xff;
  27.466 -	compare  = (compare >> 2) | ((compare << 6) & 0xc0);
  27.467 -	compare ^= 0x45;
  27.468 +  int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
  27.469 +    (GBCHEAT_HEX_VALUE(code[10]));
  27.470 +  compare  = compare ^ 0xff;
  27.471 +  compare  = (compare >> 2) | ((compare << 6) & 0xc0);
  27.472 +  compare ^= 0x45;
  27.473  
  27.474 -	int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9]));
  27.475 +  int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9]));
  27.476  
  27.477 -	if (cloak >= 1 && cloak <= 7)
  27.478 -		return false;
  27.479 +  if (cloak >= 1 && cloak <= 7)
  27.480 +    return false;
  27.481  
  27.482 -	return true;
  27.483 +  return true;
  27.484  }
  27.485  
  27.486  void gbAddGgCheat(const char *code, const char *desc)
  27.487  {
  27.488 -	if (gbCheatNumber > 99)
  27.489 -	{
  27.490 -		systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
  27.491 -		              N_("Maximum number of cheats reached."));
  27.492 -		return;
  27.493 -	}
  27.494 +  if (gbCheatNumber > 99)
  27.495 +    {
  27.496 +      systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
  27.497 +		    N_("Maximum number of cheats reached."));
  27.498 +      return;
  27.499 +    }
  27.500  
  27.501 -	if (!gbVerifyGgCode(code))
  27.502 -	{
  27.503 -		systemMessage(MSG_INVALID_GAMEGENIE_CODE,
  27.504 -		              N_("Invalid GameGenie code: %s"), code);
  27.505 -		return;
  27.506 -	}
  27.507 +  if (!gbVerifyGgCode(code))
  27.508 +    {
  27.509 +      systemMessage(MSG_INVALID_GAMEGENIE_CODE,
  27.510 +		    N_("Invalid GameGenie code: %s"), code);
  27.511 +      return;
  27.512 +    }
  27.513  
  27.514 -	int i = gbCheatNumber;
  27.515 +  int i = gbCheatNumber;
  27.516  
  27.517 -	int len = strlen(code);
  27.518 +  int len = strlen(code);
  27.519  
  27.520 -	strcpy(gbCheatList[i].cheatCode, code);
  27.521 -	strcpy(gbCheatList[i].cheatDesc, desc);
  27.522 +  strcpy(gbCheatList[i].cheatCode, code);
  27.523 +  strcpy(gbCheatList[i].cheatDesc, desc);
  27.524  
  27.525 -	gbCheatList[i].code  = 1;
  27.526 -	gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
  27.527 -	                       GBCHEAT_HEX_VALUE(code[1]);
  27.528 +  gbCheatList[i].code  = 1;
  27.529 +  gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
  27.530 +    GBCHEAT_HEX_VALUE(code[1]);
  27.531  
  27.532 -	gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
  27.533 -	                         (GBCHEAT_HEX_VALUE(code[4]) << 4) +
  27.534 -	                         (GBCHEAT_HEX_VALUE(code[5])) +
  27.535 -	                         ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
  27.536 +  gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
  27.537 +    (GBCHEAT_HEX_VALUE(code[4]) << 4) +
  27.538 +    (GBCHEAT_HEX_VALUE(code[5])) +
  27.539 +    ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
  27.540  
  27.541 -	gbCheatList[i].compare = 0;
  27.542 +  gbCheatList[i].compare = 0;
  27.543  
  27.544 -	if (len != 7 && len != 8)
  27.545 -	{
  27.546 -		int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
  27.547 -		              (GBCHEAT_HEX_VALUE(code[10]));
  27.548 -		compare  = compare ^ 0xff;
  27.549 -		compare  = (compare >> 2) | ((compare << 6) & 0xc0);
  27.550 -		compare ^= 0x45;
  27.551 +  if (len != 7 && len != 8)
  27.552 +    {
  27.553 +      int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
  27.554 +	(GBCHEAT_HEX_VALUE(code[10]));
  27.555 +      compare  = compare ^ 0xff;
  27.556 +      compare  = (compare >> 2) | ((compare << 6) & 0xc0);
  27.557 +      compare ^= 0x45;
  27.558  
  27.559 -		gbCheatList[i].compare = compare;
  27.560 -		gbCheatList[i].code    = 0;
  27.561 -	}
  27.562 +      gbCheatList[i].compare = compare;
  27.563 +      gbCheatList[i].code    = 0;
  27.564 +    }
  27.565  
  27.566 -	gbCheatList[i].enabled = true;
  27.567 +  gbCheatList[i].enabled = true;
  27.568  
  27.569 -	gbCheatMap[gbCheatList[i].address] = true;
  27.570 +  gbCheatMap[gbCheatList[i].address] = true;
  27.571  
  27.572 -	gbCheatNumber++;
  27.573 +  gbCheatNumber++;
  27.574  }
  27.575  
  27.576  void gbCheatRemove(int i)
  27.577  {
  27.578 -	if (i < 0 || i >= gbCheatNumber)
  27.579 -	{
  27.580 -		systemMessage(MSG_INVALID_CHEAT_TO_REMOVE,
  27.581 -		              N_("Invalid cheat to remove %d"), i);
  27.582 -		return;
  27.583 -	}
  27.584 +  if (i < 0 || i >= gbCheatNumber)
  27.585 +    {
  27.586 +      systemMessage(MSG_INVALID_CHEAT_TO_REMOVE,
  27.587 +		    N_("Invalid cheat to remove %d"), i);
  27.588 +      return;
  27.589 +    }
  27.590  
  27.591 -	if ((i+1) <  gbCheatNumber)
  27.592 -	{
  27.593 -		memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)*
  27.594 -		       (gbCheatNumber-i-1));
  27.595 -	}
  27.596 +  if ((i+1) <  gbCheatNumber)
  27.597 +    {
  27.598 +      memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)*
  27.599 +	     (gbCheatNumber-i-1));
  27.600 +    }
  27.601  
  27.602 -	gbCheatNumber--;
  27.603 +  gbCheatNumber--;
  27.604  
  27.605 -	gbCheatUpdateMap();
  27.606 +  gbCheatUpdateMap();
  27.607  }
  27.608  
  27.609  void gbCheatRemoveAll()
  27.610  {
  27.611 -	gbCheatNumber = 0;
  27.612 -	gbCheatUpdateMap();
  27.613 +  gbCheatNumber = 0;
  27.614 +  gbCheatUpdateMap();
  27.615  }
  27.616  
  27.617  void gbCheatEnable(int i)
  27.618  {
  27.619 -	if (i >= 0 && i < gbCheatNumber)
  27.620 +  if (i >= 0 && i < gbCheatNumber)
  27.621 +    {
  27.622 +      if (!gbCheatList[i].enabled)
  27.623  	{
  27.624 -		if (!gbCheatList[i].enabled)
  27.625 -		{
  27.626 -			gbCheatList[i].enabled = true;
  27.627 -			gbCheatUpdateMap();
  27.628 -		}
  27.629 +	  gbCheatList[i].enabled = true;
  27.630 +	  gbCheatUpdateMap();
  27.631  	}
  27.632 +    }
  27.633  }
  27.634  
  27.635  void gbCheatDisable(int i)
  27.636  {
  27.637 -	if (i >= 0 && i < gbCheatNumber)
  27.638 +  if (i >= 0 && i < gbCheatNumber)
  27.639 +    {
  27.640 +      if (gbCheatList[i].enabled)
  27.641  	{
  27.642 -		if (gbCheatList[i].enabled)
  27.643 -		{
  27.644 -			gbCheatList[i].enabled = false;
  27.645 -			gbCheatUpdateMap();
  27.646 -		}
  27.647 +	  gbCheatList[i].enabled = false;
  27.648 +	  gbCheatUpdateMap();
  27.649  	}
  27.650 +    }
  27.651  }
  27.652  
  27.653  bool gbCheatReadGSCodeFile(const char *fileName)
  27.654  {
  27.655 -	FILE *file = fopen(fileName, "rb");
  27.656 +  FILE *file = fopen(fileName, "rb");
  27.657  
  27.658 -	if (!file)
  27.659 -		return false;
  27.660 +  if (!file)
  27.661 +    return false;
  27.662  
  27.663 -	fseek(file, 0x18, SEEK_SET);
  27.664 -	int count = 0;
  27.665 -	fread(&count, 1, 2, file);
  27.666 -	int dummy = 0;
  27.667 -	gbCheatRemoveAll();
  27.668 -	char desc[13];
  27.669 -	char code[9];
  27.670 -	int  i;
  27.671 -	for (i = 0; i < count; i++)
  27.672 -	{
  27.673 -		fread(&dummy, 1, 2, file);
  27.674 -		fread(desc, 1, 12, file);
  27.675 -		desc[12] = 0;
  27.676 -		fread(code, 1, 8, file);
  27.677 -		code[8] = 0;
  27.678 -		gbAddGsCheat(code, desc);
  27.679 -	}
  27.680 +  fseek(file, 0x18, SEEK_SET);
  27.681 +  int count = 0;
  27.682 +  fread(&count, 1, 2, file);
  27.683 +  int dummy = 0;
  27.684 +  gbCheatRemoveAll();
  27.685 +  char desc[13];
  27.686 +  char code[9];
  27.687 +  int  i;
  27.688 +  for (i = 0; i < count; i++)
  27.689 +    {
  27.690 +      fread(&dummy, 1, 2, file);
  27.691 +      fread(desc, 1, 12, file);
  27.692 +      desc[12] = 0;
  27.693 +      fread(code, 1, 8, file);
  27.694 +      code[8] = 0;
  27.695 +      gbAddGsCheat(code, desc);
  27.696 +    }
  27.697  
  27.698 -	for (i = 0; i < gbCheatNumber; i++)
  27.699 -		gbCheatDisable(i);
  27.700 +  for (i = 0; i < gbCheatNumber; i++)
  27.701 +    gbCheatDisable(i);
  27.702  
  27.703 -	fclose(file);
  27.704 -	return true;
  27.705 +  fclose(file);
  27.706 +  return true;
  27.707  }
  27.708  
  27.709  u8 gbCheatRead(u16 address)
  27.710  {
  27.711 -	if (!cheatsEnabled)
  27.712 -		return gbReadMemoryQuick(address);
  27.713 +  if (!cheatsEnabled)
  27.714 +    return gbReadMemoryQuick(address);
  27.715  
  27.716 -	for (int i = 0; i < gbCheatNumber; i++)
  27.717 +  for (int i = 0; i < gbCheatNumber; i++)
  27.718 +    {
  27.719 +      if (gbCheatList[i].enabled && gbCheatList[i].address == address)
  27.720  	{
  27.721 -		if (gbCheatList[i].enabled && gbCheatList[i].address == address)
  27.722 +	  switch (gbCheatList[i].code)
  27.723 +	    {
  27.724 +	    case 0x100: // GameGenie support
  27.725 +	      if (gbReadMemoryQuick(address) == gbCheatList[i].compare)
  27.726 +		return gbCheatList[i].value;
  27.727 +	      break;
  27.728 +	    case 0x00:
  27.729 +	    case 0x01:
  27.730 +	    case 0x80:
  27.731 +	      return gbCheatList[i].value;
  27.732 +	    case 0x90:
  27.733 +	    case 0x91:
  27.734 +	    case 0x92:
  27.735 +	    case 0x93:
  27.736 +	    case 0x94:
  27.737 +	    case 0x95:
  27.738 +	    case 0x96:
  27.739 +	    case 0x97:
  27.740 +	      if (address >= 0xd000 && address < 0xe000)
  27.741  		{
  27.742 -			switch (gbCheatList[i].code)
  27.743 -			{
  27.744 -			case 0x100: // GameGenie support
  27.745 -				if (gbReadMemoryQuick(address) == gbCheatList[i].compare)
  27.746 -					return gbCheatList[i].value;
  27.747 -				break;
  27.748 -			case 0x00:
  27.749 -			case 0x01:
  27.750 -			case 0x80:
  27.751 -				return gbCheatList[i].value;
  27.752 -			case 0x90:
  27.753 -			case 0x91:
  27.754 -			case 0x92:
  27.755 -			case 0x93:
  27.756 -			case 0x94:
  27.757 -			case 0x95:
  27.758 -			case 0x96:
  27.759 -			case 0x97:
  27.760 -				if (address >= 0xd000 && address < 0xe000)
  27.761 -				{
  27.762 -					if (((gbMemoryMap[0x0d] - gbWram)/0x1000) ==
  27.763 -					    (gbCheatList[i].code - 0x90))
  27.764 -						return gbCheatList[i].value;
  27.765 -				}
  27.766 -				else
  27.767 -					return gbCheatList[i].value;
  27.768 -			}
  27.769 +		  if (((gbMemoryMap[0x0d] - gbWram)/0x1000) ==
  27.770 +		      (gbCheatList[i].code - 0x90))
  27.771 +		    return gbCheatList[i].value;
  27.772  		}
  27.773 +	      else
  27.774 +		return gbCheatList[i].value;
  27.775 +	    }
  27.776  	}
  27.777 -	return gbReadMemoryQuick(address);
  27.778 +    }
  27.779 +  return gbReadMemoryQuick(address);
  27.780  }
  27.781  
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/gba/EEprom.cpp	Sun Mar 04 14:33:52 2012 -0600
    28.3 @@ -0,0 +1,210 @@
    28.4 +#include <cstring>
    28.5 +
    28.6 +#include "GBA.h" // for SAVE_GAME_VERSION_3
    28.7 +#include "EEprom.h"
    28.8 +#include "../common/System.h"
    28.9 +#include "../common/Util.h"
   28.10 +
   28.11 +extern int32 cpuDmaCount;
   28.12 +
   28.13 +int32 eepromMode    = EEPROM_IDLE;
   28.14 +int32 eepromByte    = 0;
   28.15 +int32 eepromBits    = 0;
   28.16 +int32 eepromAddress = 0;
   28.17 +u8    eepromData[0x2000];
   28.18 +u8    eepromBuffer[16];
   28.19 +bool8 eepromInUse = false;
   28.20 +int32 eepromSize  = 512;
   28.21 +
   28.22 +variable_desc eepromSaveData[] = {
   28.23 +	{ &eepromMode,		sizeof(int32) },
   28.24 +	{ &eepromByte,		sizeof(int32) },
   28.25 +	{ &eepromBits,		sizeof(int32) },
   28.26 +	{ &eepromAddress,	sizeof(int32) },
   28.27 +	{ &eepromInUse,		sizeof(bool8) },
   28.28 +	{ &eepromData[0],             512 },
   28.29 +	{ &eepromBuffer[0],            16 },
   28.30 +	{ NULL,							0 }
   28.31 +};
   28.32 +
   28.33 +void eepromReset()
   28.34 +{
   28.35 +	eepromMode    = EEPROM_IDLE;
   28.36 +	eepromByte    = 0;
   28.37 +	eepromBits    = 0;
   28.38 +	eepromAddress = 0;
   28.39 +	eepromInUse   = false;
   28.40 +	eepromSize    = 512;
   28.41 +}
   28.42 +
   28.43 +void eepromErase()
   28.44 +{
   28.45 +	memset(eepromData, 0, 0x2000*sizeof(u8));
   28.46 +	eepromMode    = EEPROM_IDLE;
   28.47 +	eepromByte    = 0;
   28.48 +	eepromBits    = 0;
   28.49 +	eepromAddress = 0;
   28.50 +	memset(eepromBuffer, 0, 16*sizeof(u8));
   28.51 +	eepromInUse = false;
   28.52 +	eepromSize  = 512;
   28.53 +}
   28.54 +
   28.55 +void eepromSaveGame(gzFile gzFile)
   28.56 +{
   28.57 +	utilWriteData(gzFile, eepromSaveData);
   28.58 +	utilWriteInt(gzFile, eepromSize);
   28.59 +	utilGzWrite(gzFile, eepromData, 0x2000);
   28.60 +}
   28.61 +
   28.62 +void eepromReadGame(gzFile gzFile, int version)
   28.63 +{
   28.64 +	utilReadData(gzFile, eepromSaveData);
   28.65 +	if (version >= SAVE_GAME_VERSION_3)
   28.66 +	{
   28.67 +		eepromSize = utilReadInt(gzFile);
   28.68 +		utilGzRead(gzFile, eepromData, 0x2000);
   28.69 +	}
   28.70 +	else
   28.71 +	{
   28.72 +		// prior to 0.7.1, only 4K EEPROM was supported
   28.73 +		eepromSize = 512;
   28.74 +	}
   28.75 +}
   28.76 +
   28.77 +int eepromRead(u32 /* address */)
   28.78 +{
   28.79 +	switch (eepromMode)
   28.80 +	{
   28.81 +	case EEPROM_IDLE:
   28.82 +	case EEPROM_READADDRESS:
   28.83 +	case EEPROM_WRITEDATA:
   28.84 +		return 1;
   28.85 +	case EEPROM_READDATA:
   28.86 +	{
   28.87 +		eepromBits++;
   28.88 +		if (eepromBits == 4)
   28.89 +		{
   28.90 +			eepromMode = EEPROM_READDATA2;
   28.91 +			eepromBits = 0;
   28.92 +			eepromByte = 0;
   28.93 +		}
   28.94 +		return 0;
   28.95 +	}
   28.96 +	case EEPROM_READDATA2:
   28.97 +	{
   28.98 +		int data    = 0;
   28.99 +		int address = eepromAddress << 3;
  28.100 +		int mask    = 1 << (7 - (eepromBits & 7));
  28.101 +		data = (eepromData[address+eepromByte] & mask) ? 1 : 0;
  28.102 +		eepromBits++;
  28.103 +		if ((eepromBits & 7) == 0)
  28.104 +			eepromByte++;
  28.105 +		if (eepromBits == 0x40)
  28.106 +			eepromMode = EEPROM_IDLE;
  28.107 +		return data;
  28.108 +	}
  28.109 +	default:
  28.110 +		return 0;
  28.111 +	}
  28.112 +	return 1;
  28.113 +}
  28.114 +
  28.115 +void eepromWrite(u32 /* address */, u8 value)
  28.116 +{
  28.117 +	if (cpuDmaCount == 0)
  28.118 +		return;
  28.119 +	int bit = value & 1;
  28.120 +	switch (eepromMode)
  28.121 +	{
  28.122 +	case EEPROM_IDLE:
  28.123 +		eepromByte = 0;
  28.124 +		eepromBits = 1;
  28.125 +		eepromBuffer[eepromByte] = bit;
  28.126 +		eepromMode = EEPROM_READADDRESS;
  28.127 +		break;
  28.128 +	case EEPROM_READADDRESS:
  28.129 +		eepromBuffer[eepromByte] <<= 1;
  28.130 +		eepromBuffer[eepromByte]  |= bit;
  28.131 +		eepromBits++;
  28.132 +		if ((eepromBits & 7) == 0)
  28.133 +		{
  28.134 +			eepromByte++;
  28.135 +		}
  28.136 +		if (cpuDmaCount == 0x11 || cpuDmaCount == 0x51)
  28.137 +		{
  28.138 +			if (eepromBits == 0x11)
  28.139 +			{
  28.140 +				eepromInUse   = true;
  28.141 +				eepromSize    = 0x2000;
  28.142 +				eepromAddress = ((eepromBuffer[0] & 0x3F) << 8) |
  28.143 +				                ((eepromBuffer[1] & 0xFF));
  28.144 +				if (!(eepromBuffer[0] & 0x40))
  28.145 +				{
  28.146 +					eepromBuffer[0] = bit;
  28.147 +					eepromBits      = 1;
  28.148 +					eepromByte      = 0;
  28.149 +					eepromMode      = EEPROM_WRITEDATA;
  28.150 +				}
  28.151 +				else
  28.152 +				{
  28.153 +					eepromMode = EEPROM_READDATA;
  28.154 +					eepromByte = 0;
  28.155 +					eepromBits = 0;
  28.156 +				}
  28.157 +			}
  28.158 +		}
  28.159 +		else
  28.160 +		{
  28.161 +			if (eepromBits == 9)
  28.162 +			{
  28.163 +				eepromInUse   = true;
  28.164 +				eepromAddress = (eepromBuffer[0] & 0x3F);
  28.165 +				if (!(eepromBuffer[0] & 0x40))
  28.166 +				{
  28.167 +					eepromBuffer[0] = bit;
  28.168 +					eepromBits      = 1;
  28.169 +					eepromByte      = 0;
  28.170 +					eepromMode      = EEPROM_WRITEDATA;
  28.171 +				}
  28.172 +				else
  28.173 +				{
  28.174 +					eepromMode = EEPROM_READDATA;
  28.175 +					eepromByte = 0;
  28.176 +					eepromBits = 0;
  28.177 +				}
  28.178 +			}
  28.179 +		}
  28.180 +		break;
  28.181 +	case EEPROM_READDATA:
  28.182 +	case EEPROM_READDATA2:
  28.183 +		// should we reset here?
  28.184 +		eepromMode = EEPROM_IDLE;
  28.185 +		break;
  28.186 +	case EEPROM_WRITEDATA:
  28.187 +		eepromBuffer[eepromByte] <<= 1;
  28.188 +		eepromBuffer[eepromByte]  |= bit;
  28.189 +		eepromBits++;
  28.190 +		if ((eepromBits & 7) == 0)
  28.191 +		{
  28.192 +			eepromByte++;
  28.193 +		}
  28.194 +		if (eepromBits == 0x40)
  28.195 +		{
  28.196 +			eepromInUse = true;
  28.197 +			// write data;
  28.198 +			for (int i = 0; i < 8; i++)
  28.199 +			{
  28.200 +				eepromData[(eepromAddress << 3) + i] = eepromBuffer[i];
  28.201 +			}
  28.202 +			systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  28.203 +		}
  28.204 +		else if (eepromBits == 0x41)
  28.205 +		{
  28.206 +			eepromMode = EEPROM_IDLE;
  28.207 +			eepromByte = 0;
  28.208 +			eepromBits = 0;
  28.209 +		}
  28.210 +		break;
  28.211 +	}
  28.212 +}
  28.213 +
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/gba/EEprom.h	Sun Mar 04 14:33:52 2012 -0600
    29.3 @@ -0,0 +1,27 @@
    29.4 +#ifndef VBA_EEPROM_H
    29.5 +#define VBA_EEPROM_H
    29.6 +
    29.7 +#if _MSC_VER > 1000
    29.8 +#pragma once
    29.9 +#endif // _MSC_VER > 1000
   29.10 +
   29.11 +#include "zlib.h"
   29.12 +#include "../Port.h"
   29.13 +
   29.14 +extern void eepromSaveGame(gzFile gzFile);
   29.15 +extern void eepromReadGame(gzFile gzFile, int version);
   29.16 +extern int eepromRead(u32 address);
   29.17 +extern void eepromWrite(u32 address, u8 value);
   29.18 +extern void eepromReset();
   29.19 +extern void eepromErase();
   29.20 +extern u8    eepromData[0x2000];
   29.21 +extern bool8 eepromInUse;
   29.22 +extern int32 eepromSize;
   29.23 +
   29.24 +#define EEPROM_IDLE           0
   29.25 +#define EEPROM_READADDRESS    1
   29.26 +#define EEPROM_READDATA       2
   29.27 +#define EEPROM_READDATA2      3
   29.28 +#define EEPROM_WRITEDATA      4
   29.29 +
   29.30 +#endif // VBA_EEPROM_H
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/gba/Flash.cpp	Sun Mar 04 14:33:52 2012 -0600
    30.3 @@ -0,0 +1,285 @@
    30.4 +#include <cstdio>
    30.5 +#include <cstring>
    30.6 +
    30.7 +#include "Flash.h"
    30.8 +#include "GBA.h"
    30.9 +#include "GBAGlobals.h"
   30.10 +#include "Sram.h"
   30.11 +#include "../common/System.h"
   30.12 +#include "../common/Util.h"
   30.13 +
   30.14 +#define FLASH_READ_ARRAY         0
   30.15 +#define FLASH_CMD_1              1
   30.16 +#define FLASH_CMD_2              2
   30.17 +#define FLASH_AUTOSELECT         3
   30.18 +#define FLASH_CMD_3              4
   30.19 +#define FLASH_CMD_4              5
   30.20 +#define FLASH_CMD_5              6
   30.21 +#define FLASH_ERASE_COMPLETE     7
   30.22 +#define FLASH_PROGRAM            8
   30.23 +#define FLASH_SETBANK            9
   30.24 +
   30.25 +u8    flashSaveMemory[0x20000 + 4];
   30.26 +int32 flashState          = FLASH_READ_ARRAY;
   30.27 +int32 flashReadState      = FLASH_READ_ARRAY;
   30.28 +int32 flashSize           = 0x10000;
   30.29 +int32 flashDeviceID       = 0x1b;
   30.30 +int32 flashManufacturerID = 0x32;
   30.31 +int32 flashBank           = 0;
   30.32 +
   30.33 +static variable_desc flashSaveData[] = {
   30.34 +	{ &flashState,         sizeof(int32) },
   30.35 +	{ &flashReadState,     sizeof(int32) },
   30.36 +	{ &flashSaveMemory[0],       0x10000 },
   30.37 +	{ NULL,                            0 }
   30.38 +};
   30.39 +
   30.40 +static variable_desc flashSaveData2[] = {
   30.41 +	{ &flashState,         sizeof(int32) },
   30.42 +	{ &flashReadState,     sizeof(int32) },
   30.43 +	{ &flashSize,          sizeof(int32) },
   30.44 +	{ &flashSaveMemory[0],       0x20000 },
   30.45 +	{ NULL,                            0 }
   30.46 +};
   30.47 +
   30.48 +static variable_desc flashSaveData3[] = {
   30.49 +	{ &flashState,         sizeof(int32) },
   30.50 +	{ &flashReadState,     sizeof(int32) },
   30.51 +	{ &flashSize,          sizeof(int32) },
   30.52 +	{ &flashBank,          sizeof(int32) },
   30.53 +	{ &flashSaveMemory[0],       0x20000 },
   30.54 +	{ NULL,                            0 }
   30.55 +};
   30.56 +
   30.57 +void flashReset()
   30.58 +{
   30.59 +	flashState     = FLASH_READ_ARRAY;
   30.60 +	flashReadState = FLASH_READ_ARRAY;
   30.61 +	flashBank      = 0;
   30.62 +}
   30.63 +
   30.64 +void flashErase()
   30.65 +{
   30.66 +	memset(flashSaveMemory, 0, 0x20000*sizeof(u8));
   30.67 +	flashState          = FLASH_READ_ARRAY;
   30.68 +	flashReadState      = FLASH_READ_ARRAY;
   30.69 +	flashSize           = 0x10000;
   30.70 +	flashDeviceID       = 0x1b;
   30.71 +	flashManufacturerID = 0x32;
   30.72 +	flashBank           = 0;
   30.73 +}
   30.74 +
   30.75 +void flashSaveGame(gzFile gzFile)
   30.76 +{
   30.77 +	utilWriteData(gzFile, flashSaveData3);
   30.78 +}
   30.79 +
   30.80 +void flashReadGame(gzFile gzFile, int version)
   30.81 +{
   30.82 +	if (version < SAVE_GAME_VERSION_5)
   30.83 +		utilReadData(gzFile, flashSaveData);
   30.84 +	else if (version < SAVE_GAME_VERSION_7)
   30.85 +	{
   30.86 +		utilReadData(gzFile, flashSaveData2);
   30.87 +		flashBank = 0;
   30.88 +		flashSetSize(flashSize);
   30.89 +	}
   30.90 +	else
   30.91 +	{
   30.92 +		utilReadData(gzFile, flashSaveData3);
   30.93 +	}
   30.94 +}
   30.95 +
   30.96 +void flashSetSize(int size)
   30.97 +{
   30.98 +	//  log("Setting flash size to %d\n", size);
   30.99 +	flashSize = size;
  30.100 +	if (size == 0x10000)
  30.101 +	{
  30.102 +		flashDeviceID       = 0x1b;
  30.103 +		flashManufacturerID = 0x32;
  30.104 +	}
  30.105 +	else
  30.106 +	{
  30.107 +		flashDeviceID       = 0x13; //0x09;
  30.108 +		flashManufacturerID = 0x62; //0xc2;
  30.109 +	}
  30.110 +}
  30.111 +
  30.112 +u8 flashRead(u32 address)
  30.113 +{
  30.114 +	//  log("Reading %08x from %08x\n", address, reg[15].I);
  30.115 +	//  log("Current read state is %d\n", flashReadState);
  30.116 +	address &= 0xFFFF;
  30.117 +
  30.118 +	switch (flashReadState)
  30.119 +	{
  30.120 +	case FLASH_READ_ARRAY:
  30.121 +		return flashSaveMemory[(flashBank << 16) + address];
  30.122 +	case FLASH_AUTOSELECT:
  30.123 +		switch (address & 0xFF)
  30.124 +		{
  30.125 +		case 0:
  30.126 +			// manufacturer ID
  30.127 +			return u8(flashManufacturerID);
  30.128 +		case 1:
  30.129 +			// device ID
  30.130 +			return u8(flashDeviceID);
  30.131 +		}
  30.132 +		break;
  30.133 +	case FLASH_ERASE_COMPLETE:
  30.134 +		flashState     = FLASH_READ_ARRAY;
  30.135 +		flashReadState = FLASH_READ_ARRAY;
  30.136 +		return 0xFF;
  30.137 +	}
  30.138 +	;
  30.139 +	return 0;
  30.140 +}
  30.141 +
  30.142 +void flashSaveDecide(u32 address, u8 byte)
  30.143 +{
  30.144 +	//  log("Deciding save type %08x\n", address);
  30.145 +	if (address == 0x0e005555)
  30.146 +	{
  30.147 +		saveType        = 2;
  30.148 +		cpuSaveGameFunc = flashWrite;
  30.149 +	}
  30.150 +	else
  30.151 +	{
  30.152 +		saveType        = 1;
  30.153 +		cpuSaveGameFunc = sramWrite;
  30.154 +	}
  30.155 +
  30.156 +	(*cpuSaveGameFunc)(address, byte);
  30.157 +}
  30.158 +
  30.159 +void flashWrite(u32 address, u8 byte)
  30.160 +{
  30.161 +	//  log("Writing %02x at %08x\n", byte, address);
  30.162 +	//  log("Current state is %d\n", flashState);
  30.163 +	address &= 0xFFFF;
  30.164 +	switch (flashState)
  30.165 +	{
  30.166 +	case FLASH_READ_ARRAY:
  30.167 +		if (address == 0x5555 && byte == 0xAA)
  30.168 +			flashState = FLASH_CMD_1;
  30.169 +		break;
  30.170 +	case FLASH_CMD_1:
  30.171 +		if (address == 0x2AAA && byte == 0x55)
  30.172 +			flashState = FLASH_CMD_2;
  30.173 +		else
  30.174 +			flashState = FLASH_READ_ARRAY;
  30.175 +		break;
  30.176 +	case FLASH_CMD_2:
  30.177 +		if (address == 0x5555)
  30.178 +		{
  30.179 +			if (byte == 0x90)
  30.180 +			{
  30.181 +				flashState     = FLASH_AUTOSELECT;
  30.182 +				flashReadState = FLASH_AUTOSELECT;
  30.183 +			}
  30.184 +			else if (byte == 0x80)
  30.185 +			{
  30.186 +				flashState = FLASH_CMD_3;
  30.187 +			}
  30.188 +			else if (byte == 0xF0)
  30.189 +			{
  30.190 +				flashState     = FLASH_READ_ARRAY;
  30.191 +				flashReadState = FLASH_READ_ARRAY;
  30.192 +			}
  30.193 +			else if (byte == 0xA0)
  30.194 +			{
  30.195 +				flashState = FLASH_PROGRAM;
  30.196 +			}
  30.197 +			else if (byte == 0xB0 && flashSize == 0x20000)
  30.198 +			{
  30.199 +				flashState = FLASH_SETBANK;
  30.200 +			}
  30.201 +			else
  30.202 +			{
  30.203 +				flashState     = FLASH_READ_ARRAY;
  30.204 +				flashReadState = FLASH_READ_ARRAY;
  30.205 +			}
  30.206 +		}
  30.207 +		else
  30.208 +		{
  30.209 +			flashState     = FLASH_READ_ARRAY;
  30.210 +			flashReadState = FLASH_READ_ARRAY;
  30.211 +		}
  30.212 +		break;
  30.213 +	case FLASH_CMD_3:
  30.214 +		if (address == 0x5555 && byte == 0xAA)
  30.215 +		{
  30.216 +			flashState = FLASH_CMD_4;
  30.217 +		}
  30.218 +		else
  30.219 +		{
  30.220 +			flashState     = FLASH_READ_ARRAY;
  30.221 +			flashReadState = FLASH_READ_ARRAY;
  30.222 +		}
  30.223 +		break;
  30.224 +	case FLASH_CMD_4:
  30.225 +		if (address == 0x2AAA && byte == 0x55)
  30.226 +		{
  30.227 +			flashState = FLASH_CMD_5;
  30.228 +		}
  30.229 +		else
  30.230 +		{
  30.231 +			flashState     = FLASH_READ_ARRAY;
  30.232 +			flashReadState = FLASH_READ_ARRAY;
  30.233 +		}
  30.234 +		break;
  30.235 +	case FLASH_CMD_5:
  30.236 +		if (byte == 0x30)
  30.237 +		{
  30.238 +			// SECTOR ERASE
  30.239 +			memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)],
  30.240 +			       0,
  30.241 +			       0x1000);
  30.242 +			systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  30.243 +			flashReadState = FLASH_ERASE_COMPLETE;
  30.244 +		}
  30.245 +		else if (byte == 0x10)
  30.246 +		{
  30.247 +			// CHIP ERASE
  30.248 +			memset(flashSaveMemory, 0, flashSize);
  30.249 +			systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  30.250 +			flashReadState = FLASH_ERASE_COMPLETE;
  30.251 +		}
  30.252 +		else
  30.253 +		{
  30.254 +			flashState     = FLASH_READ_ARRAY;
  30.255 +			flashReadState = FLASH_READ_ARRAY;
  30.256 +		}
  30.257 +		break;
  30.258 +	case FLASH_AUTOSELECT:
  30.259 +		if (byte == 0xF0)
  30.260 +		{
  30.261 +			flashState     = FLASH_READ_ARRAY;
  30.262 +			flashReadState = FLASH_READ_ARRAY;
  30.263 +		}
  30.264 +		else if (address == 0x5555 && byte == 0xAA)
  30.265 +			flashState = FLASH_CMD_1;
  30.266 +		else
  30.267 +		{
  30.268 +			flashState     = FLASH_READ_ARRAY;
  30.269 +			flashReadState = FLASH_READ_ARRAY;
  30.270 +		}
  30.271 +		break;
  30.272 +	case FLASH_PROGRAM:
  30.273 +		flashSaveMemory[(flashBank<<16)+address] = byte;
  30.274 +		systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
  30.275 +		flashState     = FLASH_READ_ARRAY;
  30.276 +		flashReadState = FLASH_READ_ARRAY;
  30.277 +		break;
  30.278 +	case FLASH_SETBANK:
  30.279 +		if (address == 0)
  30.280 +		{
  30.281 +			flashBank = (byte & 1);
  30.282 +		}
  30.283 +		flashState     = FLASH_READ_ARRAY;
  30.284 +		flashReadState = FLASH_READ_ARRAY;
  30.285 +		break;
  30.286 +	}
  30.287 +}
  30.288 +
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/gba/Flash.h	Sun Mar 04 14:33:52 2012 -0600
    31.3 @@ -0,0 +1,23 @@
    31.4 +#ifndef VBA_FLASH_H
    31.5 +#define VBA_FLASH_H
    31.6 +
    31.7 +#if _MSC_VER > 1000
    31.8 +#pragma once
    31.9 +#endif // _MSC_VER > 1000
   31.10 +
   31.11 +#include "zlib.h"
   31.12 +#include "../Port.h"
   31.13 +
   31.14 +extern void flashSaveGame(gzFile gzFile);
   31.15 +extern void flashReadGame(gzFile gzFile, int version);
   31.16 +extern u8 flashRead(u32 address);
   31.17 +extern void flashWrite(u32 address, u8 byte);
   31.18 +extern u8 flashSaveMemory[0x20000 + 4];
   31.19 +extern void flashSaveDecide(u32 address, u8 byte);
   31.20 +extern void flashReset();
   31.21 +extern void flashErase();
   31.22 +extern void flashSetSize(int size);
   31.23 +
   31.24 +extern int32 flashSize;
   31.25 +
   31.26 +#endif // VBA_FLASH_H
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/gba/GBA.cpp	Sun Mar 04 14:33:52 2012 -0600
    32.3 @@ -0,0 +1,4567 @@
    32.4 +#include <cstdio>
    32.5 +#include <cstdlib>
    32.6 +#include <cstdarg>
    32.7 +#include <cstring>
    32.8 +
    32.9 +#include "../Port.h"
   32.10 +#include "../NLS.h"
   32.11 +#include "GBA.h"
   32.12 +//#include "GBAGlobals.h"
   32.13 +#include "GBACheats.h" // FIXME: SDL requires this included before "GBAinline.h"
   32.14 +#include "GBAinline.h"
   32.15 +#include "GBAGfx.h"
   32.16 +#include "GBASound.h"
   32.17 +#include "EEprom.h"
   32.18 +#include "Flash.h"
   32.19 +#include "Sram.h"
   32.20 +#include "bios.h"
   32.21 +#include "elf.h"
   32.22 +#include "agbprint.h"
   32.23 +#include "../common/unzip.h"
   32.24 +#include "../common/Util.h"
   32.25 +#include "../common/movie.h"
   32.26 +#include "../common/vbalua.h"
   32.27 +
   32.28 +#ifdef PROFILING
   32.29 +#include "../prof/prof.h"
   32.30 +#endif
   32.31 +
   32.32 +#define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]), value)
   32.33 +
   32.34 +#ifdef __GNUC__
   32.35 +#define _stricmp strcasecmp
   32.36 +#endif
   32.37 +
   32.38 +#define CPU_BREAK_LOOP \
   32.39 +    cpuSavedTicks	 = cpuSavedTicks - *extCpuLoopTicks; \
   32.40 +    *extCpuLoopTicks = *extClockTicks;
   32.41 +
   32.42 +#define CPU_BREAK_LOOP_2 \
   32.43 +    cpuSavedTicks	 = cpuSavedTicks - *extCpuLoopTicks; \
   32.44 +    *extCpuLoopTicks = *extClockTicks; \
   32.45 +    *extTicks		 = *extClockTicks;
   32.46 +
   32.47 +int32 cpuDmaTicksToUpdate = 0;
   32.48 +int32 cpuDmaCount		  = 0;
   32.49 +bool8 cpuDmaHack		  = 0;
   32.50 +u32	  cpuDmaLast		  = 0;
   32.51 +int32 dummyAddress		  = 0;
   32.52 +
   32.53 +int32 *extCpuLoopTicks = NULL;
   32.54 +int32 *extClockTicks   = NULL;
   32.55 +int32 *extTicks		   = NULL;
   32.56 +
   32.57 +#if (defined(WIN32) && !defined(SDL))
   32.58 +HANDLE mapROM;        // shared memory handles
   32.59 +HANDLE mapWORKRAM;
   32.60 +HANDLE mapBIOS;
   32.61 +HANDLE mapIRAM;
   32.62 +HANDLE mapPALETTERAM;
   32.63 +HANDLE mapVRAM;
   32.64 +HANDLE mapOAM;
   32.65 +HANDLE mapPIX;
   32.66 +HANDLE mapIOMEM;
   32.67 +#endif
   32.68 +
   32.69 +int32 gbaSaveType = 0;      // used to remember the save type on reset
   32.70 +bool8 intState	  = false;
   32.71 +bool8 stopState	  = false;
   32.72 +bool8 holdState	  = false;
   32.73 +int32 holdType	  = 0;
   32.74 +bool8 cpuSramEnabled		 = true;
   32.75 +bool8 cpuFlashEnabled		 = true;
   32.76 +bool8 cpuEEPROMEnabled		 = true;
   32.77 +bool8 cpuEEPROMSensorEnabled = false;
   32.78 +
   32.79 +#ifdef PROFILING
   32.80 +int profilingTicks		  = 0;
   32.81 +int profilingTicksReload  = 0;
   32.82 +static char *profilBuffer = NULL;
   32.83 +static int	 profilSize	  = 0;
   32.84 +static u32	 profilLowPC  = 0;
   32.85 +static int	 profilScale  = 0;
   32.86 +#endif
   32.87 +bool8 freezeWorkRAM[0x40000];
   32.88 +bool8 freezeInternalRAM[0x8000];
   32.89 +int32 lcdTicks = 960;
   32.90 +bool8 timer0On = false;
   32.91 +int32 timer0Ticks		= 0;
   32.92 +int32 timer0Reload		= 0;
   32.93 +int32 timer0ClockReload = 0;
   32.94 +bool8 timer1On			= false;
   32.95 +int32 timer1Ticks		= 0;
   32.96 +int32 timer1Reload		= 0;
   32.97 +int32 timer1ClockReload = 0;
   32.98 +bool8 timer2On			= false;
   32.99 +int32 timer2Ticks		= 0;
  32.100 +int32 timer2Reload		= 0;
  32.101 +int32 timer2ClockReload = 0;
  32.102 +bool8 timer3On			= false;
  32.103 +int32 timer3Ticks		= 0;
  32.104 +int32 timer3Reload		= 0;
  32.105 +int32 timer3ClockReload = 0;
  32.106 +u32	  dma0Source		= 0;
  32.107 +u32	  dma0Dest			= 0;
  32.108 +u32	  dma1Source		= 0;
  32.109 +u32	  dma1Dest			= 0;
  32.110 +u32	  dma2Source		= 0;
  32.111 +u32	  dma2Dest			= 0;
  32.112 +u32	  dma3Source		= 0;
  32.113 +u32	  dma3Dest			= 0;
  32.114 +void  (*cpuSaveGameFunc)(u32, u8) = flashSaveDecide;
  32.115 +void  (*renderLine)() = mode0RenderLine;
  32.116 +bool8 fxOn = false;
  32.117 +bool8 windowOn		 = false;
  32.118 +int32 frameSkipCount = 0;
  32.119 +u32	  gbaLastTime	 = 0;
  32.120 +int32 gbaFrameCount	 = 0;
  32.121 +bool8 prefetchActive = false, prefetchPrevActive = false, prefetchApplies = false;
  32.122 +char  buffer[1024];
  32.123 +FILE *out = NULL;
  32.124 +
  32.125 +static bool newFrame = true;
  32.126 +static bool pauseAfterFrameAdvance = false;
  32.127 +
  32.128 +const int32 TIMER_TICKS[4] = {
  32.129 +	1,
  32.130 +	64,
  32.131 +	256,
  32.132 +	1024
  32.133 +};
  32.134 +
  32.135 +const int32 thumbCycles[] = {
  32.136 +//  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  32.137 +	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0
  32.138 +	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 1
  32.139 +	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 2
  32.140 +	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 3
  32.141 +	1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // 4
  32.142 +	2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // 5
  32.143 +	2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,  // 6
  32.144 +	2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,  // 7
  32.145 +	2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,  // 8
  32.146 +	2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,  // 9
  32.147 +	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // a
  32.148 +	1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1,  // b
  32.149 +	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,  // c
  32.150 +	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,  // d
  32.151 +	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // e
  32.152 +	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2   // f
  32.153 +};
  32.154 +
  32.155 +const int32 gamepakRamWaitState[4] = { 4, 3, 2, 8 };
  32.156 +const int32 gamepakWaitState[8] =  { 4, 3, 2, 8, 4, 3, 2, 8 };
  32.157 +const int32 gamepakWaitState0[8] = { 2, 2, 2, 2, 1, 1, 1, 1 };
  32.158 +const int32 gamepakWaitState1[8] = { 4, 4, 4, 4, 1, 1, 1, 1 };
  32.159 +const int32 gamepakWaitState2[8] = { 8, 8, 8, 8, 1, 1, 1, 1 };
  32.160 +
  32.161 +int32 memoryWait[16] =
  32.162 +{ 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
  32.163 +int32 memoryWait32[16] =
  32.164 +{ 0, 0, 9, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
  32.165 +int32 memoryWaitSeq[16] =
  32.166 +{ 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 };
  32.167 +int32 memoryWaitSeq32[16] =
  32.168 +{ 2, 0, 3, 0, 0, 2, 2, 0, 4, 4, 8, 8, 16, 16, 8, 0 };
  32.169 +int32 memoryWaitFetch[16] =
  32.170 +{ 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
  32.171 +int32 memoryWaitFetch32[16] =
  32.172 +{ 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
  32.173 +
  32.174 +const int32 cpuMemoryWait[16] = {
  32.175 +	0, 0, 2, 0, 0, 0, 0, 0,
  32.176 +	2, 2, 2, 2, 2, 2, 0, 0
  32.177 +};
  32.178 +const int32 cpuMemoryWait32[16] = {
  32.179 +	0, 0, 3, 0, 0, 0, 0, 0,
  32.180 +	3, 3, 3, 3, 3, 3, 0, 0
  32.181 +};
  32.182 +
  32.183 +const bool8 memory32[16] = {
  32.184 +	true, false, false, true, true, false, false, true, false, false, false, false, false, false, true, false
  32.185 +};
  32.186 +
  32.187 +u8 biosProtected[4];
  32.188 +
  32.189 +u8 cpuBitsSet[256];
  32.190 +u8 cpuLowestBitSet[256];
  32.191 +
  32.192 +#ifdef WORDS_BIGENDIAN
  32.193 +bool8 cpuBiosSwapped = false;
  32.194 +#endif
  32.195 +
  32.196 +u32 myROM[] = {
  32.197 +	0xEA000006,
  32.198 +	0xEA000093,
  32.199 +	0xEA000006,
  32.200 +	0x00000000,
  32.201 +	0x00000000,
  32.202 +	0x00000000,
  32.203 +	0xEA000088,
  32.204 +	0x00000000,
  32.205 +	0xE3A00302,
  32.206 +	0xE1A0F000,
  32.207 +	0xE92D5800,
  32.208 +	0xE55EC002,
  32.209 +	0xE28FB03C,
  32.210 +	0xE79BC10C,
  32.211 +	0xE14FB000,
  32.212 +	0xE92D0800,
  32.213 +	0xE20BB080,
  32.214 +	0xE38BB01F,
  32.215 +	0xE129F00B,
  32.216 +	0xE92D4004,
  32.217 +	0xE1A0E00F,
  32.218 +	0xE12FFF1C,
  32.219 +	0xE8BD4004,
  32.220 +	0xE3A0C0D3,
  32.221 +	0xE129F00C,
  32.222 +	0xE8BD0800,
  32.223 +	0xE169F00B,
  32.224 +	0xE8BD5800,
  32.225 +	0xE1B0F00E,
  32.226 +	0x0000009C,
  32.227 +	0x0000009C,
  32.228 +	0x0000009C,
  32.229 +	0x0000009C,
  32.230 +	0x000001F8,
  32.231 +	0x000001F0,
  32.232 +	0x000000AC,
  32.233 +	0x000000A0,
  32.234 +	0x000000FC,
  32.235 +	0x00000168,
  32.236 +	0xE12FFF1E,
  32.237 +	0xE1A03000,
  32.238 +	0xE1A00001,
  32.239 +	0xE1A01003,
  32.240 +	0xE2113102,
  32.241 +	0x42611000,
  32.242 +	0xE033C040,
  32.243 +	0x22600000,
  32.244 +	0xE1B02001,
  32.245 +	0xE15200A0,
  32.246 +	0x91A02082,
  32.247 +	0x3AFFFFFC,
  32.248 +	0xE1500002,
  32.249 +	0xE0A33003,
  32.250 +	0x20400002,
  32.251 +	0xE1320001,
  32.252 +	0x11A020A2,
  32.253 +	0x1AFFFFF9,
  32.254 +	0xE1A01000,
  32.255 +	0xE1A00003,
  32.256 +	0xE1B0C08C,
  32.257 +	0x22600000,
  32.258 +	0x42611000,
  32.259 +	0xE12FFF1E,
  32.260 +	0xE92D0010,
  32.261 +	0xE1A0C000,
  32.262 +	0xE3A01001,
  32.263 +	0xE1500001,
  32.264 +	0x81A000A0,
  32.265 +	0x81A01081,
  32.266 +	0x8AFFFFFB,
  32.267 +	0xE1A0000C,
  32.268 +	0xE1A04001,
  32.269 +	0xE3A03000,
  32.270 +	0xE1A02001,
  32.271 +	0xE15200A0,
  32.272 +	0x91A02082,
  32.273 +	0x3AFFFFFC,
  32.274 +	0xE1500002,
  32.275 +	0xE0A33003,
  32.276 +	0x20400002,
  32.277 +	0xE1320001,
  32.278 +	0x11A020A2,
  32.279 +	0x1AFFFFF9,
  32.280 +	0xE0811003,
  32.281 +	0xE1B010A1,
  32.282 +	0xE1510004,
  32.283 +	0x3AFFFFEE,
  32.284 +	0xE1A00004,
  32.285 +	0xE8BD0010,
  32.286 +	0xE12FFF1E,
  32.287 +	0xE0010090,
  32.288 +	0xE1A01741,
  32.289 +	0xE2611000,
  32.290 +	0xE3A030A9,
  32.291 +	0xE0030391,
  32.292 +	0xE1A03743,
  32.293 +	0xE2833E39,
  32.294 +	0xE0030391,
  32.295 +	0xE1A03743,
  32.296 +	0xE2833C09,
  32.297 +	0xE283301C,
  32.298 +	0xE0030391,
  32.299 +	0xE1A03743,
  32.300 +	0xE2833C0F,
  32.301 +	0xE28330B6,
  32.302 +	0xE0030391,
  32.303 +	0xE1A03743,
  32.304 +	0xE2833C16,
  32.305 +	0xE28330AA,
  32.306 +	0xE0030391,
  32.307 +	0xE1A03743,
  32.308 +	0xE2833A02,
  32.309 +	0xE2833081,
  32.310 +	0xE0030391,
  32.311 +	0xE1A03743,
  32.312 +	0xE2833C36,
  32.313 +	0xE2833051,
  32.314 +	0xE0030391,
  32.315 +	0xE1A03743,
  32.316 +	0xE2833CA2,
  32.317 +	0xE28330F9,
  32.318 +	0xE0000093,
  32.319 +	0xE1A00840,
  32.320 +	0xE12FFF1E,
  32.321 +	0xE3A00001,
  32.322 +	0xE3A01001,
  32.323 +	0xE92D4010,
  32.324 +	0xE3A0C301,
  32.325 +	0xE3A03000,
  32.326 +	0xE3A04001,
  32.327 +	0xE3500000,
  32.328 +	0x1B000004,
  32.329 +	0xE5CC3301,
  32.330 +	0xEB000002,
  32.331 +	0x0AFFFFFC,
  32.332 +	0xE8BD4010,
  32.333 +	0xE12FFF1E,
  32.334 +	0xE5CC3208,
  32.335 +	0xE15C20B8,
  32.336 +	0xE0110002,
  32.337 +	0x10200002,
  32.338 +	0x114C00B8,
  32.339 +	0xE5CC4208,
  32.340 +	0xE12FFF1E,
  32.341 +	0xE92D500F,
  32.342 +	0xE3A00301,
  32.343 +	0xE1A0E00F,
  32.344 +	0xE510F004,
  32.345 +	0xE8BD500F,
  32.346 +	0xE25EF004,
  32.347 +	0xE59FD044,
  32.348 +	0xE92D5000,
  32.349 +	0xE14FC000,
  32.350 +	0xE10FE000,
  32.351 +	0xE92D5000,
  32.352 +	0xE3A0C302,
  32.353 +	0xE5DCE09C,
  32.354 +	0xE35E00A5,
  32.355 +	0x1A000004,
  32.356 +	0x05DCE0B4,
  32.357 +	0x021EE080,
  32.358 +	0xE28FE004,
  32.359 +	0x159FF018,
  32.360 +	0x059FF018,
  32.361 +	0xE59FD018,
  32.362 +	0xE8BD5000,
  32.363 +	0xE169F00C,
  32.364 +	0xE8BD5000,
  32.365 +	0xE25EF004,
  32.366 +	0x03007FF0,
  32.367 +	0x09FE2000,
  32.368 +	0x09FFC000,
  32.369 +	0x03007FE0
  32.370 +};
  32.371 +
  32.372 +variable_desc saveGameStruct[] = {
  32.373 +	{ &DISPCNT,			  sizeof(u16)				 },
  32.374 +	{ &DISPSTAT,		  sizeof(u16)				 },
  32.375 +	{ &VCOUNT,			  sizeof(u16)				 },
  32.376 +	{ &BG0CNT,			  sizeof(u16)				 },
  32.377 +	{ &BG1CNT,			  sizeof(u16)				 },
  32.378 +	{ &BG2CNT,			  sizeof(u16)				 },
  32.379 +	{ &BG3CNT,			  sizeof(u16)				 },
  32.380 +	{ &BG0HOFS,			  sizeof(u16)				 },
  32.381 +	{ &BG0VOFS,			  sizeof(u16)				 },
  32.382 +	{ &BG1HOFS,			  sizeof(u16)				 },
  32.383 +	{ &BG1VOFS,			  sizeof(u16)				 },
  32.384 +	{ &BG2HOFS,			  sizeof(u16)				 },
  32.385 +	{ &BG2VOFS,			  sizeof(u16)				 },
  32.386 +	{ &BG3HOFS,			  sizeof(u16)				 },
  32.387 +	{ &BG3VOFS,			  sizeof(u16)				 },
  32.388 +	{ &BG2PA,			  sizeof(u16)				 },
  32.389 +	{ &BG2PB,			  sizeof(u16)				 },
  32.390 +	{ &BG2PC,			  sizeof(u16)				 },
  32.391 +	{ &BG2PD,			  sizeof(u16)				 },
  32.392 +	{ &BG2X_L,			  sizeof(u16)				 },
  32.393 +	{ &BG2X_H,			  sizeof(u16)				 },
  32.394 +	{ &BG2Y_L,			  sizeof(u16)				 },
  32.395 +	{ &BG2Y_H,			  sizeof(u16)				 },
  32.396 +	{ &BG3PA,			  sizeof(u16)				 },
  32.397 +	{ &BG3PB,			  sizeof(u16)				 },
  32.398 +	{ &BG3PC,			  sizeof(u16)				 },
  32.399 +	{ &BG3PD,			  sizeof(u16)				 },
  32.400 +	{ &BG3X_L,			  sizeof(u16)				 },
  32.401 +	{ &BG3X_H,			  sizeof(u16)				 },
  32.402 +	{ &BG3Y_L,			  sizeof(u16)				 },
  32.403 +	{ &BG3Y_H,			  sizeof(u16)				 },
  32.404 +	{ &WIN0H,			  sizeof(u16)				 },
  32.405 +	{ &WIN1H,			  sizeof(u16)				 },
  32.406 +	{ &WIN0V,			  sizeof(u16)				 },
  32.407 +	{ &WIN1V,			  sizeof(u16)				 },
  32.408 +	{ &WININ,			  sizeof(u16)				 },
  32.409 +	{ &WINOUT,			  sizeof(u16)				 },
  32.410 +	{ &MOSAIC,			  sizeof(u16)				 },
  32.411 +	{ &BLDMOD,			  sizeof(u16)				 },
  32.412 +	{ &COLEV,			  sizeof(u16)				 },
  32.413 +	{ &COLY,			  sizeof(u16)				 },
  32.414 +	{ &DM0SAD_L,		  sizeof(u16)				 },
  32.415 +	{ &DM0SAD_H,		  sizeof(u16)				 },
  32.416 +	{ &DM0DAD_L,		  sizeof(u16)				 },
  32.417 +	{ &DM0DAD_H,		  sizeof(u16)				 },
  32.418 +	{ &DM0CNT_L,		  sizeof(u16)				 },
  32.419 +	{ &DM0CNT_H,		  sizeof(u16)				 },
  32.420 +	{ &DM1SAD_L,		  sizeof(u16)				 },
  32.421 +	{ &DM1SAD_H,		  sizeof(u16)				 },
  32.422 +	{ &DM1DAD_L,		  sizeof(u16)				 },
  32.423 +	{ &DM1DAD_H,		  sizeof(u16)				 },
  32.424 +	{ &DM1CNT_L,		  sizeof(u16)				 },
  32.425 +	{ &DM1CNT_H,		  sizeof(u16)				 },
  32.426 +	{ &DM2SAD_L,		  sizeof(u16)				 },
  32.427 +	{ &DM2SAD_H,		  sizeof(u16)				 },
  32.428 +	{ &DM2DAD_L,		  sizeof(u16)				 },
  32.429 +	{ &DM2DAD_H,		  sizeof(u16)				 },
  32.430 +	{ &DM2CNT_L,		  sizeof(u16)				 },
  32.431 +	{ &DM2CNT_H,		  sizeof(u16)				 },
  32.432 +	{ &DM3SAD_L,		  sizeof(u16)				 },
  32.433 +	{ &DM3SAD_H,		  sizeof(u16)				 },
  32.434 +	{ &DM3DAD_L,		  sizeof(u16)				 },
  32.435 +	{ &DM3DAD_H,		  sizeof(u16)				 },
  32.436 +	{ &DM3CNT_L,		  sizeof(u16)				 },
  32.437 +	{ &DM3CNT_H,		  sizeof(u16)				 },
  32.438 +	{ &TM0D,			  sizeof(u16)				 },
  32.439 +	{ &TM0CNT,			  sizeof(u16)				 },
  32.440 +	{ &TM1D,			  sizeof(u16)				 },
  32.441 +	{ &TM1CNT,			  sizeof(u16)				 },
  32.442 +	{ &TM2D,			  sizeof(u16)				 },
  32.443 +	{ &TM2CNT,			  sizeof(u16)				 },
  32.444 +	{ &TM3D,			  sizeof(u16)				 },
  32.445 +	{ &TM3CNT,			  sizeof(u16)				 },
  32.446 +	{ &P1,				  sizeof(u16)				 },
  32.447 +	{ &IE,				  sizeof(u16)				 },
  32.448 +	{ &IF,				  sizeof(u16)				 },
  32.449 +	{ &IME,				  sizeof(u16)				 },
  32.450 +	{ &holdState,		  sizeof(bool8)				 },
  32.451 +	{ &holdType,		  sizeof(int32)				 },
  32.452 +	{ &lcdTicks,		  sizeof(int32)				 },
  32.453 +	{ &timer0On,		  sizeof(bool8)				 },
  32.454 +	{ &timer0Ticks,		  sizeof(int32)				 },
  32.455 +	{ &timer0Reload,	  sizeof(int32)				 },
  32.456 +	{ &timer0ClockReload, sizeof(int32)				 },
  32.457 +	{ &timer1On,		  sizeof(bool8)				 },
  32.458 +	{ &timer1Ticks,		  sizeof(int32)				 },
  32.459 +	{ &timer1Reload,	  sizeof(int32)				 },
  32.460 +	{ &timer1ClockReload, sizeof(int32)				 },
  32.461 +	{ &timer2On,		  sizeof(bool8)				 },
  32.462 +	{ &timer2Ticks,		  sizeof(int32)				 },
  32.463 +	{ &timer2Reload,	  sizeof(int32)				 },
  32.464 +	{ &timer2ClockReload, sizeof(int32)				 },
  32.465 +	{ &timer3On,		  sizeof(bool8)				 },
  32.466 +	{ &timer3Ticks,		  sizeof(int32)				 },
  32.467 +	{ &timer3Reload,	  sizeof(int32)				 },
  32.468 +	{ &timer3ClockReload, sizeof(int32)				 },
  32.469 +	{ &dma0Source,		  sizeof(u32)				 },
  32.470 +	{ &dma0Dest,		  sizeof(u32)				 },
  32.471 +	{ &dma1Source,		  sizeof(u32)				 },
  32.472 +	{ &dma1Dest,		  sizeof(u32)				 },
  32.473 +	{ &dma2Source,		  sizeof(u32)				 },
  32.474 +	{ &dma2Dest,		  sizeof(u32)				 },
  32.475 +	{ &dma3Source,		  sizeof(u32)				 },
  32.476 +	{ &dma3Dest,		  sizeof(u32)				 },
  32.477 +	{ &fxOn,			  sizeof(bool8)				 },
  32.478 +	{ &windowOn,		  sizeof(bool8)				 },
  32.479 +	{ &N_FLAG,			  sizeof(bool8)				 },
  32.480 +	{ &C_FLAG,			  sizeof(bool8)				 },
  32.481 +	{ &Z_FLAG,			  sizeof(bool8)				 },
  32.482 +	{ &V_FLAG,			  sizeof(bool8)				 },
  32.483 +	{ &armState,		  sizeof(bool8)				 },
  32.484 +	{ &armIrqEnable,	  sizeof(bool8)				 },
  32.485 +	{ &armNextPC,		  sizeof(u32)				 },
  32.486 +	{ &armMode,			  sizeof(int32)				 },
  32.487 +	{ &saveType,		  sizeof(int32)				 },
  32.488 +	{ NULL,				  0							 }
  32.489 +};
  32.490 +
  32.491 +//int cpuLoopTicks = 0;
  32.492 +int cpuSavedTicks = 0;
  32.493 +
  32.494 +#ifdef PROFILING
  32.495 +void cpuProfil(char *buf, int size, u32 lowPC, int scale)
  32.496 +{
  32.497 +	profilBuffer = buf;
  32.498 +	profilSize	 = size;
  32.499 +	profilLowPC	 = lowPC;
  32.500 +	profilScale	 = scale;
  32.501 +}
  32.502 +
  32.503 +void cpuEnableProfiling(int hz)
  32.504 +{
  32.505 +	if (hz == 0)
  32.506 +		hz = 100;
  32.507 +	profilingTicks = profilingTicksReload = 16777216 / hz;
  32.508 +	profSetHertz(hz);
  32.509 +}
  32.510 +
  32.511 +#endif
  32.512 +
  32.513 +inline int CPUUpdateTicksAccess32(u32 address)
  32.514 +{
  32.515 +	return memoryWait32[(address >> 24) & 15];
  32.516 +}
  32.517 +
  32.518 +inline int CPUUpdateTicksAccess16(u32 address)
  32.519 +{
  32.520 +	return memoryWait[(address >> 24) & 15];
  32.521 +}
  32.522 +
  32.523 +inline int CPUUpdateTicksAccessSeq32(u32 address)
  32.524 +{
  32.525 +	return memoryWaitSeq32[(address >> 24) & 15];
  32.526 +}
  32.527 +
  32.528 +inline int CPUUpdateTicksAccessSeq16(u32 address)
  32.529 +{
  32.530 +	return memoryWaitSeq[(address >> 24) & 15];
  32.531 +}
  32.532 +
  32.533 +inline int CPUUpdateTicks()
  32.534 +{
  32.535 +	int cpuLoopTicks = lcdTicks;
  32.536 +
  32.537 +	if (soundTicks < cpuLoopTicks)
  32.538 +		cpuLoopTicks = soundTicks;
  32.539 +
  32.540 +	if (timer0On && !(TM0CNT & 4) && (timer0Ticks < cpuLoopTicks))
  32.541 +	{
  32.542 +		cpuLoopTicks = timer0Ticks;
  32.543 +	}
  32.544 +	if (timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks))
  32.545 +	{
  32.546 +		cpuLoopTicks = timer1Ticks;
  32.547 +	}
  32.548 +	if (timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks))
  32.549 +	{
  32.550 +		cpuLoopTicks = timer2Ticks;
  32.551 +	}
  32.552 +	if (timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks))
  32.553 +	{
  32.554 +		cpuLoopTicks = timer3Ticks;
  32.555 +	}
  32.556 +#ifdef PROFILING
  32.557 +	if (profilingTicksReload != 0)
  32.558 +	{
  32.559 +		if (profilingTicks < cpuLoopTicks)
  32.560 +		{
  32.561 +			cpuLoopTicks = profilingTicks;
  32.562 +		}
  32.563 +	}
  32.564 +#endif
  32.565 +	cpuSavedTicks = cpuLoopTicks;
  32.566 +	return cpuLoopTicks;
  32.567 +}
  32.568 +
  32.569 +void CPUUpdateWindow0()
  32.570 +{
  32.571 +	int x00 = WIN0H >> 8;
  32.572 +	int x01 = WIN0H & 255;
  32.573 +
  32.574 +	if (x00 <= x01)
  32.575 +	{
  32.576 +		for (int i = 0; i < 240; i++)
  32.577 +		{
  32.578 +			gfxInWin0[i] = (i >= x00 && i < x01);
  32.579 +		}
  32.580 +	}
  32.581 +	else
  32.582 +	{
  32.583 +		for (int i = 0; i < 240; i++)
  32.584 +		{
  32.585 +			gfxInWin0[i] = (i >= x00 || i < x01);
  32.586 +		}
  32.587 +	}
  32.588 +}
  32.589 +
  32.590 +void CPUUpdateWindow1()
  32.591 +{
  32.592 +	int x00 = WIN1H >> 8;
  32.593 +	int x01 = WIN1H & 255;
  32.594 +
  32.595 +	if (x00 <= x01)
  32.596 +	{
  32.597 +		for (int i = 0; i < 240; i++)
  32.598 +		{
  32.599 +			gfxInWin1[i] = (i >= x00 && i < x01);
  32.600 +		}
  32.601 +	}
  32.602 +	else
  32.603 +	{
  32.604 +		for (int i = 0; i < 240; i++)
  32.605 +		{
  32.606 +			gfxInWin1[i] = (i >= x00 || i < x01);
  32.607 +		}
  32.608 +	}
  32.609 +}
  32.610 +
  32.611 +#define CLEAR_ARRAY(a) \
  32.612 +	{ \
  32.613 +		u32 *array = (a); \
  32.614 +		for (int i = 0; i < 240; i++) { \
  32.615 +			*array++ = 0x80000000; \
  32.616 +		} \
  32.617 +	} \
  32.618 +
  32.619 +void CPUUpdateRenderBuffers(bool force)
  32.620 +{
  32.621 +	if (!(layerEnable & 0x0100) || force)
  32.622 +	{
  32.623 +		CLEAR_ARRAY(line0);
  32.624 +	}
  32.625 +	if (!(layerEnable & 0x0200) || force)
  32.626 +	{
  32.627 +		CLEAR_ARRAY(line1);
  32.628 +	}
  32.629 +	if (!(layerEnable & 0x0400) || force)
  32.630 +	{
  32.631 +		CLEAR_ARRAY(line2);
  32.632 +	}
  32.633 +	if (!(layerEnable & 0x0800) || force)
  32.634 +	{
  32.635 +		CLEAR_ARRAY(line3);
  32.636 +	}
  32.637 +}
  32.638 +
  32.639 +bool CPUWriteStateToStream(gzFile gzFile)
  32.640 +{
  32.641 +	utilWriteInt(gzFile, SAVE_GAME_VERSION);
  32.642 +
  32.643 +	utilGzWrite(gzFile, &rom[0xa0], 16);
  32.644 +
  32.645 +	utilWriteInt(gzFile, useBios);
  32.646 +
  32.647 +	utilGzWrite(gzFile, &reg[0], sizeof(reg));
  32.648 +
  32.649 +	utilWriteData(gzFile, saveGameStruct);
  32.650 +
  32.651 +	// new to version 0.7.1
  32.652 +	utilWriteInt(gzFile, stopState);
  32.653 +	// new to version 0.8
  32.654 +	utilWriteInt(gzFile, intState);
  32.655 +
  32.656 +	utilGzWrite(gzFile, internalRAM, 0x8000);
  32.657 +	utilGzWrite(gzFile, paletteRAM, 0x400);
  32.658 +	utilGzWrite(gzFile, workRAM, 0x40000);
  32.659 +	utilGzWrite(gzFile, vram, 0x20000);
  32.660 +	utilGzWrite(gzFile, oam, 0x400);
  32.661 +	utilGzWrite(gzFile, pix, 4 * 241 * 162);
  32.662 +	utilGzWrite(gzFile, ioMem, 0x400);
  32.663 +
  32.664 +	eepromSaveGame(gzFile);
  32.665 +	flashSaveGame(gzFile);
  32.666 +	soundSaveGame(gzFile);
  32.667 +
  32.668 +	cheatsSaveGame(gzFile);
  32.669 +
  32.670 +	// version 1.5
  32.671 +	rtcSaveGame(gzFile);
  32.672 +
  32.673 +	// SAVE_GAME_VERSION_9 (new to re-recording version which is based on 1.72)
  32.674 +	{
  32.675 +		extern int32 sensorX, sensorY; // from SDL.cpp
  32.676 +		utilGzWrite(gzFile, &sensorX, sizeof(sensorX));
  32.677 +		utilGzWrite(gzFile, &sensorY, sizeof(sensorY));
  32.678 +		bool8 movieActive = VBAMovieActive();
  32.679 +		utilGzWrite(gzFile, &movieActive, sizeof(movieActive));
  32.680 +		if (movieActive)
  32.681 +		{
  32.682 +			uint8 *movie_freeze_buf	 = NULL;
  32.683 +			uint32 movie_freeze_size = 0;
  32.684 +
  32.685 +			VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size);
  32.686 +			if (movie_freeze_buf)
  32.687 +			{
  32.688 +				utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size));
  32.689 +				utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size);
  32.690 +				delete [] movie_freeze_buf;
  32.691 +			}
  32.692 +			else
  32.693 +			{
  32.694 +				systemMessage(0, N_("Failed to save movie snapshot."));
  32.695 +				return false;
  32.696 +			}
  32.697 +		}
  32.698 +		utilGzWrite(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount));
  32.699 +	}
  32.700 +
  32.701 +	// SAVE_GAME_VERSION_10
  32.702 +	{
  32.703 +		utilGzWrite(gzFile, memoryWait, 16 * sizeof(int32));
  32.704 +		utilGzWrite(gzFile, memoryWait32, 16 * sizeof(int32));
  32.705 +		utilGzWrite(gzFile, memoryWaitSeq, 16 * sizeof(int32));
  32.706 +		utilGzWrite(gzFile, memoryWaitSeq32, 16 * sizeof(int32));
  32.707 +		utilGzWrite(gzFile, memoryWaitFetch, 16 * sizeof(int32));
  32.708 +		utilGzWrite(gzFile, memoryWaitFetch32, 16 * sizeof(int32));
  32.709 +	}
  32.710 +
  32.711 +	// SAVE_GAME_VERSION_11
  32.712 +	{
  32.713 +		utilGzWrite(gzFile, &prefetchActive, sizeof(bool8));
  32.714 +		utilGzWrite(gzFile, &prefetchPrevActive, sizeof(bool8));
  32.715 +		utilGzWrite(gzFile, &prefetchApplies, sizeof(bool8));
  32.716 +	}
  32.717 +
  32.718 +	// SAVE_GAME_VERSION_12
  32.719 +	{
  32.720 +		utilGzWrite(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary
  32.721 +		utilGzWrite(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used...
  32.722 +	}
  32.723 +
  32.724 +	// SAVE_GAME_VERSION_13
  32.725 +	{
  32.726 +		utilGzWrite(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount));
  32.727 +		utilGzWrite(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged));
  32.728 +		utilGzWrite(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast));
  32.729 +	}
  32.730 +
  32.731 +	return true;
  32.732 +}
  32.733 +
  32.734 +bool CPUWriteState(const char *file)
  32.735 +{
  32.736 +	gzFile gzFile = utilGzOpen(file, "wb");
  32.737 +
  32.738 +	if (gzFile == NULL)
  32.739 +	{
  32.740 +		systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file);
  32.741 +		return false;
  32.742 +	}
  32.743 +
  32.744 +	bool res = CPUWriteStateToStream(gzFile);
  32.745 +
  32.746 +	utilGzClose(gzFile);
  32.747 +
  32.748 +	return res;
  32.749 +}
  32.750 +
  32.751 +bool CPUWriteMemState(char *memory, int available)
  32.752 +{
  32.753 +	gzFile gzFile = utilMemGzOpen(memory, available, "w");
  32.754 +
  32.755 +	if (gzFile == NULL)
  32.756 +	{
  32.757 +		return false;
  32.758 +	}
  32.759 +
  32.760 +	bool res = CPUWriteStateToStream(gzFile);
  32.761 +
  32.762 +	long pos = utilGzTell(gzFile) + 8;
  32.763 +
  32.764 +	if (pos >= (available))
  32.765 +		res = false;
  32.766 +
  32.767 +	utilGzClose(gzFile);
  32.768 +
  32.769 +	return res;
  32.770 +}
  32.771 +
  32.772 +static int	tempStateID	  = 0;
  32.773 +static int	tempFailCount = 0;
  32.774 +static bool backupSafe	  = true;
  32.775 +
  32.776 +bool CPUReadStateFromStream(gzFile gzFile)
  32.777 +{
  32.778 +	bool8 ub;
  32.779 +	char  tempBackupName [128];
  32.780 +	if (backupSafe)
  32.781 +	{
  32.782 +		sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++);
  32.783 +		CPUWriteState(tempBackupName);
  32.784 +	}
  32.785 +
  32.786 +	int version = utilReadInt(gzFile);
  32.787 +
  32.788 +	if (version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1)
  32.789 +	{
  32.790 +		systemMessage(MSG_UNSUPPORTED_VBA_SGM,
  32.791 +		              N_("Unsupported VisualBoyAdvance save game version %d"),
  32.792 +		              version);
  32.793 +		goto failedLoad;
  32.794 +	}
  32.795 +
  32.796 +	u8 romname[17];
  32.797 +
  32.798 +	utilGzRead(gzFile, romname, 16);
  32.799 +
  32.800 +	if (memcmp(&rom[0xa0], romname, 16) != 0)
  32.801 +	{
  32.802 +		romname[16] = 0;
  32.803 +		for (int i = 0; i < 16; i++)
  32.804 +			if (romname[i] < 32)
  32.805 +				romname[i] = 32;
  32.806 +		systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname);
  32.807 +		goto failedLoad;
  32.808 +	}
  32.809 +
  32.810 +	ub = utilReadInt(gzFile) ? true : false;
  32.811 +
  32.812 +	if (ub != useBios)
  32.813 +	{
  32.814 +		if (useBios)
  32.815 +			systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS,
  32.816 +			              N_("Save game is not using the BIOS files"));
  32.817 +		else
  32.818 +			systemMessage(MSG_SAVE_GAME_USING_BIOS,
  32.819 +			              N_("Save game is using the BIOS file"));
  32.820 +		goto failedLoad;
  32.821 +	}
  32.822 +
  32.823 +	utilGzRead(gzFile, &reg[0], sizeof(reg));
  32.824 +
  32.825 +	utilReadData(gzFile, saveGameStruct);
  32.826 +
  32.827 +	if (version < SAVE_GAME_VERSION_3)
  32.828 +		stopState = false;
  32.829 +	else
  32.830 +		stopState = utilReadInt(gzFile) ? true : false;
  32.831 +
  32.832 +	if (version < SAVE_GAME_VERSION_4)
  32.833 +		intState = false;
  32.834 +	else
  32.835 +		intState = utilReadInt(gzFile) ? true : false;
  32.836 +
  32.837 +	utilGzRead(gzFile, internalRAM, 0x8000);
  32.838 +	utilGzRead(gzFile, paletteRAM, 0x400);
  32.839 +	utilGzRead(gzFile, workRAM, 0x40000);
  32.840 +	utilGzRead(gzFile, vram, 0x20000);
  32.841 +	utilGzRead(gzFile, oam, 0x400);
  32.842 +	if (version < SAVE_GAME_VERSION_6)
  32.843 +		utilGzRead(gzFile, pix, 4 * 240 * 160);
  32.844 +	else
  32.845 +		utilGzRead(gzFile, pix, 4 * 241 * 162);
  32.846 +	utilGzRead(gzFile, ioMem, 0x400);
  32.847 +
  32.848 +	eepromReadGame(gzFile, version);
  32.849 +	flashReadGame(gzFile, version);
  32.850 +	soundReadGame(gzFile, version);
  32.851 +
  32.852 +	if (version > SAVE_GAME_VERSION_1)
  32.853 +	{
  32.854 +		cheatsReadGame(gzFile);
  32.855 +	}
  32.856 +	if (version > SAVE_GAME_VERSION_6)
  32.857 +	{
  32.858 +		rtcReadGame(gzFile);
  32.859 +	}
  32.860 +
  32.861 +	if (version <= SAVE_GAME_VERSION_7)
  32.862 +	{
  32.863 +		u32 temp;
  32.864 +#define SWAP(a, b, c) \
  32.865 +	temp = (a); \
  32.866 +	(a)	 = (b) << 16 | (c); \
  32.867 +	(b)	 = (temp) >> 16; \
  32.868 +	(c)	 = (temp) & 0xFFFF;
  32.869 +
  32.870 +		SWAP(dma0Source, DM0SAD_H, DM0SAD_L);
  32.871 +		SWAP(dma0Dest,   DM0DAD_H, DM0DAD_L);
  32.872 +		SWAP(dma1Source, DM1SAD_H, DM1SAD_L);
  32.873 +		SWAP(dma1Dest,   DM1DAD_H, DM1DAD_L);
  32.874 +		SWAP(dma2Source, DM2SAD_H, DM2SAD_L);
  32.875 +		SWAP(dma2Dest,   DM2DAD_H, DM2DAD_L);
  32.876 +		SWAP(dma3Source, DM3SAD_H, DM3SAD_L);
  32.877 +		SWAP(dma3Dest,   DM3DAD_H, DM3DAD_L);
  32.878 +	}
  32.879 +
  32.880 +	// set pointers!
  32.881 +	layerEnable = layerSettings & DISPCNT;
  32.882 +
  32.883 +	CPUUpdateRender();
  32.884 +	CPUUpdateRenderBuffers(true);
  32.885 +	CPUUpdateWindow0();
  32.886 +	CPUUpdateWindow1();
  32.887 +	gbaSaveType = 0;
  32.888 +	switch (saveType)
  32.889 +	{
  32.890 +	case 0:
  32.891 +		cpuSaveGameFunc = flashSaveDecide;
  32.892 +		break;
  32.893 +	case 1:
  32.894 +		cpuSaveGameFunc = sramWrite;
  32.895 +		gbaSaveType		= 1;
  32.896 +		break;
  32.897 +	case 2:
  32.898 +		cpuSaveGameFunc = flashWrite;
  32.899 +		gbaSaveType		= 2;
  32.900 +		break;
  32.901 +	default:
  32.902 +		systemMessage(MSG_UNSUPPORTED_SAVE_TYPE,
  32.903 +		              N_("Unsupported save type %d"), saveType);
  32.904 +		break;
  32.905 +	}
  32.906 +	if (eepromInUse)
  32.907 +		gbaSaveType = 3;
  32.908 +
  32.909 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  32.910 +
  32.911 +	if (version >= SAVE_GAME_VERSION_9) // new to re-recording version:
  32.912 +	{
  32.913 +		extern int32 sensorX, sensorY; // from SDL.cpp
  32.914 +		utilGzRead(gzFile, &sensorX, sizeof(sensorX));
  32.915 +		utilGzRead(gzFile, &sensorY, sizeof(sensorY));
  32.916 +
  32.917 +		bool8 movieSnapshot;
  32.918 +		utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot));
  32.919 +		if (VBAMovieActive() && !movieSnapshot)
  32.920 +		{
  32.921 +			systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active."));
  32.922 +			goto failedLoad;
  32.923 +		}
  32.924 +
  32.925 +		if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added
  32.926 +		                   // later on in the save format
  32.927 +		{
  32.928 +			uint32 movieInputDataSize = 0;
  32.929 +			utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize));
  32.930 +			uint8 *local_movie_data = new uint8[movieInputDataSize];
  32.931 +			int	   readBytes		= utilGzRead(gzFile, local_movie_data, movieInputDataSize);
  32.932 +			if (readBytes != movieInputDataSize)
  32.933 +			{
  32.934 +				systemMessage(0, N_("Corrupt movie snapshot."));
  32.935 +				if (local_movie_data)
  32.936 +					delete [] local_movie_data;
  32.937 +				goto failedLoad;
  32.938 +			}
  32.939 +			int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize);
  32.940 +			if (local_movie_data)
  32.941 +				delete [] local_movie_data;
  32.942 +			if (code != MOVIE_SUCCESS && VBAMovieActive())
  32.943 +			{
  32.944 +				char errStr [1024];
  32.945 +				strcpy(errStr, "Failed to load movie snapshot");
  32.946 +				switch (code)
  32.947 +				{
  32.948 +				case MOVIE_NOT_FROM_THIS_MOVIE:
  32.949 +					strcat(errStr, ";\nSnapshot not from this movie"); break;
  32.950 +				case MOVIE_NOT_FROM_A_MOVIE:
  32.951 +					strcat(errStr, ";\nNot a movie snapshot"); break;                   // shouldn't get here...
  32.952 +				case MOVIE_SNAPSHOT_INCONSISTENT:
  32.953 +					strcat(errStr, ";\nSnapshot inconsistent with movie"); break;
  32.954 +				case MOVIE_WRONG_FORMAT:
  32.955 +					strcat(errStr, ";\nWrong format"); break;
  32.956 +				}
  32.957 +				strcat(errStr, ".");
  32.958 +				systemMessage(0, N_(errStr));
  32.959 +				goto failedLoad;
  32.960 +			}
  32.961 +		}
  32.962 +		utilGzRead(gzFile, &GBASystemCounters.frameCount, sizeof(GBASystemCounters.frameCount));
  32.963 +	}
  32.964 +	if (version >= SAVE_GAME_VERSION_10)
  32.965 +	{
  32.966 +		utilGzRead(gzFile, memoryWait, 16 * sizeof(int32));
  32.967 +		utilGzRead(gzFile, memoryWait32, 16 * sizeof(int32));
  32.968 +		utilGzRead(gzFile, memoryWaitSeq, 16 * sizeof(int32));
  32.969 +		utilGzRead(gzFile, memoryWaitSeq32, 16 * sizeof(int32));
  32.970 +		utilGzRead(gzFile, memoryWaitFetch, 16 * sizeof(int32));
  32.971 +		utilGzRead(gzFile, memoryWaitFetch32, 16 * sizeof(int32));
  32.972 +	}
  32.973 +	if (version >= SAVE_GAME_VERSION_11)
  32.974 +	{
  32.975 +		utilGzRead(gzFile, &prefetchActive, sizeof(bool8));
  32.976 +		//if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
  32.977 +		//if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
  32.978 +		utilGzRead(gzFile, &prefetchPrevActive, sizeof(bool8));
  32.979 +		utilGzRead(gzFile, &prefetchApplies, sizeof(bool8));
  32.980 +	}
  32.981 +	if (version >= SAVE_GAME_VERSION_12)
  32.982 +	{
  32.983 +		utilGzRead(gzFile, &memLagTempEnabled, sizeof(bool8)); // necessary
  32.984 +		utilGzRead(gzFile, &speedHack, sizeof(bool8)); // just in case it's ever used...
  32.985 +	}
  32.986 +	if (version >= SAVE_GAME_VERSION_13)
  32.987 +	{
  32.988 +		utilGzRead(gzFile, &GBASystemCounters.lagCount, sizeof(GBASystemCounters.lagCount));
  32.989 +		utilGzRead(gzFile, &GBASystemCounters.lagged, sizeof(GBASystemCounters.lagged));
  32.990 +		utilGzRead(gzFile, &GBASystemCounters.laggedLast, sizeof(GBASystemCounters.laggedLast));
  32.991 +	}
  32.992 +
  32.993 +	if (backupSafe)
  32.994 +	{
  32.995 +		remove(tempBackupName);
  32.996 +		tempFailCount = 0;
  32.997 +	}
  32.998 +	systemSetJoypad(0, ~P1 & 0x3FF);
  32.999 +	VBAUpdateButtonPressDisplay();
 32.1000 +	VBAUpdateFrameCountDisplay();
 32.1001 +	systemRefreshScreen();
 32.1002 +	return true;
 32.1003 +
 32.1004 +failedLoad:
 32.1005 +	if (backupSafe)
 32.1006 +	{
 32.1007 +		tempFailCount++;
 32.1008 +		if (tempFailCount < 3) // fail no more than 2 times in a row
 32.1009 +			CPUReadState(tempBackupName);
 32.1010 +		remove(tempBackupName);
 32.1011 +	}
 32.1012 +	return false;
 32.1013 +}
 32.1014 +
 32.1015 +bool CPUReadMemState(char *memory, int available)
 32.1016 +{
 32.1017 +	gzFile gzFile = utilMemGzOpen(memory, available, "r");
 32.1018 +
 32.1019 +	backupSafe = false;
 32.1020 +	bool res = CPUReadStateFromStream(gzFile);
 32.1021 +	backupSafe = true;
 32.1022 +
 32.1023 +	utilGzClose(gzFile);
 32.1024 +
 32.1025 +	return res;
 32.1026 +}
 32.1027 +
 32.1028 +bool CPUReadState(const char *file)
 32.1029 +{
 32.1030 +	gzFile gzFile = utilGzOpen(file, "rb");
 32.1031 +
 32.1032 +	if (gzFile == NULL)
 32.1033 +		return false;
 32.1034 +
 32.1035 +	bool res = CPUReadStateFromStream(gzFile);
 32.1036 +
 32.1037 +	utilGzClose(gzFile);
 32.1038 +
 32.1039 +	return res;
 32.1040 +}
 32.1041 +
 32.1042 +bool CPUExportEepromFile(const char *fileName)
 32.1043 +{
 32.1044 +	if (eepromInUse)
 32.1045 +	{
 32.1046 +		FILE *file = fopen(fileName, "wb");
 32.1047 +
 32.1048 +		if (!file)
 32.1049 +		{
 32.1050 +			systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
 32.1051 +			              fileName);
 32.1052 +			return false;
 32.1053 +		}
 32.1054 +
 32.1055 +		for (int i = 0; i < eepromSize; )
 32.1056 +		{
 32.1057 +			for (int j = 0; j < 8; j++)
 32.1058 +			{
 32.1059 +				if (fwrite(&eepromData[i + 7 - j], 1, 1, file) != 1)
 32.1060 +				{
 32.1061 +					fclose(file);
 32.1062 +					return false;
 32.1063 +				}
 32.1064 +			}
 32.1065 +			i += 8;
 32.1066 +		}
 32.1067 +		fclose(file);
 32.1068 +	}
 32.1069 +	return true;
 32.1070 +}
 32.1071 +
 32.1072 +bool CPUWriteBatteryToStream(gzFile gzFile)
 32.1073 +{
 32.1074 +	if (!gzFile)
 32.1075 +		return false;
 32.1076 +
 32.1077 +	utilWriteInt(gzFile, SAVE_GAME_VERSION);
 32.1078 +
 32.1079 +	// for simplicity, we put both types of battery files should be in the stream, even if one's empty
 32.1080 +	eepromSaveGame(gzFile);
 32.1081 +	flashSaveGame(gzFile);
 32.1082 +
 32.1083 +	return true;
 32.1084 +}
 32.1085 +
 32.1086 +bool CPUWriteBatteryFile(const char *fileName)
 32.1087 +{
 32.1088 +	if (gbaSaveType == 0)
 32.1089 +	{
 32.1090 +		if (eepromInUse)
 32.1091 +			gbaSaveType = 3;
 32.1092 +		else
 32.1093 +			switch (saveType)
 32.1094 +			{
 32.1095 +			case 1:
 32.1096 +				gbaSaveType = 1;
 32.1097 +				break;
 32.1098 +			case 2:
 32.1099 +				gbaSaveType = 2;
 32.1100 +				break;
 32.1101 +			}
 32.1102 +	}
 32.1103 +
 32.1104 +	if (gbaSaveType)
 32.1105 +	{
 32.1106 +		FILE *file = fopen(fileName, "wb");
 32.1107 +
 32.1108 +		if (!file)
 32.1109 +		{
 32.1110 +			systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
 32.1111 +			              fileName);
 32.1112 +			return false;
 32.1113 +		}
 32.1114 +
 32.1115 +		// only save if Flash/Sram in use or EEprom in use
 32.1116 +		if (gbaSaveType != 3)
 32.1117 +		{
 32.1118 +			if (gbaSaveType == 2)
 32.1119 +			{
 32.1120 +				if (fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize)
 32.1121 +				{
 32.1122 +					fclose(file);
 32.1123 +					return false;
 32.1124 +				}
 32.1125 +			}
 32.1126 +			else
 32.1127 +			{
 32.1128 +				if (fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000)
 32.1129 +				{
 32.1130 +					fclose(file);
 32.1131 +					return false;
 32.1132 +				}
 32.1133 +			}
 32.1134 +		}
 32.1135 +		else
 32.1136 +		{
 32.1137 +			if (fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize)
 32.1138 +			{
 32.1139 +				fclose(file);
 32.1140 +				return false;
 32.1141 +			}
 32.1142 +		}
 32.1143 +		fclose(file);
 32.1144 +	}
 32.1145 +
 32.1146 +	return true;
 32.1147 +}
 32.1148 +
 32.1149 +bool CPUReadGSASnapshot(const char *fileName)
 32.1150 +{
 32.1151 +	int	  i;
 32.1152 +	FILE *file = fopen(fileName, "rb");
 32.1153 +
 32.1154 +	if (!file)
 32.1155 +	{
 32.1156 +		systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
 32.1157 +		return false;
 32.1158 +	}
 32.1159 +
 32.1160 +	// check file size to know what we should read
 32.1161 +	fseek(file, 0, SEEK_END);
 32.1162 +
 32.1163 +	// long size = ftell(file);
 32.1164 +	fseek(file, 0x0, SEEK_SET);
 32.1165 +	fread(&i, 1, 4, file);
 32.1166 +	fseek(file, i, SEEK_CUR); // Skip SharkPortSave
 32.1167 +	fseek(file, 4, SEEK_CUR); // skip some sort of flag
 32.1168 +	fread(&i, 1, 4, file); // name length
 32.1169 +	fseek(file, i, SEEK_CUR); // skip name
 32.1170 +	fread(&i, 1, 4, file); // desc length
 32.1171 +	fseek(file, i, SEEK_CUR); // skip desc
 32.1172 +	fread(&i, 1, 4, file); // notes length
 32.1173 +	fseek(file, i, SEEK_CUR); // skip notes
 32.1174 +	int saveSize;
 32.1175 +	fread(&saveSize, 1, 4, file); // read length
 32.1176 +	saveSize -= 0x1c; // remove header size
 32.1177 +	char buffer[17];
 32.1178 +	char buffer2[17];
 32.1179 +	fread(buffer, 1, 16, file);
 32.1180 +	buffer[16] = 0;
 32.1181 +	for (i = 0; i < 16; i++)
 32.1182 +		if (buffer[i] < 32)
 32.1183 +			buffer[i] = 32;
 32.1184 +	memcpy(buffer2, &rom[0xa0], 16);
 32.1185 +	buffer2[16] = 0;
 32.1186 +	for (i = 0; i < 16; i++)
 32.1187 +		if (buffer2[i] < 32)
 32.1188 +			buffer2[i] = 32;
 32.1189 +	if (memcmp(buffer, buffer2, 16))
 32.1190 +	{
 32.1191 +		systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR,
 32.1192 +		              N_("Cannot import snapshot for %s. Current game is %s"),
 32.1193 +		              buffer,
 32.1194 +		              buffer2);
 32.1195 +		fclose(file);
 32.1196 +		return false;
 32.1197 +	}
 32.1198 +	fseek(file, 12, SEEK_CUR); // skip some flags
 32.1199 +	if (saveSize >= 65536)
 32.1200 +	{
 32.1201 +		if (fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize)
 32.1202 +		{
 32.1203 +			fclose(file);
 32.1204 +			return false;
 32.1205 +		}
 32.1206 +	}
 32.1207 +	else
 32.1208 +	{
 32.1209 +		systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE,
 32.1210 +		              N_("Unsupported snapshot file %s"),
 32.1211 +		              fileName);
 32.1212 +		fclose(file);
 32.1213 +		return false;
 32.1214 +	}
 32.1215 +	fclose(file);
 32.1216 +	CPUReset();
 32.1217 +	return true;
 32.1218 +}
 32.1219 +
 32.1220 +bool CPUWriteGSASnapshot(const char *fileName,
 32.1221 +                         const char *title,
 32.1222 +                         const char *desc,
 32.1223 +                         const char *notes)
 32.1224 +{
 32.1225 +	FILE *file = fopen(fileName, "wb");
 32.1226 +
 32.1227 +	if (!file)
 32.1228 +	{
 32.1229 +		systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
 32.1230 +		return false;
 32.1231 +	}
 32.1232 +
 32.1233 +	u8 buffer[17];
 32.1234 +
 32.1235 +	utilPutDword(buffer, 0x0d); // SharkPortSave length
 32.1236 +	fwrite(buffer, 1, 4, file);
 32.1237 +	fwrite("SharkPortSave", 1, 0x0d, file);
 32.1238 +	utilPutDword(buffer, 0x000f0000);
 32.1239 +	fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save
 32.1240 +	utilPutDword(buffer, strlen(title));
 32.1241 +	fwrite(buffer, 1, 4, file); // title length
 32.1242 +	fwrite(title, 1, strlen(title), file);
 32.1243 +	utilPutDword(buffer, strlen(desc));
 32.1244 +	fwrite(buffer, 1, 4, file); // desc length
 32.1245 +	fwrite(desc, 1, strlen(desc), file);
 32.1246 +	utilPutDword(buffer, strlen(notes));
 32.1247 +	fwrite(buffer, 1, 4, file); // notes length
 32.1248 +	fwrite(notes, 1, strlen(notes), file);
 32.1249 +	int saveSize = 0x10000;
 32.1250 +	if (gbaSaveType == 2)
 32.1251 +		saveSize = flashSize;
 32.1252 +	int totalSize = saveSize + 0x1c;
 32.1253 +
 32.1254 +	utilPutDword(buffer, totalSize); // length of remainder of save - CRC
 32.1255 +	fwrite(buffer, 1, 4, file);
 32.1256 +
 32.1257 +	char temp[0x2001c];
 32.1258 +	memset(temp, 0, 28);
 32.1259 +	memcpy(temp, &rom[0xa0], 16); // copy internal name
 32.1260 +	temp[0x10] = rom[0xbe]; // reserved area (old checksum)
 32.1261 +	temp[0x11] = rom[0xbf]; // reserved area (old checksum)
 32.1262 +	temp[0x12] = rom[0xbd]; // complement check
 32.1263 +	temp[0x13] = rom[0xb0]; // maker
 32.1264 +	temp[0x14] = 1; // 1 save ?
 32.1265 +	memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save
 32.1266 +	fwrite(temp, 1, totalSize, file); // write save + header
 32.1267 +	u32 crc = 0;
 32.1268 +
 32.1269 +	for (int i = 0; i < totalSize; i++)
 32.1270 +	{
 32.1271 +		crc += ((u32)temp[i] << (crc % 0x18));
 32.1272 +	}
 32.1273 +
 32.1274 +	utilPutDword(buffer, crc);
 32.1275 +	fwrite(buffer, 1, 4, file); // CRC?
 32.1276 +
 32.1277 +	fclose(file);
 32.1278 +	return true;
 32.1279 +}
 32.1280 +
 32.1281 +bool CPUImportEepromFile(const char *fileName)
 32.1282 +{
 32.1283 +	FILE *file = fopen(fileName, "rb");
 32.1284 +
 32.1285 +	if (!file)
 32.1286 +		return false;
 32.1287 +
 32.1288 +	// check file size to know what we should read
 32.1289 +	fseek(file, 0, SEEK_END);
 32.1290 +
 32.1291 +	long size = ftell(file);
 32.1292 +	fseek(file, 0, SEEK_SET);
 32.1293 +	if (size == 512 || size == 0x2000)
 32.1294 +	{
 32.1295 +		if (fread(eepromData, 1, size, file) != (size_t)size)
 32.1296 +		{
 32.1297 +			fclose(file);
 32.1298 +			return false;
 32.1299 +		}
 32.1300 +		for (int i = 0; i < size; )
 32.1301 +		{
 32.1302 +			u8 tmp = eepromData[i];
 32.1303 +			eepromData[i]	  = eepromData[7 - i];
 32.1304 +			eepromData[7 - i] = tmp;
 32.1305 +			i++;
 32.1306 +			tmp = eepromData[i];
 32.1307 +			eepromData[i]	  = eepromData[7 - i];
 32.1308 +			eepromData[7 - i] = tmp;
 32.1309 +			i++;
 32.1310 +			tmp = eepromData[i];
 32.1311 +			eepromData[i]	  = eepromData[7 - i];
 32.1312 +			eepromData[7 - i] = tmp;
 32.1313 +			i++;
 32.1314 +			tmp = eepromData[i];
 32.1315 +			eepromData[i]	  = eepromData[7 - i];
 32.1316 +			eepromData[7 - i] = tmp;
 32.1317 +			i++;
 32.1318 +			i += 4;
 32.1319 +		}
 32.1320 +	}
 32.1321 +	else
 32.1322 +	{
 32.1323 +		fclose(file);
 32.1324 +		return false;
 32.1325 +	}
 32.1326 +	fclose(file);
 32.1327 +	return true;
 32.1328 +}
 32.1329 +
 32.1330 +bool CPUReadBatteryFromStream(gzFile gzFile)
 32.1331 +{
 32.1332 +	if (!gzFile)
 32.1333 +		return false;
 32.1334 +
 32.1335 +	int version = utilReadInt(gzFile);
 32.1336 +
 32.1337 +	// for simplicity, we put both types of battery files should be in the stream, even if one's empty
 32.1338 +	eepromReadGame(gzFile, version);
 32.1339 +	flashReadGame(gzFile, version);
 32.1340 +
 32.1341 +	return true;
 32.1342 +}
 32.1343 +
 32.1344 +bool CPUReadBatteryFile(const char *fileName)
 32.1345 +{
 32.1346 +	FILE *file = fopen(fileName, "rb");
 32.1347 +
 32.1348 +	if (!file)
 32.1349 +		return false;
 32.1350 +
 32.1351 +	// check file size to know what we should read
 32.1352 +	fseek(file, 0, SEEK_END);
 32.1353 +
 32.1354 +	long size = ftell(file);
 32.1355 +	fseek(file, 0, SEEK_SET);
 32.1356 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
 32.1357 +
 32.1358 +	if (size == 512 || size == 0x2000)
 32.1359 +	{
 32.1360 +		if (fread(eepromData, 1, size, file) != (size_t)size)
 32.1361 +		{
 32.1362 +			fclose(file);
 32.1363 +			return false;
 32.1364 +		}
 32.1365 +	}
 32.1366 +	else
 32.1367 +	{
 32.1368 +		if (size == 0x20000)
 32.1369 +		{
 32.1370 +			if (fread(flashSaveMemory, 1, 0x20000, file) != 0x20000)
 32.1371 +			{
 32.1372 +				fclose(file);
 32.1373 +				return false;
 32.1374 +			}
 32.1375 +			flashSetSize(0x20000);
 32.1376 +		}
 32.1377 +		else
 32.1378 +		{
 32.1379 +			if (fread(flashSaveMemory, 1, 0x10000, file) != 0x10000)
 32.1380 +			{
 32.1381 +				fclose(file);
 32.1382 +				return false;
 32.1383 +			}
 32.1384 +			flashSetSize(0x10000);
 32.1385 +		}
 32.1386 +	}
 32.1387 +	fclose(file);
 32.1388 +	return true;
 32.1389 +}
 32.1390 +
 32.1391 +bool CPUWritePNGFile(const char *fileName)
 32.1392 +{
 32.1393 +	return utilWritePNGFile(fileName, 240, 160, pix);
 32.1394 +}
 32.1395 +
 32.1396 +bool CPUWriteBMPFile(const char *fileName)
 32.1397 +{
 32.1398 +	return utilWriteBMPFile(fileName, 240, 160, pix);
 32.1399 +}
 32.1400 +
 32.1401 +void CPUCleanUp()
 32.1402 +{
 32.1403 +	newFrame	  = true;
 32.1404 +
 32.1405 +	GBASystemCounters.frameCount = 0;
 32.1406 +	GBASystemCounters.lagCount	 = 0;
 32.1407 +	GBASystemCounters.extraCount = 0;
 32.1408 +	GBASystemCounters.lagged	 = true;
 32.1409 +	GBASystemCounters.laggedLast = true;
 32.1410 +
 32.1411 +#ifdef PROFILING
 32.1412 +	if (profilingTicksReload)
 32.1413 +	{
 32.1414 +		profCleanup();
 32.1415 +	}
 32.1416 +#endif
 32.1417 +
 32.1418 +#if (defined(WIN32) && !defined(SDL))
 32.1419 +	#define FreeMappedMem(name, mapName, offset) \
 32.1420 +	if (name != NULL) { \
 32.1421 +		UnmapViewOfFile((name) - (offset)); \
 32.1422 +		name = NULL; \
 32.1423 +		CloseHandle(mapName); \
 32.1424 +	}
 32.1425 +#else
 32.1426 +	#define FreeMappedMem(name, mapName, offset) \
 32.1427 +	if (name != NULL) { \
 32.1428 +		free(name); \
 32.1429 +		name = NULL; \
 32.1430 +	}
 32.1431 +#endif
 32.1432 +
 32.1433 +	FreeMappedMem(rom, mapROM, 0);
 32.1434 +	FreeMappedMem(vram, mapVRAM, 0);
 32.1435 +	FreeMappedMem(paletteRAM, mapPALETTERAM, 0);
 32.1436 +	FreeMappedMem(internalRAM, mapIRAM, 0);
 32.1437 +	FreeMappedMem(workRAM, mapWORKRAM, 0);
 32.1438 +	FreeMappedMem(bios, mapBIOS, 0);
 32.1439 +	FreeMappedMem(pix, mapPIX, 4);
 32.1440 +	FreeMappedMem(oam, mapOAM, 0);
 32.1441 +	FreeMappedMem(ioMem, mapIOMEM, 0);
 32.1442 +
 32.1443 +	eepromErase();
 32.1444 +	flashErase();
 32.1445 +
 32.1446 +	elfCleanUp();
 32.1447 +
 32.1448 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
 32.1449 +
 32.1450 +	systemClearJoypads();
 32.1451 +	systemResetSensor();
 32.1452 +
 32.1453 +//	gbaLastTime = gbaFrameCount = 0;
 32.1454 +	systemRefreshScreen();
 32.1455 +}
 32.1456 +
 32.1457 +int CPULoadRom(const char *szFile)
 32.1458 +{
 32.1459 +	int size = 0x2000000;
 32.1460 +
 32.1461 +	if (rom != NULL)
 32.1462 +	{
 32.1463 +		CPUCleanUp();
 32.1464 +	}
 32.1465 +
 32.1466 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
 32.1467 +
 32.1468 +	// size+4 is so RAM search and watch are safe to read any byte in the allocated region as a 4-byte int
 32.1469 +#if (defined(WIN32) && !defined(SDL))
 32.1470 +	#define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \
 32.1471 +	mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), nameStr); \
 32.1472 +	if ((mapName) && GetLastError() == ERROR_ALREADY_EXISTS) { \
 32.1473 +		CloseHandle(mapName); \
 32.1474 +		mapName = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (size) + (offset) + (4), NULL); \
 32.1475 +	} \
 32.1476 +	name = (u8 *)MapViewOfFile(mapName, FILE_MAP_WRITE, 0, 0, 0) + (offset); \
 32.1477 +	if ((name) == NULL) { \
 32.1478 +		systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \
 32.1479 +		CPUCleanUp(); \
 32.1480 +		return 0; \
 32.1481 +	} \
 32.1482 +	memset(name, 0, size + 4);
 32.1483 +#else
 32.1484 +	#define AllocMappedMem(name, mapName, nameStr, size, useCalloc, offset) \
 32.1485 +	name = (u8 *)(useCalloc ? calloc(1, size + 4) : malloc(size + 4)); \
 32.1486 +	if ((name) == NULL) { \
 32.1487 +		systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), nameStr); \
 32.1488 +		CPUCleanUp(); \
 32.1489 +		return 0; \
 32.1490 +	} \
 32.1491 +	memset(name, 0, size + 4);
 32.1492 +#endif
 32.1493 +
 32.1494 +	AllocMappedMem(rom, mapROM, "vbaROM", 0x2000000, false, 0);
 32.1495 +	AllocMappedMem(workRAM, mapWORKRAM, "vbaWORKRAM", 0x40000, true, 0);
 32.1496 +
 32.1497 +	u8 *whereToLoad = rom;
 32.1498 +	if (cpuIsMultiBoot)
 32.1499 +		whereToLoad = workRAM;
 32.1500 +
 32.1501 +	if (utilIsELF(szFile))
 32.1502 +	{
 32.1503 +		FILE *f = fopen(szFile, "rb");
 32.1504 +		if (!f)
 32.1505 +		{
 32.1506 +			systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"),
 32.1507 +			              szFile);
 32.1508 +			FreeMappedMem(rom, mapROM, 0);
 32.1509 +			FreeMappedMem(workRAM, mapWORKRAM, 0);
 32.1510 +			return 0;
 32.1511 +		}
 32.1512 +		bool res = elfRead(szFile, size, f);
 32.1513 +		if (!res || size == 0)
 32.1514 +		{
 32.1515 +			FreeMappedMem(rom, mapROM, 0);
 32.1516 +			FreeMappedMem(workRAM, mapWORKRAM, 0);
 32.1517 +			elfCleanUp();
 32.1518 +			return 0;
 32.1519 +		}
 32.1520 +	}
 32.1521 +	else if (!utilLoad(szFile,
 32.1522 +	                   utilIsGBAImage,
 32.1523 +	                   whereToLoad,
 32.1524 +	                   size))
 32.1525 +	{
 32.1526 +		FreeMappedMem(rom, mapROM, 0);
 32.1527 +		FreeMappedMem(workRAM, mapWORKRAM, 0);
 32.1528 +		return 0;
 32.1529 +	}
 32.1530 +
 32.1531 +	u16 *temp = (u16 *)(rom + ((size + 1) & ~1));
 32.1532 +	int	 i;
 32.1533 +	for (i = (size + 1) & ~1; i < 0x2000000; i += 2)
 32.1534 +	{
 32.1535 +		WRITE16LE(temp, (i >> 1) & 0xFFFF);
 32.1536 +		temp++;
 32.1537 +	}
 32.1538 +
 32.1539 +	AllocMappedMem(bios, mapBIOS, "vbaBIOS", 0x4000, true, 0);
 32.1540 +	AllocMappedMem(internalRAM, mapIRAM, "vbaIRAM", 0x8000, true, 0);
 32.1541 +	AllocMappedMem(paletteRAM, mapPALETTERAM, "vbaPALETTERAM", 0x400, true, 0);
 32.1542 +	AllocMappedMem(vram, mapVRAM, "vbaVRAM", 0x20000, true, 0);
 32.1543 +	AllocMappedMem(oam, mapOAM, "vbaOAM", 0x400, true, 0);
 32.1544 +
 32.1545 +	// HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel
 32.1546 +	AllocMappedMem(pix, mapPIX, "vbaPIX", 4 * 241 * 162, true, 4);
 32.1547 +	AllocMappedMem(ioMem, mapIOMEM, "vbaIOMEM", 0x400, true, 0);
 32.1548 +
 32.1549 +	CPUUpdateRenderBuffers(true);
 32.1550 +
 32.1551 +	return size;
 32.1552 +}
 32.1553 +
 32.1554 +void CPUUpdateRender()
 32.1555 +{
 32.1556 +	switch (DISPCNT & 7)
 32.1557 +	{
 32.1558 +	case 0:
 32.1559 +		if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
 32.1560 +		    cpuDisableSfx)
 32.1561 +			renderLine = mode0RenderLine;
 32.1562 +		else if (fxOn && !windowOn && !(layerEnable & 0x8000))
 32.1563 +			renderLine = mode0RenderLineNoWindow;
 32.1564 +		else
 32.1565 +			renderLine = mode0RenderLineAll;
 32.1566 +		break;
 32.1567 +	case 1:
 32.1568 +		if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
 32.1569 +		    cpuDisableSfx)
 32.1570 +			renderLine = mode1RenderLine;
 32.1571 +		else if (fxOn && !windowOn && !(layerEnable & 0x8000))
 32.1572 +			renderLine = mode1RenderLineNoWindow;
 32.1573 +		else
 32.1574 +			renderLine = mode1RenderLineAll;
 32.1575 +		break;
 32.1576 +	case 2:
 32.1577 +		if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
 32.1578 +		    cpuDisableSfx)
 32.1579 +			renderLine = mode2RenderLine;
 32.1580 +		else if (fxOn && !windowOn && !(layerEnable & 0x8000))
 32.1581 +			renderLine = mode2RenderLineNoWindow;
 32.1582 +		else
 32.1583 +			renderLine = mode2RenderLineAll;
 32.1584 +		break;
 32.1585 +	case 3:
 32.1586 +		if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
 32.1587 +		    cpuDisableSfx)
 32.1588 +			renderLine = mode3RenderLine;
 32.1589 +		else if (fxOn && !windowOn && !(layerEnable & 0x8000))
 32.1590 +			renderLine = mode3RenderLineNoWindow;
 32.1591 +		else
 32.1592 +			renderLine = mode3RenderLineAll;
 32.1593 +		break;
 32.1594 +	case 4:
 32.1595 +		if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
 32.1596 +		    cpuDisableSfx)
 32.1597 +			renderLine = mode4RenderLine;
 32.1598 +		else if (fxOn && !windowOn && !(layerEnable & 0x8000))
 32.1599 +			renderLine = mode4RenderLineNoWindow;
 32.1600 +		else
 32.1601 +			renderLine = mode4RenderLineAll;
 32.1602 +		break;
 32.1603 +	case 5:
 32.1604 +		if ((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
 32.1605 +		    cpuDisableSfx)
 32.1606 +			renderLine = mode5RenderLine;
 32.1607 +		else if (fxOn && !windowOn && !(layerEnable & 0x8000))
 32.1608 +			renderLine = mode5RenderLineNoWindow;
 32.1609 +		else
 32.1610 +			renderLine = mode5RenderLineAll;
 32.1611 +	default:
 32.1612 +		break;
 32.1613 +	}
 32.1614 +}
 32.1615 +
 32.1616 +void CPUUpdateCPSR()
 32.1617 +{
 32.1618 +	u32 CPSR = reg[16].I & 0x40;
 32.1619 +	if (N_FLAG)
 32.1620 +		CPSR |= 0x80000000;
 32.1621 +	if (Z_FLAG)
 32.1622 +		CPSR |= 0x40000000;
 32.1623 +	if (C_FLAG)
 32.1624 +		CPSR |= 0x20000000;
 32.1625 +	if (V_FLAG)
 32.1626 +		CPSR |= 0x10000000;
 32.1627 +	if (!armState)
 32.1628 +		CPSR |= 0x00000020;
 32.1629 +	if (!armIrqEnable)
 32.1630 +		CPSR |= 0x80;
 32.1631 +	CPSR	 |= (armMode & 0x1F);
 32.1632 +	reg[16].I = CPSR;
 32.1633 +}
 32.1634 +
 32.1635 +void CPUUpdateFlags(bool breakLoop)
 32.1636 +{
 32.1637 +	u32 CPSR = reg[16].I;
 32.1638 +
 32.1639 +	N_FLAG		 = (CPSR & 0x80000000) ? true : false;
 32.1640 +	Z_FLAG		 = (CPSR & 0x40000000) ? true : false;
 32.1641 +	C_FLAG		 = (CPSR & 0x20000000) ? true : false;
 32.1642 +	V_FLAG		 = (CPSR & 0x10000000) ? true : false;
 32.1643 +	armState	 = (CPSR & 0x20) ? false : true;
 32.1644 +	armIrqEnable = (CPSR & 0x80) ? false : true;
 32.1645 +	if (breakLoop)
 32.1646 +	{
 32.1647 +		if (armIrqEnable && (IF & IE) && (IME & 1))
 32.1648 +		{
 32.1649 +			CPU_BREAK_LOOP_2;
 32.1650 +		}
 32.1651 +	}
 32.1652 +}
 32.1653 +
 32.1654 +void CPUUpdateFlags()
 32.1655 +{
 32.1656 +	CPUUpdateFlags(true);
 32.1657 +}
 32.1658 +
 32.1659 +#ifdef WORDS_BIGENDIAN
 32.1660 +static void CPUSwap(volatile u32 *a, volatile u32 *b)
 32.1661 +{
 32.1662 +	volatile u32 c = *b;
 32.1663 +	*b = *a;
 32.1664 +	*a = c;
 32.1665 +}
 32.1666 +
 32.1667 +#else
 32.1668 +static void CPUSwap(u32 *a, u32 *b)
 32.1669 +{
 32.1670 +	u32 c = *b;
 32.1671 +	*b = *a;
 32.1672 +	*a = c;
 32.1673 +}
 32.1674 +
 32.1675 +#endif
 32.1676 +
 32.1677 +void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
 32.1678 +{
 32.1679 +	//  if(armMode == mode)
 32.1680 +	//    return;
 32.1681 +
 32.1682 +	CPUUpdateCPSR();
 32.1683 +
 32.1684 +	switch (armMode)
 32.1685 +	{
 32.1686 +	case 0x10:
 32.1687 +	case 0x1F:
 32.1688 +		reg[R13_USR].I = reg[13].I;
 32.1689 +		reg[R14_USR].I = reg[14].I;
 32.1690 +		reg[17].I	   = reg[16].I;
 32.1691 +		break;
 32.1692 +	case 0x11:
 32.1693 +		CPUSwap(&reg[R8_FIQ].I, &reg[8].I);
 32.1694 +		CPUSwap(&reg[R9_FIQ].I, &reg[9].I);
 32.1695 +		CPUSwap(&reg[R10_FIQ].I, &reg[10].I);
 32.1696 +		CPUSwap(&reg[R11_FIQ].I, &reg[11].I);
 32.1697 +		CPUSwap(&reg[R12_FIQ].I, &reg[12].I);
 32.1698 +		reg[R13_FIQ].I	= reg[13].I;
 32.1699 +		reg[R14_FIQ].I	= reg[14].I;
 32.1700 +		reg[SPSR_FIQ].I = reg[17].I;
 32.1701 +		break;
 32.1702 +	case 0x12:
 32.1703 +		reg[R13_IRQ].I	= reg[13].I;
 32.1704 +		reg[R14_IRQ].I	= reg[14].I;
 32.1705 +		reg[SPSR_IRQ].I =  reg[17].I;
 32.1706 +		break;
 32.1707 +	case 0x13:
 32.1708 +		reg[R13_SVC].I	= reg[13].I;
 32.1709 +		reg[R14_SVC].I	= reg[14].I;
 32.1710 +		reg[SPSR_SVC].I =  reg[17].I;
 32.1711 +		break;
 32.1712 +	case 0x17:
 32.1713 +		reg[R13_ABT].I	= reg[13].I;
 32.1714 +		reg[R14_ABT].I	= reg[14].I;
 32.1715 +		reg[SPSR_ABT].I =  reg[17].I;
 32.1716 +		break;
 32.1717 +	case 0x1b:
 32.1718 +		reg[R13_UND].I	= reg[13].I;
 32.1719 +		reg[R14_UND].I	= reg[14].I;
 32.1720 +		reg[SPSR_UND].I =  reg[17].I;
 32.1721 +		break;
 32.1722 +	}
 32.1723 +
 32.1724 +	u32 CPSR = reg[16].I;
 32.1725 +	u32 SPSR = reg[17].I;
 32.1726 +
 32.1727 +	switch (mode)
 32.1728 +	{
 32.1729 +	case 0x10:
 32.1730 +	case 0x1F:
 32.1731 +		reg[13].I = reg[R13_USR].I;
 32.1732 +		reg[14].I = reg[R14_USR].I;
 32.1733 +		reg[16].I = SPSR;
 32.1734 +		break;
 32.1735 +	case 0x11:
 32.1736 +		CPUSwap(&reg[8].I, &reg[R8_FIQ].I);
 32.1737 +		CPUSwap(&reg[9].I, &reg[R9_FIQ].I);
 32.1738 +		CPUSwap(&reg[10].I, &reg[R10_FIQ].I);
 32.1739 +		CPUSwap(&reg[11].I, &reg[R11_FIQ].I);
 32.1740 +		CPUSwap(&reg[12].I, &reg[R12_FIQ].I);
 32.1741 +		reg[13].I = reg[R13_FIQ].I;
 32.1742 +		reg[14].I = reg[R14_FIQ].I;
 32.1743 +		if (saveState)
 32.1744 +			reg[17].I = CPSR;
 32.1745 +		else
 32.1746 +			reg[17].I = reg[SPSR_FIQ].I;
 32.1747 +		break;
 32.1748 +	case 0x12:
 32.1749 +		reg[13].I = reg[R13_IRQ].I;
 32.1750 +		reg[14].I = reg[R14_IRQ].I;
 32.1751 +		reg[16].I = SPSR;
 32.1752 +		if (saveState)
 32.1753 +			reg[17].I = CPSR;
 32.1754 +		else
 32.1755 +			reg[17].I = reg[SPSR_IRQ].I;
 32.1756 +		break;
 32.1757 +	case 0x13:
 32.1758 +		reg[13].I = reg[R13_SVC].I;
 32.1759 +		reg[14].I = reg[R14_SVC].I;
 32.1760 +		reg[16].I = SPSR;
 32.1761 +		if (saveState)
 32.1762 +			reg[17].I = CPSR;
 32.1763 +		else
 32.1764 +			reg[17].I = reg[SPSR_SVC].I;
 32.1765 +		break;
 32.1766 +	case 0x17:
 32.1767 +		reg[13].I = reg[R13_ABT].I;
 32.1768 +		reg[14].I = reg[R14_ABT].I;
 32.1769 +		reg[16].I = SPSR;
 32.1770 +		if (saveState)
 32.1771 +			reg[17].I = CPSR;
 32.1772 +		else
 32.1773 +			reg[17].I = reg[SPSR_ABT].I;
 32.1774 +		break;
 32.1775 +	case 0x1b:
 32.1776 +		reg[13].I = reg[R13_UND].I;
 32.1777 +		reg[14].I = reg[R14_UND].I;
 32.1778 +		reg[16].I = SPSR;
 32.1779 +		if (saveState)
 32.1780 +			reg[17].I = CPSR;
 32.1781 +		else
 32.1782 +			reg[17].I = reg[SPSR_UND].I;
 32.1783 +		break;
 32.1784 +	default:
 32.1785 +		systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode);
 32.1786 +		break;
 32.1787 +	}
 32.1788 +	armMode = mode;
 32.1789 +	CPUUpdateFlags(breakLoop);
 32.1790 +	CPUUpdateCPSR();
 32.1791 +}
 32.1792 +
 32.1793 +void CPUSwitchMode(int mode, bool saveState)
 32.1794 +{
 32.1795 +	CPUSwitchMode(mode, saveState, true);
 32.1796 +}
 32.1797 +
 32.1798 +void CPUUndefinedException()
 32.1799 +{
 32.1800 +	u32	 PC = reg[15].I;
 32.1801 +	bool savedArmState = armState;
 32.1802 +	CPUSwitchMode(0x1b, true, false);
 32.1803 +	reg[14].I	 = PC - (savedArmState ? 4 : 2);
 32.1804 +	reg[15].I	 = 0x04;
 32.1805 +	armState	 = true;
 32.1806 +	armIrqEnable = false;
 32.1807 +	armNextPC	 = 0x04;
 32.1808 +	reg[15].I	+= 4;
 32.1809 +}
 32.1810 +
 32.1811 +void CPUSoftwareInterrupt()
 32.1812 +{
 32.1813 +	u32	 PC = reg[15].I;
 32.1814 +	bool savedArmState = armState;
 32.1815 +	CPUSwitchMode(0x13, true, false);
 32.1816 +	reg[14].I	 = PC - (savedArmState ? 4 : 2);
 32.1817 +	reg[15].I	 = 0x08;
 32.1818 +	armState	 = true;
 32.1819 +	armIrqEnable = false;
 32.1820 +	armNextPC	 = 0x08;
 32.1821 +	reg[15].I	+= 4;
 32.1822 +}
 32.1823 +
 32.1824 +void CPUSoftwareInterrupt(int comment)
 32.1825 +{
 32.1826 +	static bool disableMessage = false;
 32.1827 +	if (armState)
 32.1828 +		comment >>= 16;
 32.1829 +#ifdef BKPT_SUPPORT
 32.1830 +	if (comment == 0xff)
 32.1831 +	{
 32.1832 +		extern void (*dbgOutput)(char *, u32);
 32.1833 +		dbgOutput(NULL, reg[0].I);
 32.1834 +		return;
 32.1835 +	}
 32.1836 +#endif
 32.1837 +#ifdef PROFILING
 32.1838 +	if (comment == 0xfe)
 32.1839 +	{
 32.1840 +		profStartup(reg[0].I, reg[1].I);
 32.1841 +		return;
 32.1842 +	}
 32.1843 +	if (comment == 0xfd)
 32.1844 +	{
 32.1845 +		profControl(reg[0].I);
 32.1846 +		return;
 32.1847 +	}
 32.1848 +	if (comment == 0xfc)
 32.1849 +	{
 32.1850 +		profCleanup();
 32.1851 +		return;
 32.1852 +	}
 32.1853 +	if (comment == 0xfb)
 32.1854 +	{
 32.1855 +		profCount();
 32.1856 +		return;
 32.1857 +	}
 32.1858 +#endif
 32.1859 +	if (comment == 0xfa)
 32.1860 +	{
 32.1861 +		agbPrintFlush();
 32.1862 +		return;
 32.1863 +	}
 32.1864 +#ifdef SDL
 32.1865 +	if (comment == 0xf9)
 32.1866 +	{
 32.1867 +		emulating = 0;
 32.1868 +		CPU_BREAK_LOOP_2;
 32.1869 +		return;
 32.1870 +	}
 32.1871 +#endif
 32.1872 +	if (useBios)
 32.1873 +	{
 32.1874 +#ifdef GBA_LOGGING
 32.1875 +		if (systemVerbose & VERBOSE_SWI)
 32.1876 +		{
 32.1877 +			log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
 32.1878 +			    armState ? armNextPC - 4 : armNextPC - 2,
 32.1879 +			    reg[0].I,
 32.1880 +			    reg[1].I,
 32.1881 +			    reg[2].I,
 32.1882 +			    VCOUNT);
 32.1883 +		}
 32.1884 +#endif
 32.1885 +		CPUSoftwareInterrupt();
 32.1886 +		return;
 32.1887 +	}
 32.1888 +	// This would be correct, but it causes problems if uncommented
 32.1889 +	//  else {
 32.1890 +	//    biosProtected = 0xe3a02004;
 32.1891 +	//  }
 32.1892 +
 32.1893 +	switch (comment)
 32.1894 +	{
 32.1895 +	case 0x00:
 32.1896 +		BIOS_SoftReset();
 32.1897 +		break;
 32.1898 +	case 0x01:
 32.1899 +		BIOS_RegisterRamReset();
 32.1900 +		break;
 32.1901 +	case 0x02:
 32.1902 +#ifdef GBA_LOGGING
 32.1903 +		if (systemVerbose & VERBOSE_SWI)
 32.1904 +		{
 32.1905 +			log("Halt: (VCOUNT = %2d)\n",
 32.1906 +			    VCOUNT);
 32.1907 +		}
 32.1908 +#endif
 32.1909 +		holdState = true;
 32.1910 +		holdType  = -1;
 32.1911 +		break;
 32.1912 +	case 0x03:
 32.1913 +#ifdef GBA_LOGGING
 32.1914 +		if (systemVerbose & VERBOSE_SWI)
 32.1915 +		{
 32.1916 +			log("Stop: (VCOUNT = %2d)\n",
 32.1917 +			    VCOUNT);
 32.1918 +		}
 32.1919 +#endif
 32.1920 +		holdState = true;
 32.1921 +		holdType  = -1;
 32.1922 +		stopState = true;
 32.1923 +		break;
 32.1924 +	case 0x04:
 32.1925 +#ifdef GBA_LOGGING
 32.1926 +		if (systemVerbose & VERBOSE_SWI)
 32.1927 +		{
 32.1928 +			log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n",
 32.1929 +			    reg[0].I,
 32.1930 +			    reg[1].I,
 32.1931 +			    VCOUNT);
 32.1932 +		}
 32.1933 +#endif
 32.1934 +		CPUSoftwareInterrupt();
 32.1935 +		break;
 32.1936 +	case 0x05:
 32.1937 +#ifdef GBA_LOGGING
 32.1938 +		if (systemVerbose & VERBOSE_SWI)
 32.1939 +		{
 32.1940 +			log("VBlankIntrWait: (VCOUNT = %2d)\n",
 32.1941 +			    VCOUNT);
 32.1942 +		}
 32.1943 +#endif
 32.1944 +		CPUSoftwareInterrupt();
 32.1945 +		break;
 32.1946 +	case 0x06:
 32.1947 +		CPUSoftwareInterrupt();
 32.1948 +		break;
 32.1949 +	case 0x07:
 32.1950 +		CPUSoftwareInterrupt();
 32.1951 +		break;
 32.1952 +	case 0x08:
 32.1953 +		BIOS_Sqrt();
 32.1954 +		break;
 32.1955 +	case 0x09:
 32.1956 +		BIOS_ArcTan();
 32.1957 +		break;
 32.1958 +	case 0x0A:
 32.1959 +		BIOS_ArcTan2();
 32.1960 +		break;
 32.1961 +	case 0x0B:
 32.1962 +		BIOS_CpuSet();
 32.1963 +		break;
 32.1964 +	case 0x0C:
 32.1965 +		BIOS_CpuFastSet();
 32.1966 +		break;
 32.1967 +	case 0x0E:
 32.1968 +		BIOS_BgAffineSet();
 32.1969 +		break;
 32.1970 +	case 0x0F:
 32.1971 +		BIOS_ObjAffineSet();
 32.1972 +		break;
 32.1973 +	case 0x10:
 32.1974 +		BIOS_BitUnPack();
 32.1975 +		break;
 32.1976 +	case 0x11:
 32.1977 +		BIOS_LZ77UnCompWram();
 32.1978 +		break;
 32.1979 +	case 0x12:
 32.1980 +		BIOS_LZ77UnCompVram();
 32.1981 +		break;
 32.1982 +	case 0x13:
 32.1983 +		BIOS_HuffUnComp();
 32.1984 +		break;
 32.1985 +	case 0x14:
 32.1986 +		BIOS_RLUnCompWram();
 32.1987 +		break;
 32.1988 +	case 0x15:
 32.1989 +		BIOS_RLUnCompVram();
 32.1990 +		break;
 32.1991 +	case 0x16:
 32.1992 +		BIOS_Diff8bitUnFilterWram();
 32.1993 +		break;
 32.1994 +	case 0x17:
 32.1995 +		BIOS_Diff8bitUnFilterVram();
 32.1996 +		break;
 32.1997 +	case 0x18:
 32.1998 +		BIOS_Diff16bitUnFilter();
 32.1999 +		break;
 32.2000 +	case 0x19:
 32.2001 +#ifdef GBA_LOGGING
 32.2002 +		if (systemVerbose & VERBOSE_SWI)
 32.2003 +		{
 32.2004 +			log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n",
 32.2005 +			    reg[0].I,
 32.2006 +			    VCOUNT);
 32.2007 +		}
 32.2008 +#endif
 32.2009 +		if (reg[0].I)
 32.2010 +			soundPause();
 32.2011 +		else
 32.2012 +			soundResume();
 32.2013 +		break;
 32.2014 +	case 0x1F:
 32.2015 +		BIOS_MidiKey2Freq();
 32.2016 +		break;
 32.2017 +	case 0x2A:
 32.2018 +		BIOS_SndDriverJmpTableCopy();
 32.2019 +	// let it go, because we don't really emulate this function // FIXME (?)
 32.2020 +	default:
 32.2021 +#ifdef GBA_LOGGING
 32.2022 +		if (systemVerbose & VERBOSE_SWI)
 32.2023 +		{
 32.2024 +			log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
 32.2025 +			    armState ? armNextPC - 4 : armNextPC - 2,
 32.2026 +			    reg[0].I,
 32.2027 +			    reg[1].I,
 32.2028 +			    reg[2].I,
 32.2029 +			    VCOUNT);
 32.2030 +		}
 32.2031 +#endif
 32.2032 +
 32.2033 +		if (!disableMessage)
 32.2034 +		{
 32.2035 +			systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION,
 32.2036 +			              N_(
 32.2037 +			                  "Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."),
 32.2038 +			              comment,
 32.2039 +			              armMode ? armNextPC - 4 : armNextPC - 2);
 32.2040 +			disableMessage = true;
 32.2041 +		}
 32.2042 +		break;
 32.2043 +	}
 32.2044 +}
 32.2045 +
 32.2046 +void CPUCompareVCOUNT()
 32.2047 +{
 32.2048 +	if (VCOUNT == (DISPSTAT >> 8))
 32.2049 +	{
 32.2050 +		DISPSTAT |= 4;
 32.2051 +		UPDATE_REG(0x04, DISPSTAT);
 32.2052 +
 32.2053 +		if (DISPSTAT & 0x20)
 32.2054 +		{
 32.2055 +			IF |= 4;
 32.2056 +			UPDATE_REG(0x202, IF);
 32.2057 +		}
 32.2058 +	}
 32.2059 +	else
 32.2060 +	{
 32.2061 +		DISPSTAT &= 0xFFFB;
 32.2062 +		UPDATE_REG(0x4, DISPSTAT);
 32.2063 +	}
 32.2064 +}
 32.2065 +
 32.2066 +void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
 32.2067 +{
 32.2068 +	int sm = s >> 24;
 32.2069 +	int dm = d >> 24;
 32.2070 +
 32.2071 +	int sc = c;
 32.2072 +
 32.2073 +	cpuDmaCount = c;
 32.2074 +
 32.2075 +	if (transfer32)
 32.2076 +	{
 32.2077 +		s &= 0xFFFFFFFC;
 32.2078 +		if (s < 0x02000000 && (reg[15].I >> 24))
 32.2079 +		{
 32.2080 +			while (c != 0)
 32.2081 +			{
 32.2082 +				CPUWriteMemory(d, 0);
 32.2083 +				d += di;
 32.2084 +				c--;
 32.2085 +			}
 32.2086 +		}
 32.2087 +		else
 32.2088 +		{
 32.2089 +			while (c != 0)
 32.2090 +			{
 32.2091 +				CPUWriteMemory(d, CPUReadMemory(s));
 32.2092 +				d += di;
 32.2093 +				s += si;
 32.2094 +				c--;
 32.2095 +			}
 32.2096 +		}
 32.2097 +	}
 32.2098 +	else
 32.2099 +	{
 32.2100 +		s &= 0xFFFFFFFE;
 32.2101 +		si = (int)si >> 1;
 32.2102 +		di = (int)di >> 1;
 32.2103 +		if (s < 0x02000000 && (reg[15].I >> 24))
 32.2104 +		{
 32.2105 +			while (c != 0)
 32.2106 +			{
 32.2107 +				CPUWriteHalfWord(d, 0);
 32.2108 +				d += di;
 32.2109 +				c--;
 32.2110 +			}
 32.2111 +		}
 32.2112 +		else
 32.2113 +		{
 32.2114 +			while (c != 0)
 32.2115 +			{
 32.2116 +				cpuDmaLast = CPUReadHalfWord(s);
 32.2117 +				CPUWriteHalfWord(d, cpuDmaLast);
 32.2118 +				d += di;
 32.2119 +				s += si;
 32.2120 +				c--;
 32.2121 +			}
 32.2122 +		}
 32.2123 +	}
 32.2124 +
 32.2125 +	cpuDmaCount = 0;
 32.2126 +
 32.2127 +	int sw = 1 + memoryWaitSeq[sm & 15];
 32.2128 +	int dw = 1 + memoryWaitSeq[dm & 15];
 32.2129 +
 32.2130 +	int totalTicks = 0;
 32.2131 +
 32.2132 +	if (transfer32)
 32.2133 +	{
 32.2134 +		if (!memory32[sm & 15])
 32.2135 +			sw <<= 1;
 32.2136 +		if (!memory32[dm & 15])
 32.2137 +			dw <<= 1;
 32.2138 +	}
 32.2139 +
 32.2140 +	totalTicks = (sw + dw) * sc;
 32.2141 +
 32.2142 +	cpuDmaTicksToUpdate += totalTicks;
 32.2143 +
 32.2144 +	if (*extCpuLoopTicks >= 0)
 32.2145 +	{
 32.2146 +		CPU_BREAK_LOOP;
 32.2147 +	}
 32.2148 +}
 32.2149 +
 32.2150 +void CPUCheckDMA(int reason, int dmamask)
 32.2151 +{
 32.2152 +	cpuDmaHack = 0;
 32.2153 +	// DMA 0
 32.2154 +	if ((DM0CNT_H & 0x8000) && (dmamask & 1))
 32.2155 +	{
 32.2156 +		if (((DM0CNT_H >> 12) & 3) == reason)
 32.2157 +		{
 32.2158 +			u32 sourceIncrement = 4;
 32.2159 +			u32 destIncrement	= 4;
 32.2160 +			switch ((DM0CNT_H >> 7) & 3)
 32.2161 +			{
 32.2162 +			case 0:
 32.2163 +				break;
 32.2164 +			case 1:
 32.2165 +				sourceIncrement = (u32) - 4;
 32.2166 +				break;
 32.2167 +			case 2:
 32.2168 +				sourceIncrement = 0;
 32.2169 +				break;
 32.2170 +			}
 32.2171 +			switch ((DM0CNT_H >> 5) & 3)
 32.2172 +			{
 32.2173 +			case 0:
 32.2174 +				break;
 32.2175 +			case 1:
 32.2176 +				destIncrement = (u32) - 4;
 32.2177 +				break;
 32.2178 +			case 2:
 32.2179 +				destIncrement = 0;
 32.2180 +				break;
 32.2181 +			}
 32.2182 +#ifdef GBA_LOGGING
 32.2183 +			if (systemVerbose & VERBOSE_DMA0)
 32.2184 +			{
 32.2185 +				int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1;
 32.2186 +				if (DM0CNT_H & 0x0400)
 32.2187 +					count <<= 1;
 32.2188 +				log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest,
 32.2189 +				    DM0CNT_H,
 32.2190 +				    count);
 32.2191 +			}
 32.2192 +#endif
 32.2193 +			doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement,
 32.2194 +			      DM0CNT_L ? DM0CNT_L : 0x4000,
 32.2195 +			      DM0CNT_H & 0x0400);
 32.2196 +			cpuDmaHack = 1;
 32.2197 +			if (DM0CNT_H & 0x4000)
 32.2198 +			{
 32.2199 +				IF |= 0x0100;
 32.2200 +				UPDATE_REG(0x202, IF);
 32.2201 +			}
 32.2202 +
 32.2203 +			if (((DM0CNT_H >> 5) & 3) == 3)
 32.2204 +			{
 32.2205 +				dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
 32.2206 +			}
 32.2207 +
 32.2208 +			if (!(DM0CNT_H & 0x0200) || (reason == 0))
 32.2209 +			{
 32.2210 +				DM0CNT_H &= 0x7FFF;
 32.2211 +				UPDATE_REG(0xBA, DM0CNT_H);
 32.2212 +			}
 32.2213 +		}
 32.2214 +	}
 32.2215 +
 32.2216 +	// DMA 1
 32.2217 +	if ((DM1CNT_H & 0x8000) && (dmamask & 2))
 32.2218 +	{
 32.2219 +		if (((DM1CNT_H >> 12) & 3) == reason)
 32.2220 +		{
 32.2221 +			u32 sourceIncrement = 4;
 32.2222 +			u32 destIncrement	= 4;
 32.2223 +			switch ((DM1CNT_H >> 7) & 3)
 32.2224 +			{
 32.2225 +			case 0:
 32.2226 +				break;
 32.2227 +			case 1:
 32.2228 +				sourceIncrement = (u32) - 4;
 32.2229 +				break;
 32.2230 +			case 2:
 32.2231 +				sourceIncrement = 0;
 32.2232 +				break;
 32.2233 +			}
 32.2234 +			switch ((DM1CNT_H >> 5) & 3)
 32.2235 +			{
 32.2236 +			case 0:
 32.2237 +				break;
 32.2238 +			case 1:
 32.2239 +				destIncrement = (u32) - 4;
 32.2240 +				break;
 32.2241 +			case 2:
 32.2242 +				destIncrement = 0;
 32.2243 +				break;
 32.2244 +			}
 32.2245 +			if (reason == 3)
 32.2246 +			{
 32.2247 +#ifdef GBA_LOGGING
 32.2248 +				if (systemVerbose & VERBOSE_DMA1)
 32.2249 +				{
 32.2250 +					log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
 32.2251 +					    DM1CNT_H,
 32.2252 +					    16);
 32.2253 +				}
 32.2254 +#endif
 32.2255 +				doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4,
 32.2256 +				      0x0400);
 32.2257 +			}
 32.2258 +			else
 32.2259 +			{
 32.2260 +#ifdef GBA_LOGGING
 32.2261 +				if (systemVerbose & VERBOSE_DMA1)
 32.2262 +				{
 32.2263 +					int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1;
 32.2264 +					if (DM1CNT_H & 0x0400)
 32.2265 +						count <<= 1;
 32.2266 +					log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
 32.2267 +					    DM1CNT_H,
 32.2268 +					    count);
 32.2269 +				}
 32.2270 +#endif
 32.2271 +				doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement,
 32.2272 +				      DM1CNT_L ? DM1CNT_L : 0x4000,
 32.2273 +				      DM1CNT_H & 0x0400);
 32.2274 +			}
 32.2275 +			cpuDmaHack = 1;
 32.2276 +
 32.2277 +			if (DM1CNT_H & 0x4000)
 32.2278 +			{
 32.2279 +				IF |= 0x0200;
 32.2280 +				UPDATE_REG(0x202, IF);
 32.2281 +			}
 32.2282 +
 32.2283 +			if (((DM1CNT_H >> 5) & 3) == 3)
 32.2284 +			{
 32.2285 +				dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
 32.2286 +			}
 32.2287 +
 32.2288 +			if (!(DM1CNT_H & 0x0200) || (reason == 0))
 32.2289 +			{
 32.2290 +				DM1CNT_H &= 0x7FFF;
 32.2291 +				UPDATE_REG(0xC6, DM1CNT_H);
 32.2292 +			}
 32.2293 +		}
 32.2294 +	}
 32.2295 +
 32.2296 +	// DMA 2
 32.2297 +	if ((DM2CNT_H & 0x8000) && (dmamask & 4))
 32.2298 +	{
 32.2299 +		if (((DM2CNT_H >> 12) & 3) == reason)
 32.2300 +		{
 32.2301 +			u32 sourceIncrement = 4;
 32.2302 +			u32 destIncrement	= 4;
 32.2303 +			switch ((DM2CNT_H >> 7) & 3)
 32.2304 +			{
 32.2305 +			case 0:
 32.2306 +				break;
 32.2307 +			case 1:
 32.2308 +				sourceIncrement = (u32) - 4;
 32.2309 +				break;
 32.2310 +			case 2:
 32.2311 +				sourceIncrement = 0;
 32.2312 +				break;
 32.2313 +			}
 32.2314 +			switch ((DM2CNT_H >> 5) & 3)
 32.2315 +			{
 32.2316 +			case 0:
 32.2317 +				break;
 32.2318 +			case 1:
 32.2319 +				destIncrement = (u32) - 4;
 32.2320 +				break;
 32.2321 +			case 2:
 32.2322 +				destIncrement = 0;
 32.2323 +				break;
 32.2324 +			}
 32.2325 +			if (reason == 3)
 32.2326 +			{
 32.2327 +#ifdef GBA_LOGGING
 32.2328 +				if (systemVerbose & VERBOSE_DMA2)
 32.2329 +				{
 32.2330 +					int count = (4) << 2;
 32.2331 +					log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
 32.2332 +					    DM2CNT_H,
 32.2333 +					    count);
 32.2334 +				}
 32.2335 +#endif
 32.2336 +				doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4,
 32.2337 +				      0x0400);
 32.2338 +			}
 32.2339 +			else
 32.2340 +			{
 32.2341 +#ifdef GBA_LOGGING
 32.2342 +				if (systemVerbose & VERBOSE_DMA2)
 32.2343 +				{
 32.2344 +					int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1;
 32.2345 +					if (DM2CNT_H & 0x0400)
 32.2346 +						count <<= 1;
 32.2347 +					log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
 32.2348 +					    DM2CNT_H,
 32.2349 +					    count);
 32.2350 +				}
 32.2351 +#endif
 32.2352 +				doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement,
 32.2353 +				      DM2CNT_L ? DM2CNT_L : 0x4000,
 32.2354 +				      DM2CNT_H & 0x0400);
 32.2355 +			}
 32.2356 +			cpuDmaHack = 1;
 32.2357 +			if (DM2CNT_H & 0x4000)
 32.2358 +			{
 32.2359 +				IF |= 0x0400;
 32.2360 +				UPDATE_REG(0x202, IF);
 32.2361 +			}
 32.2362 +
 32.2363 +			if (((DM2CNT_H >> 5) & 3) == 3)
 32.2364 +			{
 32.2365 +				dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
 32.2366 +			}
 32.2367 +
 32.2368 +			if (!(DM2CNT_H & 0x0200) || (reason == 0))
 32.2369 +			{
 32.2370 +				DM2CNT_H &= 0x7FFF;
 32.2371 +				UPDATE_REG(0xD2, DM2CNT_H);
 32.2372 +			}
 32.2373 +		}
 32.2374 +	}
 32.2375 +
 32.2376 +	// DMA 3
 32.2377 +	if ((DM3CNT_H & 0x8000) && (dmamask & 8))
 32.2378 +	{
 32.2379 +		if (((DM3CNT_H >> 12) & 3) == reason)
 32.2380 +		{
 32.2381 +			u32 sourceIncrement = 4;
 32.2382 +			u32 destIncrement	= 4;
 32.2383 +			switch ((DM3CNT_H >> 7) & 3)
 32.2384 +			{
 32.2385 +			case 0:
 32.2386 +				break;
 32.2387 +			case 1:
 32.2388 +				sourceIncrement = (u32) - 4;
 32.2389 +				break;
 32.2390 +			case 2:
 32.2391 +				sourceIncrement = 0;
 32.2392 +				break;
 32.2393 +			}
 32.2394 +			switch ((DM3CNT_H >> 5) & 3)
 32.2395 +			{
 32.2396 +			case 0:
 32.2397 +				break;
 32.2398 +			case 1:
 32.2399 +				destIncrement = (u32) - 4;
 32.2400 +				break;
 32.2401 +			case 2:
 32.2402 +				destIncrement = 0;
 32.2403 +				break;
 32.2404 +			}
 32.2405 +#ifdef GBA_LOGGING
 32.2406 +			if (systemVerbose & VERBOSE_DMA3)
 32.2407 +			{
 32.2408 +				int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1;
 32.2409 +				if (DM3CNT_H & 0x0400)
 32.2410 +					count <<= 1;
 32.2411 +				log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest,
 32.2412 +				    DM3CNT_H,
 32.2413 +				    count);
 32.2414 +			}
 32.2415 +#endif
 32.2416 +			doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement,
 32.2417 +			      DM3CNT_L ? DM3CNT_L : 0x10000,
 32.2418 +			      DM3CNT_H & 0x0400);
 32.2419 +			if (DM3CNT_H & 0x4000)
 32.2420 +			{
 32.2421 +				IF |= 0x0800;
 32.2422 +				UPDATE_REG(0x202, IF);
 32.2423 +			}
 32.2424 +
 32.2425 +			if (((DM3CNT_H >> 5) & 3) == 3)
 32.2426 +			{
 32.2427 +				dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
 32.2428 +			}
 32.2429 +
 32.2430 +			if (!(DM3CNT_H & 0x0200) || (reason == 0))
 32.2431 +			{
 32.2432 +				DM3CNT_H &= 0x7FFF;
 32.2433 +				UPDATE_REG(0xDE, DM3CNT_H);
 32.2434 +			}
 32.2435 +		}
 32.2436 +	}
 32.2437 +	cpuDmaHack = 0;
 32.2438 +}
 32.2439 +
 32.2440 +void CPUUpdateRegister(u32 address, u16 value)
 32.2441 +{
 32.2442 +	switch (address)
 32.2443 +	{
 32.2444 +	case 0x00:
 32.2445 +	{
 32.2446 +		bool change	  = ((DISPCNT ^ value) & 0x80) ? true : false;
 32.2447 +		bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false;
 32.2448 +		DISPCNT = (value & 0xFFF7);
 32.2449 +		UPDATE_REG(0x00, DISPCNT);
 32.2450 +		layerEnable = layerSettings & value;
 32.2451 +		windowOn	= (layerEnable & 0x6000) ? true : false;
 32.2452 +		if (change && !((value & 0x80)))
 32.2453 +		{
 32.2454 +			if (!(DISPSTAT & 1))
 32.2455 +			{
 32.2456 +				lcdTicks = 960;
 32.2457 +				//      VCOUNT = 0;
 32.2458 +				//      UPDATE_REG(0x06, VCOUNT);
 32.2459 +				DISPSTAT &= 0xFFFC;
 32.2460 +				UPDATE_REG(0x04, DISPSTAT);
 32.2461 +				CPUCompareVCOUNT();
 32.2462 +			}
 32.2463 +			//        (*renderLine)();
 32.2464 +		}
 32.2465 +		CPUUpdateRender();
 32.2466 +		// we only care about changes in BG0-BG3
 32.2467 +		if (changeBG)
 32.2468 +			CPUUpdateRenderBuffers(false);
 32.2469 +		//      CPUUpdateTicks();
 32.2470 +		break;
 32.2471 +	}
 32.2472 +	case 0x04:
 32.2473 +		DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7);
 32.2474 +		UPDATE_REG(0x04, DISPSTAT);
 32.2475 +		break;
 32.2476 +	case 0x06:
 32.2477 +		// not writable
 32.2478 +		break;
 32.2479 +	case 0x08:
 32.2480 +		BG0CNT = (value & 0xDFCF);
 32.2481 +		UPDATE_REG(0x08, BG0CNT);
 32.2482 +		break;
 32.2483 +	case 0x0A:
 32.2484 +		BG1CNT = (value & 0xDFCF);
 32.2485 +		UPDATE_REG(0x0A, BG1CNT);
 32.2486 +		break;
 32.2487 +	case 0x0C:
 32.2488 +		BG2CNT = (value & 0xFFCF);
 32.2489 +		UPDATE_REG(0x0C, BG2CNT);
 32.2490 +		break;
 32.2491 +	case 0x0E:
 32.2492 +		BG3CNT = (value & 0xFFCF);
 32.2493 +		UPDATE_REG(0x0E, BG3CNT);
 32.2494 +		break;
 32.2495 +	case 0x10:
 32.2496 +		BG0HOFS = value & 511;
 32.2497 +		UPDATE_REG(0x10, BG0HOFS);
 32.2498 +		break;
 32.2499 +	case 0x12:
 32.2500 +		BG0VOFS = value & 511;
 32.2501 +		UPDATE_REG(0x12, BG0VOFS);
 32.2502 +		break;
 32.2503 +	case 0x14:
 32.2504 +		BG1HOFS = value & 511;
 32.2505 +		UPDATE_REG(0x14, BG1HOFS);
 32.2506 +		break;
 32.2507 +	case 0x16:
 32.2508 +		BG1VOFS = value & 511;
 32.2509 +		UPDATE_REG(0x16, BG1VOFS);
 32.2510 +		break;
 32.2511 +	case 0x18:
 32.2512 +		BG2HOFS = value & 511;
 32.2513 +		UPDATE_REG(0x18, BG2HOFS);
 32.2514 +		break;
 32.2515 +	case 0x1A:
 32.2516 +		BG2VOFS = value & 511;
 32.2517 +		UPDATE_REG(0x1A, BG2VOFS);
 32.2518 +		break;
 32.2519 +	case 0x1C:
 32.2520 +		BG3HOFS = value & 511;
 32.2521 +		UPDATE_REG(0x1C, BG3HOFS);
 32.2522 +		break;
 32.2523 +	case 0x1E:
 32.2524 +		BG3VOFS = value & 511;
 32.2525 +		UPDATE_REG(0x1E, BG3VOFS);
 32.2526 +		break;
 32.2527 +	case 0x20:
 32.2528 +		BG2PA = value;
 32.2529 +		UPDATE_REG(0x20, BG2PA);
 32.2530 +		break;
 32.2531 +	case 0x22:
 32.2532 +		BG2PB = value;
 32.2533 +		UPDATE_REG(0x22, BG2PB);
 32.2534 +		break;
 32.2535 +	case 0x24:
 32.2536 +		BG2PC = value;
 32.2537 +		UPDATE_REG(0x24, BG2PC);
 32.2538 +		break;
 32.2539 +	case 0x26:
 32.2540 +		BG2PD = value;
 32.2541 +		UPDATE_REG(0x26, BG2PD);
 32.2542 +		break;
 32.2543 +	case 0x28:
 32.2544 +		BG2X_L = value;
 32.2545 +		UPDATE_REG(0x28, BG2X_L);
 32.2546 +		gfxBG2Changed |= 1;
 32.2547 +		break;
 32.2548 +	case 0x2A:
 32.2549 +		BG2X_H = (value & 0xFFF);
 32.2550 +		UPDATE_REG(0x2A, BG2X_H);
 32.2551 +		gfxBG2Changed |= 1;
 32.2552 +		break;
 32.2553 +	case 0x2C:
 32.2554 +		BG2Y_L = value;
 32.2555 +		UPDATE_REG(0x2C, BG2Y_L);
 32.2556 +		gfxBG2Changed |= 2;
 32.2557 +		break;
 32.2558 +	case 0x2E:
 32.2559 +		BG2Y_H = value & 0xFFF;
 32.2560 +		UPDATE_REG(0x2E, BG2Y_H);
 32.2561 +		gfxBG2Changed |= 2;
 32.2562 +		break;
 32.2563 +	case 0x30:
 32.2564 +		BG3PA = value;
 32.2565 +		UPDATE_REG(0x30, BG3PA);
 32.2566 +		break;
 32.2567 +	case 0x32:
 32.2568 +		BG3PB = value;
 32.2569 +		UPDATE_REG(0x32, BG3PB);
 32.2570 +		break;
 32.2571 +	case 0x34:
 32.2572 +		BG3PC = value;
 32.2573 +		UPDATE_REG(0x34, BG3PC);
 32.2574 +		break;
 32.2575 +	case 0x36:
 32.2576 +		BG3PD = value;
 32.2577 +		UPDATE_REG(0x36, BG3PD);
 32.2578 +		break;
 32.2579 +	case 0x38:
 32.2580 +		BG3X_L = value;
 32.2581 +		UPDATE_REG(0x38, BG3X_L);
 32.2582 +		gfxBG3Changed |= 1;
 32.2583 +		break;
 32.2584 +	case 0x3A:
 32.2585 +		BG3X_H = value & 0xFFF;
 32.2586 +		UPDATE_REG(0x3A, BG3X_H);
 32.2587 +		gfxBG3Changed |= 1;
 32.2588 +		break;
 32.2589 +	case 0x3C:
 32.2590 +		BG3Y_L = value;
 32.2591 +		UPDATE_REG(0x3C, BG3Y_L);
 32.2592 +		gfxBG3Changed |= 2;
 32.2593 +		break;
 32.2594 +	case 0x3E:
 32.2595 +		BG3Y_H = value & 0xFFF;
 32.2596 +		UPDATE_REG(0x3E, BG3Y_H);
 32.2597 +		gfxBG3Changed |= 2;
 32.2598 +		break;
 32.2599 +	case 0x40:
 32.2600 +		WIN0H = value;
 32.2601 +		UPDATE_REG(0x40, WIN0H);
 32.2602 +		CPUUpdateWindow0();
 32.2603 +		break;
 32.2604 +	case 0x42:
 32.2605 +		WIN1H = value;
 32.2606 +		UPDATE_REG(0x42, WIN1H);
 32.2607 +		CPUUpdateWindow1();
 32.2608 +		break;
 32.2609 +	case 0x44:
 32.2610 +		WIN0V = value;
 32.2611 +		UPDATE_REG(0x44, WIN0V);
 32.2612 +		break;
 32.2613 +	case 0x46:
 32.2614 +		WIN1V = value;
 32.2615 +		UPDATE_REG(0x46, WIN1V);
 32.2616 +		break;
 32.2617 +	case 0x48:
 32.2618 +		WININ = value & 0x3F3F;
 32.2619 +		UPDATE_REG(0x48, WININ);
 32.2620 +		break;
 32.2621 +	case 0x4A:
 32.2622 +		WINOUT = value & 0x3F3F;
 32.2623 +		UPDATE_REG(0x4A, WINOUT);
 32.2624 +		break;
 32.2625 +	case 0x4C:
 32.2626 +		MOSAIC = value;
 32.2627 +		UPDATE_REG(0x4C, MOSAIC);
 32.2628 +		break;
 32.2629 +	case 0x50:
 32.2630 +		BLDMOD = value & 0x3FFF;
 32.2631 +		UPDATE_REG(0x50, BLDMOD);
 32.2632 +		fxOn = ((BLDMOD >> 6) & 3) != 0;
 32.2633 +		CPUUpdateRender();
 32.2634 +		break;
 32.2635 +	case 0x52:
 32.2636 +		COLEV = value & 0x1F1F;
 32.2637 +		UPDATE_REG(0x52, COLEV);
 32.2638 +		break;
 32.2639 +	case 0x54:
 32.2640 +		COLY = value & 0x1F;
 32.2641 +		UPDATE_REG(0x54, COLY);
 32.2642 +		break;
 32.2643 +	case 0x60:
 32.2644 +	case 0x62:
 32.2645 +	case 0x64:
 32.2646 +	case 0x68:
 32.2647 +	case 0x6c:
 32.2648 +	case 0x70:
 32.2649 +	case 0x72:
 32.2650 +	case 0x74:
 32.2651 +	case 0x78:
 32.2652 +	case 0x7c:
 32.2653 +	case 0x80:
 32.2654 +	case 0x84:
 32.2655 +		soundEvent(address & 0xFF, (u8)(value & 0xFF));
 32.2656 +		soundEvent((address & 0xFF) + 1, (u8)(value >> 8));
 32.2657 +		break;
 32.2658 +	case 0x82:
 32.2659 +	case 0x88:
 32.2660 +	case 0xa0:
 32.2661 +	case 0xa2:
 32.2662 +	case 0xa4:
 32.2663 +	case 0xa6:
 32.2664 +	case 0x90:
 32.2665 +	case 0x92:
 32.2666 +	case 0x94:
 32.2667 +	case 0x96:
 32.2668 +	case 0x98:
 32.2669 +	case 0x9a:
 32.2670 +	case 0x9c:
 32.2671 +	case 0x9e:
 32.2672 +		soundEvent(address & 0xFF, value);
 32.2673 +		break;
 32.2674 +	case 0xB0:
 32.2675 +		DM0SAD_L = value;
 32.2676 +		UPDATE_REG(0xB0, DM0SAD_L);
 32.2677 +		break;
 32.2678 +	case 0xB2:
 32.2679 +		DM0SAD_H = value & 0x07FF;
 32.2680 +		UPDATE_REG(0xB2, DM0SAD_H);
 32.2681 +		break;
 32.2682 +	case 0xB4:
 32.2683 +		DM0DAD_L = value;
 32.2684 +		UPDATE_REG(0xB4, DM0DAD_L);
 32.2685 +		break;
 32.2686 +	case 0xB6:
 32.2687 +		DM0DAD_H = value & 0x07FF;
 32.2688 +		UPDATE_REG(0xB6, DM0DAD_H);
 32.2689 +		break;
 32.2690 +	case 0xB8:
 32.2691 +		DM0CNT_L = value & 0x3FFF;
 32.2692 +		UPDATE_REG(0xB8, 0);
 32.2693 +		break;
 32.2694 +	case 0xBA:
 32.2695 +	{
 32.2696 +		bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false;
 32.2697 +		value &= 0xF7E0;
 32.2698 +
 32.2699 +		DM0CNT_H = value;
 32.2700 +		UPDATE_REG(0xBA, DM0CNT_H);
 32.2701 +
 32.2702 +		if (start && (value & 0x8000))
 32.2703 +		{
 32.2704 +			dma0Source = DM0SAD_L | (DM0SAD_H << 16);
 32.2705 +			dma0Dest   = DM0DAD_L | (DM0DAD_H << 16);
 32.2706 +			CPUCheckDMA(0, 1);
 32.2707 +		}
 32.2708 +		break;
 32.2709 +	}
 32.2710 +	case 0xBC:
 32.2711 +		DM1SAD_L = value;
 32.2712 +		UPDATE_REG(0xBC, DM1SAD_L);
 32.2713 +		break;
 32.2714 +	case 0xBE:
 32.2715 +		DM1SAD_H = value & 0x0FFF;
 32.2716 +		UPDATE_REG(0xBE, DM1SAD_H);
 32.2717 +		break;
 32.2718 +	case 0xC0:
 32.2719 +		DM1DAD_L = value;
 32.2720 +		UPDATE_REG(0xC0, DM1DAD_L);
 32.2721 +		break;
 32.2722 +	case 0xC2:
 32.2723 +		DM1DAD_H = value & 0x07FF;
 32.2724 +		UPDATE_REG(0xC2, DM1DAD_H);
 32.2725 +		break;
 32.2726 +	case 0xC4:
 32.2727 +		DM1CNT_L = value & 0x3FFF;
 32.2728 +		UPDATE_REG(0xC4, 0);
 32.2729 +		break;
 32.2730 +	case 0xC6:
 32.2731 +	{
 32.2732 +		bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false;
 32.2733 +		value &= 0xF7E0;
 32.2734 +
 32.2735 +		DM1CNT_H = value;
 32.2736 +		UPDATE_REG(0xC6, DM1CNT_H);
 32.2737 +
 32.2738 +		if (start && (value & 0x8000))
 32.2739 +		{
 32.2740 +			dma1Source = DM1SAD_L | (DM1SAD_H << 16);
 32.2741 +			dma1Dest   = DM1DAD_L | (DM1DAD_H << 16);
 32.2742 +			CPUCheckDMA(0, 2);
 32.2743 +		}
 32.2744 +		break;
 32.2745 +	}
 32.2746 +	case 0xC8:
 32.2747 +		DM2SAD_L = value;
 32.2748 +		UPDATE_REG(0xC8, DM2SAD_L);
 32.2749 +		break;
 32.2750 +	case 0xCA:
 32.2751 +		DM2SAD_H = value & 0x0FFF;
 32.2752 +		UPDATE_REG(0xCA, DM2SAD_H);
 32.2753 +		break;
 32.2754 +	case 0xCC:
 32.2755 +		DM2DAD_L = value;
 32.2756 +		UPDATE_REG(0xCC, DM2DAD_L);
 32.2757 +		break;
 32.2758 +	case 0xCE:
 32.2759 +		DM2DAD_H = value & 0x07FF;
 32.2760 +		UPDATE_REG(0xCE, DM2DAD_H);
 32.2761 +		break;
 32.2762 +	case 0xD0:
 32.2763 +		DM2CNT_L = value & 0x3FFF;
 32.2764 +		UPDATE_REG(0xD0, 0);
 32.2765 +		break;
 32.2766 +	case 0xD2:
 32.2767 +	{
 32.2768 +		bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false;
 32.2769 +
 32.2770 +		value &= 0xF7E0;
 32.2771 +
 32.2772 +		DM2CNT_H = value;
 32.2773 +		UPDATE_REG(0xD2, DM2CNT_H);
 32.2774 +
 32.2775 +		if (start && (value & 0x8000))
 32.2776 +		{
 32.2777 +			dma2Source = DM2SAD_L | (DM2SAD_H << 16);
 32.2778 +			dma2Dest   = DM2DAD_L | (DM2DAD_H << 16);
 32.2779 +
 32.2780 +			CPUCheckDMA(0, 4);
 32.2781 +		}
 32.2782 +		break;
 32.2783 +	}
 32.2784 +	case 0xD4:
 32.2785 +		DM3SAD_L = value;
 32.2786 +		UPDATE_REG(0xD4, DM3SAD_L);
 32.2787 +		break;
 32.2788 +	case 0xD6:
 32.2789 +		DM3SAD_H = value & 0x0FFF;
 32.2790 +		UPDATE_REG(0xD6, DM3SAD_H);
 32.2791 +		break;
 32.2792 +	case 0xD8:
 32.2793 +		DM3DAD_L = value;
 32.2794 +		UPDATE_REG(0xD8, DM3DAD_L);
 32.2795 +		break;
 32.2796 +	case 0xDA:
 32.2797 +		DM3DAD_H = value & 0x0FFF;
 32.2798 +		UPDATE_REG(0xDA, DM3DAD_H);
 32.2799 +		break;
 32.2800 +	case 0xDC:
 32.2801 +		DM3CNT_L = value;
 32.2802 +		UPDATE_REG(0xDC, 0);
 32.2803 +		break;
 32.2804 +	case 0xDE:
 32.2805 +	{
 32.2806 +		bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false;
 32.2807 +
 32.2808 +		value &= 0xFFE0;
 32.2809 +
 32.2810 +		DM3CNT_H = value;
 32.2811 +		UPDATE_REG(0xDE, DM3CNT_H);
 32.2812 +
 32.2813 +		if (start && (value & 0x8000))
 32.2814 +		{
 32.2815 +			dma3Source = DM3SAD_L | (DM3SAD_H << 16);
 32.2816 +			dma3Dest   = DM3DAD_L | (DM3DAD_H << 16);
 32.2817 +			CPUCheckDMA(0, 8);
 32.2818 +		}
 32.2819 +		break;
 32.2820 +	}
 32.2821 +	case 0x100:
 32.2822 +		timer0Reload = value;
 32.2823 +		break;
 32.2824 +	case 0x102:
 32.2825 +		timer0Ticks = timer0ClockReload = TIMER_TICKS[value & 3];
 32.2826 +		if (!timer0On && (value & 0x80))
 32.2827 +		{
 32.2828 +			// reload the counter
 32.2829 +			TM0D = timer0Reload;
 32.2830 +			if (timer0ClockReload == 1)
 32.2831 +				timer0Ticks = 0x10000 - TM0D;
 32.2832 +			UPDATE_REG(0x100, TM0D);
 32.2833 +		}
 32.2834 +		timer0On = value & 0x80 ? true : false;
 32.2835 +		TM0CNT	 = value & 0xC7;
 32.2836 +		UPDATE_REG(0x102, TM0CNT);
 32.2837 +		//    CPUUpdateTicks();
 32.2838 +		break;
 32.2839 +	case 0x104:
 32.2840 +		timer1Reload = value;
 32.2841 +		break;
 32.2842 +	case 0x106:
 32.2843 +		timer1Ticks = timer1ClockReload = TIMER_TICKS[value & 3];
 32.2844 +		if (!timer1On && (value & 0x80))
 32.2845 +		{
 32.2846 +			// reload the counter
 32.2847 +			TM1D = timer1Reload;
 32.2848 +			if (timer1ClockReload == 1)
 32.2849 +				timer1Ticks = 0x10000 - TM1D;
 32.2850 +			UPDATE_REG(0x104, TM1D);
 32.2851 +		}
 32.2852 +		timer1On = value & 0x80 ? true : false;
 32.2853 +		TM1CNT	 = value & 0xC7;
 32.2854 +		UPDATE_REG(0x106, TM1CNT);
 32.2855 +		break;
 32.2856 +	case 0x108:
 32.2857 +		timer2Reload = value;
 32.2858 +		break;
 32.2859 +	case 0x10A:
 32.2860 +		timer2Ticks = timer2ClockReload = TIMER_TICKS[value & 3];
 32.2861 +		if (!timer2On && (value & 0x80))
 32.2862 +		{
 32.2863 +			// reload the counter
 32.2864 +			TM2D = timer2Reload;
 32.2865 +			if (timer2ClockReload == 1)
 32.2866 +				timer2Ticks = 0x10000 - TM2D;
 32.2867 +			UPDATE_REG(0x108, TM2D);
 32.2868 +		}
 32.2869 +		timer2On = value & 0x80 ? true : false;
 32.2870 +		TM2CNT	 = value & 0xC7;
 32.2871 +		UPDATE_REG(0x10A, TM2CNT);
 32.2872 +		break;
 32.2873 +	case 0x10C:
 32.2874 +		timer3Reload = value;
 32.2875 +		break;
 32.2876 +	case 0x10E:
 32.2877 +		timer3Ticks = timer3ClockReload = TIMER_TICKS[value & 3];
 32.2878 +		if (!timer3On && (value & 0x80))
 32.2879 +		{
 32.2880 +			// reload the counter
 32.2881 +			TM3D = timer3Reload;
 32.2882 +			if (timer3ClockReload == 1)
 32.2883 +				timer3Ticks = 0x10000 - TM3D;
 32.2884 +			UPDATE_REG(0x10C, TM3D);
 32.2885 +		}
 32.2886 +		timer3On = value & 0x80 ? true : false;
 32.2887 +		TM3CNT	 = value & 0xC7;
 32.2888 +		UPDATE_REG(0x10E, TM3CNT);
 32.2889 +		break;
 32.2890 +	case 0x128:
 32.2891 +		if (value & 0x80)
 32.2892 +		{
 32.2893 +			value &= 0xff7f;
 32.2894 +			if (value & 1 && (value & 0x4000))
 32.2895 +			{
 32.2896 +				UPDATE_REG(0x12a, 0xFF);
 32.2897 +				IF |= 0x80;
 32.2898 +				UPDATE_REG(0x202, IF);
 32.2899 +				value &= 0x7f7f;
 32.2900 +			}
 32.2901 +		}
 32.2902 +		UPDATE_REG(0x128, value);
 32.2903 +		break;
 32.2904 +	case 0x130:
 32.2905 +		P1 |= (value & 0x3FF);
 32.2906 +		UPDATE_REG(0x130, P1);
 32.2907 +		break;
 32.2908 +	case 0x132:
 32.2909 +		UPDATE_REG(0x132, value & 0xC3FF);
 32.2910 +		break;
 32.2911 +	case 0x200:
 32.2912 +		IE = value & 0x3FFF;
 32.2913 +		UPDATE_REG(0x200, IE);
 32.2914 +		if ((IME & 1) && (IF & IE) && armIrqEnable)
 32.2915 +		{
 32.2916 +			CPU_BREAK_LOOP_2;
 32.2917 +		}
 32.2918 +		break;
 32.2919 +	case 0x202:
 32.2920 +		IF ^= (value & IF);
 32.2921 +		UPDATE_REG(0x202, IF);
 32.2922 +		break;
 32.2923 +	case 0x204:
 32.2924 +	{
 32.2925 +		int i;
 32.2926 +		memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3];
 32.2927 +
 32.2928 +		if (!speedHack)
 32.2929 +		{
 32.2930 +			memoryWait[0x08]	= memoryWait[0x09] = gamepakWaitState[(value >> 2) & 7];
 32.2931 +			memoryWaitSeq[0x08] = memoryWaitSeq[0x09] =
 32.2932 +			                          gamepakWaitState0[(value >> 2) & 7];
 32.2933 +
 32.2934 +			memoryWait[0x0a]	= memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 7];
 32.2935 +			memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] =
 32.2936 +			                          gamepakWaitState1[(value >> 5) & 7];
 32.2937 +
 32.2938 +			memoryWait[0x0c]	= memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 7];
 32.2939 +			memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] =
 32.2940 +			                          gamepakWaitState2[(value >> 8) & 7];
 32.2941 +		}
 32.2942 +		else
 32.2943 +		{
 32.2944 +			memoryWait[0x08]	= memoryWait[0x09] = 4;
 32.2945 +			memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 2;
 32.2946 +
 32.2947 +			memoryWait[0x0a]	= memoryWait[0x0b] = 4;
 32.2948 +			memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 4;
 32.2949 +
 32.2950 +			memoryWait[0x0c]	= memoryWait[0x0d] = 4;
 32.2951 +			memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 8;
 32.2952 +		}
 32.2953 +		for (i = 0; i < 16; i++)
 32.2954 +		{
 32.2955 +			memoryWaitFetch32[i] = memoryWait32[i] = memoryWait[i] *
 32.2956 +			                                         (memory32[i] ? 1 : 2);
 32.2957 +			memoryWaitFetch[i] = memoryWait[i];
 32.2958 +		}
 32.2959 +		memoryWaitFetch32[3] += 1;
 32.2960 +		memoryWaitFetch32[2] += 3;
 32.2961 +
 32.2962 +		prefetchActive	= false;
 32.2963 +		prefetchApplies = false;
 32.2964 +		if (value & 0x4000)
 32.2965 +		{
 32.2966 +			for (i = 8; i < 16; i++)
 32.2967 +			{
 32.2968 +				memoryWaitFetch32[i] = 2 * cpuMemoryWait[i];
 32.2969 +				memoryWaitFetch[i]	 = cpuMemoryWait[i];
 32.2970 +			}
 32.2971 +			if (((value & 3) == 3))
 32.2972 +			{
 32.2973 +				if (!memLagTempEnabled)
 32.2974 +				{
 32.2975 +					memoryWaitFetch[8]--; // hack to prevent inaccurately extreme lag at some points of many games (possibly
 32.2976 +					                      // from no pre-fetch emulation)
 32.2977 +					                      /// FIXME: how correct is this? Should it set the fetch to 0 or change fetch32 or
 32.2978 +					                      // anything else?
 32.2979 +
 32.2980 +					prefetchActive = true;
 32.2981 +				}
 32.2982 +				prefetchApplies = true;
 32.2983 +			}
 32.2984 +		}
 32.2985 +		//if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
 32.2986 +		//if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
 32.2987 +		prefetchPrevActive = prefetchActive;
 32.2988 +
 32.2989 +		UPDATE_REG(0x204, value);
 32.2990 +		break;
 32.2991 +	}
 32.2992 +	case 0x208:
 32.2993 +		IME = value & 1;
 32.2994 +		UPDATE_REG(0x208, IME);
 32.2995 +		if ((IME & 1) && (IF & IE) && armIrqEnable)
 32.2996 +		{
 32.2997 +			CPU_BREAK_LOOP_2;
 32.2998 +		}
 32.2999 +		break;
 32.3000 +	case 0x300:
 32.3001 +		if (value != 0)
 32.3002 +			value &= 0xFFFE;
 32.3003 +		UPDATE_REG(0x300, value);
 32.3004 +		break;
 32.3005 +	default:
 32.3006 +		UPDATE_REG(address & 0x3FE, value);
 32.3007 +		break;
 32.3008 +	}
 32.3009 +}
 32.3010 +
 32.3011 +void CPUWriteHalfWordWrapped(u32 address, u16 value)
 32.3012 +{
 32.3013 +#ifdef GBA_LOGGING
 32.3014 +	if (address & 1)
 32.3015 +	{
 32.3016 +		if (systemVerbose & VERBOSE_UNALIGNED_MEMORY)
 32.3017 +		{
 32.3018 +			log("Unaligned halfword write: %04x to %08x from %08x\n",
 32.3019 +			    value,
 32.3020 +			    address,
 32.3021 +			    armMode ? armNextPC - 4 : armNextPC - 2);
 32.3022 +		}
 32.3023 +	}
 32.3024 +#endif
 32.3025 +
 32.3026 +	switch (address >> 24)
 32.3027 +	{
 32.3028 +	case 2:
 32.3029 +#ifdef SDL
 32.3030 +		if (*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
 32.3031 +			cheatsWriteHalfWord((u16 *)&workRAM[address & 0x3FFFE],
 32.3032 +			                    value,
 32.3033 +			                    *((u16 *)&freezeWorkRAM[address & 0x3FFFE]));
 32.3034 +		else
 32.3035 +#endif
 32.3036 +		WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]), value);
 32.3037 +		break;
 32.3038 +	case 3:
 32.3039 +#ifdef SDL
 32.3040 +		if (*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
 32.3041 +			cheatsWriteHalfWord((u16 *)&internalRAM[address & 0x7ffe],
 32.3042 +			                    value,
 32.3043 +			                    *((u16 *)&freezeInternalRAM[address & 0x7ffe]));
 32.3044 +		else
 32.3045 +#endif
 32.3046 +		WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
 32.3047 +		break;
 32.3048 +	case 4:
 32.3049 +		CPUUpdateRegister(address & 0x3fe, value);
 32.3050 +		break;
 32.3051 +	case 5:
 32.3052 +		WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
 32.3053 +		break;
 32.3054 +	case 6:
 32.3055 +		if (address & 0x10000)
 32.3056 +			WRITE16LE(((u16 *)&vram[address & 0x17ffe]), value);
 32.3057 +		else
 32.3058 +			WRITE16LE(((u16 *)&vram[address & 0x1fffe]), value);
 32.3059 +		break;
 32.3060 +	case 7:
 32.3061 +		WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
 32.3062 +		break;
 32.3063 +	case 8:
 32.3064 +	case 9:
 32.3065 +		if (address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
 32.3066 +		{
 32.3067 +			if (!rtcWrite(address, value))
 32.3068 +				goto unwritable;
 32.3069 +		}
 32.3070 +		else if (!agbPrintWrite(address, value))
 32.3071 +			goto unwritable;
 32.3072 +		break;
 32.3073 +	case 13:
 32.3074 +		if (cpuEEPROMEnabled)
 32.3075 +		{
 32.3076 +			eepromWrite(address, (u8)(value & 0xFF));
 32.3077 +			break;
 32.3078 +		}
 32.3079 +		goto unwritable;
 32.3080 +	case 14:
 32.3081 +		if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)
 32.3082 +		{
 32.3083 +			(*cpuSaveGameFunc)(address, (u8)(value & 0xFF));
 32.3084 +			break;
 32.3085 +		}
 32.3086 +		goto unwritable;
 32.3087 +	default:
 32.3088 +unwritable:
 32.3089 +#ifdef GBA_LOGGING
 32.3090 +		if (systemVerbose & VERBOSE_ILLEGAL_WRITE)
 32.3091 +		{
 32.3092 +			log("Illegal halfword write: %04x to %08x from %08x\n",
 32.3093 +			    value,
 32.3094 +			    address,
 32.3095 +			    armMode ? armNextPC - 4 : armNextPC - 2);
 32.3096 +		}
 32.3097 +#endif
 32.3098 +		break;
 32.3099 +	}
 32.3100 +}
 32.3101 +
 32.3102 +void CPUWriteHalfWord(u32 address, u16 value)
 32.3103 +{
 32.3104 +	CPUWriteHalfWordWrapped(address, value);
 32.3105 +	CallRegisteredLuaMemHook(address, 2, value, LUAMEMHOOK_WRITE);
 32.3106 +}
 32.3107 +
 32.3108 +void CPUWriteByteWrapped(u32 address, u8 b)
 32.3109 +{
 32.3110 +	switch (address >> 24)
 32.3111 +	{
 32.3112 +	case 2:
 32.3113 +#ifdef SDL
 32.3114 +		if (freezeWorkRAM[address & 0x3FFFF])
 32.3115 +			cheatsWriteByte(&workRAM[address & 0x3FFFF], b);
 32.3116 +		else
 32.3117 +#endif
 32.3118 +		workRAM[address & 0x3FFFF] = b;
 32.3119 +		break;
 32.3120 +	case 3:
 32.3121 +#ifdef SDL
 32.3122 +		if (freezeInternalRAM[address & 0x7fff])
 32.3123 +			cheatsWriteByte(&internalRAM[address & 0x7fff], b);
 32.3124 +		else
 32.3125 +#endif
 32.3126 +		internalRAM[address & 0x7fff] = b;
 32.3127 +		break;
 32.3128 +	case 4:
 32.3129 +		switch (address & 0x3FF)
 32.3130 +		{
 32.3131 +		case 0x301:
 32.3132 +			if (b == 0x80)
 32.3133 +				stopState = true;
 32.3134 +			holdState = 1;
 32.3135 +			holdType  = -1;
 32.3136 +			break;
 32.3137 +		case 0x60:
 32.3138 +		case 0x61:
 32.3139 +		case 0x62:
 32.3140 +		case 0x63:
 32.3141 +		case 0x64:
 32.3142 +		case 0x65:
 32.3143 +		case 0x68:
 32.3144 +		case 0x69:
 32.3145 +		case 0x6c:
 32.3146 +		case 0x6d:
 32.3147 +		case 0x70:
 32.3148 +		case 0x71:
 32.3149 +		case 0x72:
 32.3150 +		case 0x73:
 32.3151 +		case 0x74:
 32.3152 +		case 0x75:
 32.3153 +		case 0x78:
 32.3154 +		case 0x79:
 32.3155 +		case 0x7c:
 32.3156 +		case 0x7d:
 32.3157 +		case 0x80:
 32.3158 +		case 0x81:
 32.3159 +		case 0x84:
 32.3160 +		case 0x85:
 32.3161 +		case 0x90:
 32.3162 +		case 0x91:
 32.3163 +		case 0x92:
 32.3164 +		case 0x93:
 32.3165 +		case 0x94:
 32.3166 +		case 0x95:
 32.3167 +		case 0x96:
 32.3168 +		case 0x97:
 32.3169 +		case 0x98:
 32.3170 +		case 0x99:
 32.3171 +		case 0x9a:
 32.3172 +		case 0x9b:
 32.3173 +		case 0x9c:
 32.3174 +		case 0x9d:
 32.3175 +		case 0x9e:
 32.3176 +		case 0x9f:
 32.3177 +			soundEvent(address & 0xFF, b);
 32.3178 +			break;
 32.3179 +		default:
 32.3180 +			//      if(address & 1) {
 32.3181 +			//        CPUWriteHalfWord(address-1, (CPUReadHalfWord(address-1)&0x00FF)|((int)b<<8));
 32.3182 +			//      } else
 32.3183 +			if (address & 1)
 32.3184 +				CPUUpdateRegister(address & 0x3fe,
 32.3185 +				                  ((READ16LE(((u16 *)&ioMem[address & 0x3fe])))
 32.3186 +				                   & 0x00FF) |
 32.3187 +				                  b << 8);
 32.3188 +			else
 32.3189 +				CPUUpdateRegister(address & 0x3fe,
 32.3190 +				                  ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b));
 32.3191 +		}
 32.3192 +		break;
 32.3193 +	case 5:
 32.3194 +		// no need to switch
 32.3195 +		*((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b;
 32.3196 +		break;
 32.3197 +	case 6:
 32.3198 +		// no need to switch
 32.3199 +		if (address & 0x10000)
 32.3200 +			*((u16 *)&vram[address & 0x17FFE]) = (b << 8) | b;
 32.3201 +		else
 32.3202 +			*((u16 *)&vram[address & 0x1FFFE]) = (b << 8) | b;
 32.3203 +		break;
 32.3204 +	case 7:
 32.3205 +		// no need to switch
 32.3206 +		*((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
 32.3207 +		break;
 32.3208 +	case 13:
 32.3209 +		if (cpuEEPROMEnabled)
 32.3210 +		{
 32.3211 +			eepromWrite(address, b);
 32.3212 +			break;
 32.3213 +		}
 32.3214 +		goto unwritable;
 32.3215 +	case 14:
 32.3216 +		if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)
 32.3217 +		{
 32.3218 +			(*cpuSaveGameFunc)(address, b);
 32.3219 +			break;
 32.3220 +		}
 32.3221 +	// default
 32.3222 +	default:
 32.3223 +unwritable:
 32.3224 +#ifdef GBA_LOGGING
 32.3225 +		if (systemVerbose & VERBOSE_ILLEGAL_WRITE)
 32.3226 +		{
 32.3227 +			log("Illegal byte write: %02x to %08x from %08x\n",
 32.3228 +			    b,
 32.3229 +			    address,
 32.3230 +			    armMode ? armNextPC - 4 : armNextPC - 2);
 32.3231 +		}
 32.3232 +#endif
 32.3233 +		break;
 32.3234 +	}
 32.3235 +}
 32.3236 +
 32.3237 +void CPUWriteByte(u32 address, u8 b)
 32.3238 +{
 32.3239 +	CPUWriteByteWrapped(address, b);
 32.3240 +	CallRegisteredLuaMemHook(address, 1, b, LUAMEMHOOK_WRITE);
 32.3241 +}
 32.3242 +
 32.3243 +bool CPULoadBios(const char *biosFileName, bool useBiosFile)
 32.3244 +{
 32.3245 +	useBios = false;
 32.3246 +	if (useBiosFile)
 32.3247 +	{
 32.3248 +		useBios = utilLoadBIOS(bios, biosFileName, 4);
 32.3249 +		if (!useBios)
 32.3250 +		{
 32.3251 +			systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid GBA BIOS file"));
 32.3252 +		}
 32.3253 +	}
 32.3254 +
 32.3255 +	if (!useBios)
 32.3256 +	{
 32.3257 +		// load internal BIOS
 32.3258 +		memcpy(bios, myROM, sizeof(myROM));
 32.3259 +	}
 32.3260 +
 32.3261 +	return useBios;
 32.3262 +}
 32.3263 +
 32.3264 +void CPUInit()
 32.3265 +{
 32.3266 +#ifdef WORDS_BIGENDIAN
 32.3267 +	if (!cpuBiosSwapped)
 32.3268 +	{
 32.3269 +		for (unsigned int i = 0; i < sizeof(myROM) / 4; i++)
 32.3270 +		{
 32.3271 +			WRITE32LE(&myROM[i], myROM[i]);
 32.3272 +		}
 32.3273 +		cpuBiosSwapped = true;
 32.3274 +	}
 32.3275 +#endif
 32.3276 +	gbaSaveType = 0;
 32.3277 +	eepromInUse = 0;
 32.3278 +	saveType	= 0;
 32.3279 +
 32.3280 +	if (!useBios)
 32.3281 +	{
 32.3282 +		// load internal BIOS
 32.3283 +		memcpy(bios, myROM, sizeof(myROM));
 32.3284 +	}
 32.3285 +
 32.3286 +	biosProtected[0] = 0x00;
 32.3287 +	biosProtected[1] = 0xf0;
 32.3288 +	biosProtected[2] = 0x29;
 32.3289 +	biosProtected[3] = 0xe1;
 32.3290 +
 32.3291 +	int i = 0;
 32.3292 +	for (i = 0; i < 256; i++)
 32.3293 +	{
 32.3294 +		int cpuBitSetCount = 0;
 32.3295 +		int j;
 32.3296 +		for (j = 0; j < 8; j++)
 32.3297 +			if (i & (1 << j))
 32.3298 +				cpuBitSetCount++;
 32.3299 +		cpuBitsSet[i] = cpuBitSetCount;
 32.3300 +
 32.3301 +		for (j = 0; j < 8; j++)
 32.3302 +			if (i & (1 << j))
 32.3303 +				break;
 32.3304 +		cpuLowestBitSet[i] = j;
 32.3305 +	}
 32.3306 +
 32.3307 +	for (i = 0; i < 0x400; i++)
 32.3308 +		ioReadable[i] = true;
 32.3309 +	for (i = 0x10; i < 0x48; i++)
 32.3310 +		ioReadable[i] = false;
 32.3311 +	for (i = 0x4c; i < 0x50; i++)
 32.3312 +		ioReadable[i] = false;
 32.3313 +	for (i = 0x54; i < 0x60; i++)
 32.3314 +		ioReadable[i] = false;
 32.3315 +	for (i = 0x8c; i < 0x90; i++)
 32.3316 +		ioReadable[i] = false;
 32.3317 +	for (i = 0xa0; i < 0xb8; i++)
 32.3318 +		ioReadable[i] = false;
 32.3319 +	for (i = 0xbc; i < 0xc4; i++)
 32.3320 +		ioReadable[i] = false;
 32.3321 +	for (i = 0xc8; i < 0xd0; i++)
 32.3322 +		ioReadable[i] = false;
 32.3323 +	for (i = 0xd4; i < 0xdc; i++)
 32.3324 +		ioReadable[i] = false;
 32.3325 +	for (i = 0xe0; i < 0x100; i++)
 32.3326 +		ioReadable[i] = false;
 32.3327 +	for (i = 0x110; i < 0x120; i++)
 32.3328 +		ioReadable[i] = false;
 32.3329 +	for (i = 0x12c; i < 0x130; i++)
 32.3330 +		ioReadable[i] = false;
 32.3331 +	for (i = 0x138; i < 0x140; i++)
 32.3332 +		ioReadable[i] = false;
 32.3333 +	for (i = 0x144; i < 0x150; i++)
 32.3334 +		ioReadable[i] = false;
 32.3335 +	for (i = 0x15c; i < 0x200; i++)
 32.3336 +		ioReadable[i] = false;
 32.3337 +	for (i = 0x20c; i < 0x300; i++)
 32.3338 +		ioReadable[i] = false;
 32.3339 +	for (i = 0x304; i < 0x400; i++)
 32.3340 +		ioReadable[i] = false;
 32.3341 +
 32.3342 +	*((u16 *)&rom[0x1fe209c]) = 0xdffa;  // SWI 0xFA
 32.3343 +	*((u16 *)&rom[0x1fe209e]) = 0x4770;  // BX LR
 32.3344 +
 32.3345 +	{
 32.3346 +		int32 origMemoryWaitFetch[16]	= { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
 32.3347 +		int32 origMemoryWaitFetch32[16] = { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 };
 32.3348 +		memcpy(memoryWaitFetch, origMemoryWaitFetch, 16 * sizeof(int32));
 32.3349 +		memcpy(memoryWaitFetch32, origMemoryWaitFetch32, 16 * sizeof(int32));
 32.3350 +	}
 32.3351 +}
 32.3352 +
 32.3353 +void CPUReset(bool userReset)
 32.3354 +{
 32.3355 +	// movie must be closed while opening/creating a movie
 32.3356 +	if (userReset && VBAMovieRecording())
 32.3357 +	{
 32.3358 +		VBAMovieSignalReset();
 32.3359 +		return;
 32.3360 +	}
 32.3361 +
 32.3362 +	if (!VBAMovieActive())
 32.3363 +	{
 32.3364 +		GBASystemCounters.frameCount = 0;
 32.3365 +		GBASystemCounters.lagCount	 = 0;
 32.3366 +		GBASystemCounters.extraCount = 0;
 32.3367 +		GBASystemCounters.lagged	 = true;
 32.3368 +		GBASystemCounters.laggedLast = true;
 32.3369 +	}
 32.3370 +
 32.3371 +	if (gbaSaveType == 0)
 32.3372 +	{
 32.3373 +		if (eepromInUse)
 32.3374 +			gbaSaveType = 3;
 32.3375 +		else
 32.3376 +			switch (saveType)
 32.3377 +			{
 32.3378 +			case 1:
 32.3379 +				gbaSaveType = 1;
 32.3380 +				break;
 32.3381 +			case 2:
 32.3382 +				gbaSaveType = 2;
 32.3383 +				break;
 32.3384 +			}
 32.3385 +	}
 32.3386 +
 32.3387 +	rtcReset();
 32.3388 +	// clean registers
 32.3389 +	memset(&reg[0], 0, sizeof(reg));
 32.3390 +	// clean OAM
 32.3391 +	memset(oam, 0, 0x400);
 32.3392 +	// clean palette
 32.3393 +	memset(paletteRAM, 0, 0x400);
 32.3394 +	// clean picture
 32.3395 +	memset(pix, 0, 4 * 241 * 162);
 32.3396 +	// clean vram
 32.3397 +	memset(vram, 0, 0x20000);
 32.3398 +	// clean io memory
 32.3399 +	memset(ioMem, 0, 0x400);
 32.3400 +	// clean RAM
 32.3401 +	memset(internalRAM, 0, 0x8000); /// FIXME: is it unsafe to erase ALL of this? Even the init code doesn't.
 32.3402 +	memset(workRAM, 0, 0x40000); /// ditto
 32.3403 +
 32.3404 +	DISPCNT	 = 0x0080;
 32.3405 +	DISPSTAT = 0x0000;
 32.3406 +	VCOUNT	 = 0x0000;
 32.3407 +	BG0CNT	 = 0x0000;
 32.3408 +	BG1CNT	 = 0x0000;
 32.3409 +	BG2CNT	 = 0x0000;
 32.3410 +	BG3CNT	 = 0x0000;
 32.3411 +	BG0HOFS	 = 0x0000;
 32.3412 +	BG0VOFS	 = 0x0000;
 32.3413 +	BG1HOFS	 = 0x0000;
 32.3414 +	BG1VOFS	 = 0x0000;
 32.3415 +	BG2HOFS	 = 0x0000;
 32.3416 +	BG2VOFS	 = 0x0000;
 32.3417 +	BG3HOFS	 = 0x0000;
 32.3418 +	BG3VOFS	 = 0x0000;
 32.3419 +	BG2PA	 = 0x0100;
 32.3420 +	BG2PB	 = 0x0000;
 32.3421 +	BG2PC	 = 0x0000;
 32.3422 +	BG2PD	 = 0x0100;
 32.3423 +	BG2X_L	 = 0x0000;
 32.3424 +	BG2X_H	 = 0x0000;
 32.3425 +	BG2Y_L	 = 0x0000;
 32.3426 +	BG2Y_H	 = 0x0000;
 32.3427 +	BG3PA	 = 0x0100;
 32.3428 +	BG3PB	 = 0x0000;
 32.3429 +	BG3PC	 = 0x0000;
 32.3430 +	BG3PD	 = 0x0100;
 32.3431 +	BG3X_L	 = 0x0000;
 32.3432 +	BG3X_H	 = 0x0000;
 32.3433 +	BG3Y_L	 = 0x0000;
 32.3434 +	BG3Y_H	 = 0x0000;
 32.3435 +	WIN0H	 = 0x0000;
 32.3436 +	WIN1H	 = 0x0000;
 32.3437 +	WIN0V	 = 0x0000;
 32.3438 +	WIN1V	 = 0x0000;
 32.3439 +	WININ	 = 0x0000;
 32.3440 +	WINOUT	 = 0x0000;
 32.3441 +	MOSAIC	 = 0x0000;
 32.3442 +	BLDMOD	 = 0x0000;
 32.3443 +	COLEV	 = 0x0000;
 32.3444 +	COLY	 = 0x0000;
 32.3445 +	DM0SAD_L = 0x0000;
 32.3446 +	DM0SAD_H = 0x0000;
 32.3447 +	DM0DAD_L = 0x0000;
 32.3448 +	DM0DAD_H = 0x0000;
 32.3449 +	DM0CNT_L = 0x0000;
 32.3450 +	DM0CNT_H = 0x0000;
 32.3451 +	DM1SAD_L = 0x0000;
 32.3452 +	DM1SAD_H = 0x0000;
 32.3453 +	DM1DAD_L = 0x0000;
 32.3454 +	DM1DAD_H = 0x0000;
 32.3455 +	DM1CNT_L = 0x0000;
 32.3456 +	DM1CNT_H = 0x0000;
 32.3457 +	DM2SAD_L = 0x0000;
 32.3458 +	DM2SAD_H = 0x0000;
 32.3459 +	DM2DAD_L = 0x0000;
 32.3460 +	DM2DAD_H = 0x0000;
 32.3461 +	DM2CNT_L = 0x0000;
 32.3462 +	DM2CNT_H = 0x0000;
 32.3463 +	DM3SAD_L = 0x0000;
 32.3464 +	DM3SAD_H = 0x0000;
 32.3465 +	DM3DAD_L = 0x0000;
 32.3466 +	DM3DAD_H = 0x0000;
 32.3467 +	DM3CNT_L = 0x0000;
 32.3468 +	DM3CNT_H = 0x0000;
 32.3469 +	TM0D	 = 0x0000;
 32.3470 +	TM0CNT	 = 0x0000;
 32.3471 +	TM1D	 = 0x0000;
 32.3472 +	TM1CNT	 = 0x0000;
 32.3473 +	TM2D	 = 0x0000;
 32.3474 +	TM2CNT	 = 0x0000;
 32.3475 +	TM3D	 = 0x0000;
 32.3476 +	TM3CNT	 = 0x0000;
 32.3477 +	P1		 = 0x03FF;
 32.3478 +	IE		 = 0x0000;
 32.3479 +	IF		 = 0x0000;
 32.3480 +	IME		 = 0x0000;
 32.3481 +
 32.3482 +	armMode = 0x1F;
 32.3483 +
 32.3484 +	if (cpuIsMultiBoot)
 32.3485 +	{
 32.3486 +		reg[13].I	   = 0x03007F00;
 32.3487 +		reg[15].I	   = 0x02000000;
 32.3488 +		reg[16].I	   = 0x00000000;
 32.3489 +		reg[R13_IRQ].I = 0x03007FA0;
 32.3490 +		reg[R13_SVC].I = 0x03007FE0;
 32.3491 +		armIrqEnable   = true;
 32.3492 +	}
 32.3493 +	else
 32.3494 +	{
 32.3495 +		if (useBios && !skipBios)
 32.3496 +		{
 32.3497 +			reg[15].I	 = 0x00000000;
 32.3498 +			armMode		 = 0x13;
 32.3499 +			armIrqEnable = false;
 32.3500 +		}
 32.3501 +		else
 32.3502 +		{
 32.3503 +			reg[13].I	   = 0x03007F00;
 32.3504 +			reg[15].I	   = 0x08000000;
 32.3505 +			reg[16].I	   = 0x00000000;
 32.3506 +			reg[R13_IRQ].I = 0x03007FA0;
 32.3507 +			reg[R13_SVC].I = 0x03007FE0;
 32.3508 +			armIrqEnable   = true;
 32.3509 +		}
 32.3510 +	}
 32.3511 +	armState = true;
 32.3512 +	C_FLAG	 = V_FLAG = N_FLAG = Z_FLAG = false;
 32.3513 +	UPDATE_REG(0x00, DISPCNT);
 32.3514 +	UPDATE_REG(0x20, BG2PA);
 32.3515 +	UPDATE_REG(0x26, BG2PD);
 32.3516 +	UPDATE_REG(0x30, BG3PA);
 32.3517 +	UPDATE_REG(0x36, BG3PD);
 32.3518 +	UPDATE_REG(0x130, P1);
 32.3519 +	UPDATE_REG(0x88, 0x200);
 32.3520 +
 32.3521 +	// disable FIQ
 32.3522 +	reg[16].I |= 0x40;
 32.3523 +	CPUUpdateCPSR();
 32.3524 +
 32.3525 +	armNextPC  = reg[15].I;
 32.3526 +	reg[15].I += 4;
 32.3527 +
 32.3528 +	// reset internal state
 32.3529 +	holdState = false;
 32.3530 +	holdType  = 0;
 32.3531 +
 32.3532 +	biosProtected[0] = 0x00;
 32.3533 +	biosProtected[1] = 0xf0;
 32.3534 +	biosProtected[2] = 0x29;
 32.3535 +	biosProtected[3] = 0xe1;
 32.3536 +
 32.3537 +	BIOS_RegisterRamReset();
 32.3538 +
 32.3539 +	lcdTicks = 960;
 32.3540 +	timer0On = false;
 32.3541 +	timer0Ticks		  = 0;
 32.3542 +	timer0Reload	  = 0;
 32.3543 +	timer0ClockReload = 0;
 32.3544 +	timer1On		  = false;
 32.3545 +	timer1Ticks		  = 0;
 32.3546 +	timer1Reload	  = 0;
 32.3547 +	timer1ClockReload = 0;
 32.3548 +	timer2On		  = false;
 32.3549 +	timer2Ticks		  = 0;
 32.3550 +	timer2Reload	  = 0;
 32.3551 +	timer2ClockReload = 0;
 32.3552 +	timer3On		  = false;
 32.3553 +	timer3Ticks		  = 0;
 32.3554 +	timer3Reload	  = 0;
 32.3555 +	timer3ClockReload = 0;
 32.3556 +	dma0Source		  = 0;
 32.3557 +	dma0Dest		  = 0;
 32.3558 +	dma1Source		  = 0;
 32.3559 +	dma1Dest		  = 0;
 32.3560 +	dma2Source		  = 0;
 32.3561 +	dma2Dest		  = 0;
 32.3562 +	dma3Source		  = 0;
 32.3563 +	dma3Dest		  = 0;
 32.3564 +	cpuSaveGameFunc	  = flashSaveDecide;
 32.3565 +	renderLine		  = mode0RenderLine;
 32.3566 +	fxOn			  = false;
 32.3567 +	windowOn		  = false;
 32.3568 +	frameSkipCount	  = 0;
 32.3569 +	saveType		  = 0;
 32.3570 +	layerEnable		  = DISPCNT & layerSettings;
 32.3571 +
 32.3572 +	CPUUpdateRenderBuffers(true);
 32.3573 +
 32.3574 +	for (int i = 0; i < 256; i++)
 32.3575 +	{
 32.3576 +		map[i].address = (u8 *)&dummyAddress;
 32.3577 +		map[i].mask	   = 0;
 32.3578 +	}
 32.3579 +
 32.3580 +	map[0].address	= bios;
 32.3581 +	map[0].mask		= 0x3FFF;
 32.3582 +	map[2].address	= workRAM;
 32.3583 +	map[2].mask		= 0x3FFFF;
 32.3584 +	map[3].address	= internalRAM;
 32.3585 +	map[3].mask		= 0x7FFF;
 32.3586 +	map[4].address	= ioMem;
 32.3587 +	map[4].mask		= 0x3FF;
 32.3588 +	map[5].address	= paletteRAM;
 32.3589 +	map[5].mask		= 0x3FF;
 32.3590 +	map[6].address	= vram;
 32.3591 +	map[6].mask		= 0x1FFFF;
 32.3592 +	map[7].address	= oam;
 32.3593 +	map[7].mask		= 0x3FF;
 32.3594 +	map[8].address	= rom;
 32.3595 +	map[8].mask		= 0x1FFFFFF;
 32.3596 +	map[9].address	= rom;
 32.3597 +	map[9].mask		= 0x1FFFFFF;
 32.3598 +	map[10].address = rom;
 32.3599 +	map[10].mask	= 0x1FFFFFF;
 32.3600 +	map[12].address = rom;
 32.3601 +	map[12].mask	= 0x1FFFFFF;
 32.3602 +	map[14].address = flashSaveMemory;
 32.3603 +	map[14].mask	= 0xFFFF;
 32.3604 +
 32.3605 +	eepromReset();
 32.3606 +	flashReset();
 32.3607 +
 32.3608 +	soundReset();
 32.3609 +
 32.3610 +	CPUUpdateWindow0();
 32.3611 +	CPUUpdateWindow1();
 32.3612 +
 32.3613 +	// make sure registers are correctly initialized if not using BIOS
 32.3614 +	if (!useBios)
 32.3615 +	{
 32.3616 +		if (cpuIsMultiBoot)
 32.3617 +			BIOS_RegisterRamReset(0xfe);
 32.3618 +		else
 32.3619 +			BIOS_RegisterRamReset(0xff);
 32.3620 +	}
 32.3621 +	else
 32.3622 +	{
 32.3623 +		if (cpuIsMultiBoot)
 32.3624 +			BIOS_RegisterRamReset(0xfe);
 32.3625 +	}
 32.3626 +
 32.3627 +	switch (cpuSaveType)
 32.3628 +	{
 32.3629 +	case 0: // automatic
 32.3630 +		cpuSramEnabled		   = true;
 32.3631 +		cpuFlashEnabled		   = true;
 32.3632 +		cpuEEPROMEnabled	   = true;
 32.3633 +		cpuEEPROMSensorEnabled = false;
 32.3634 +		break;
 32.3635 +	case 1: // EEPROM
 32.3636 +		cpuSramEnabled		   = false;
 32.3637 +		cpuFlashEnabled		   = false;
 32.3638 +		cpuEEPROMEnabled	   = true;
 32.3639 +		cpuEEPROMSensorEnabled = false;
 32.3640 +		break;
 32.3641 +	case 2: // SRAM
 32.3642 +		cpuSramEnabled		   = true;
 32.3643 +		cpuFlashEnabled		   = false;
 32.3644 +		cpuEEPROMEnabled	   = false;
 32.3645 +		cpuEEPROMSensorEnabled = false;
 32.3646 +		cpuSaveGameFunc		   = sramWrite;
 32.3647 +		break;
 32.3648 +	case 3: // FLASH
 32.3649 +		cpuSramEnabled		   = false;
 32.3650 +		cpuFlashEnabled		   = true;
 32.3651 +		cpuEEPROMEnabled	   = false;
 32.3652 +		cpuEEPROMSensorEnabled = false;
 32.3653 +		cpuSaveGameFunc		   = flashWrite;
 32.3654 +		break;
 32.3655 +	case 4: // EEPROM+Sensor
 32.3656 +		cpuSramEnabled		   = false;
 32.3657 +		cpuFlashEnabled		   = false;
 32.3658 +		cpuEEPROMEnabled	   = true;
 32.3659 +		cpuEEPROMSensorEnabled = true;
 32.3660 +		break;
 32.3661 +	case 5: // NONE
 32.3662 +		cpuSramEnabled		   = false;
 32.3663 +		cpuFlashEnabled		   = false;
 32.3664 +		cpuEEPROMEnabled	   = false;
 32.3665 +		cpuEEPROMSensorEnabled = false;
 32.3666 +		break;
 32.3667 +	}
 32.3668 +
 32.3669 +	systemResetSensor();
 32.3670 +
 32.3671 +	systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
 32.3672 +
 32.3673 +	gbaLastTime	  = systemGetClock();
 32.3674 +	gbaFrameCount = 0;
 32.3675 +
 32.3676 +	systemRefreshScreen();
 32.3677 +}
 32.3678 +
 32.3679 +void CPUInterrupt()
 32.3680 +{
 32.3681 +	u32	 PC			= reg[15].I;
 32.3682 +	bool savedState = armState;
 32.3683 +	CPUSwitchMode(0x12, true, false);
 32.3684 +	reg[14].I = PC;
 32.3685 +	if (!savedState)
 32.3686 +		reg[14].I += 2;
 32.3687 +	reg[15].I	 = 0x18;
 32.3688 +	armState	 = true;
 32.3689 +	armIrqEnable = false;
 32.3690 +
 32.3691 +	armNextPC  = reg[15].I;
 32.3692 +	reg[15].I += 4;
 32.3693 +
 32.3694 +	//  if(!holdState)
 32.3695 +	biosProtected[0] = 0x02;
 32.3696 +	biosProtected[1] = 0xc0;
 32.3697 +	biosProtected[2] = 0x5e;
 32.3698 +	biosProtected[3] = 0xe5;
 32.3699 +}
 32.3700 +
 32.3701 +void TogglePrefetchHack()
 32.3702 +{
 32.3703 +	memLagTempEnabled = !memLagTempEnabled;
 32.3704 +
 32.3705 +	if (emulating)
 32.3706 +	{
 32.3707 +		extern bool8 prefetchActive, prefetchPrevActive, prefetchApplies;
 32.3708 +		if (prefetchApplies && prefetchActive == memLagTempEnabled)
 32.3709 +		{
 32.3710 +			prefetchActive = !prefetchActive;
 32.3711 +			//if(prefetchActive && !prefetchPrevActive) systemScreenMessage("pre-fetch enabled",3,600);
 32.3712 +			//if(!prefetchActive && prefetchPrevActive) systemScreenMessage("pre-fetch disabled",3,600);
 32.3713 +			extern int32 memoryWaitFetch [16];
 32.3714 +			if (prefetchActive)
 32.3715 +				memoryWaitFetch[8]--;
 32.3716 +			else
 32.3717 +				memoryWaitFetch[8]++;
 32.3718 +			prefetchPrevActive = prefetchActive;
 32.3719 +		}
 32.3720 +	}
 32.3721 +}
 32.3722 +
 32.3723 +void SetPrefetchHack(bool set)
 32.3724 +{
 32.3725 +	if ((bool)memLagTempEnabled == set)
 32.3726 +		TogglePrefetchHack();
 32.3727 +}
 32.3728 +
 32.3729 +#ifdef SDL
 32.3730 +void log(const char *defaultMsg, ...)
 32.3731 +{
 32.3732 +	char	buffer[2048];
 32.3733 +	va_list valist;
 32.3734 +
 32.3735 +	va_start(valist, defaultMsg);
 32.3736 +	vsprintf(buffer, defaultMsg, valist);
 32.3737 +
 32.3738 +	if (out == NULL)
 32.3739 +	{
 32.3740 +		out = fopen("trace.log", "w");
 32.3741 +	}
 32.3742 +
 32.3743 +	fputs(buffer, out);
 32.3744 +
 32.3745 +	va_end(valist);
 32.3746 +}
 32.3747 +
 32.3748 +#else
 32.3749 +extern void winlog(const char *, ...);
 32.3750 +#endif
 32.3751 +
 32.3752 +void CPULoop(int _ticks)
 32.3753 +{
 32.3754 +	int32 ticks = _ticks;
 32.3755 +	int32 clockTicks;
 32.3756 +	int32 cpuLoopTicks	= 0;
 32.3757 +	int32 timerOverflow = 0;
 32.3758 +	// variables used by the CPU core
 32.3759 +
 32.3760 +	extCpuLoopTicks = &cpuLoopTicks;
 32.3761 +	extClockTicks	= &clockTicks;
 32.3762 +	extTicks		= &ticks;
 32.3763 +
 32.3764 +	cpuLoopTicks = CPUUpdateTicks();
 32.3765 +	if (cpuLoopTicks > ticks)
 32.3766 +	{
 32.3767 +		cpuLoopTicks  = ticks;
 32.3768 +		cpuSavedTicks = ticks;
 32.3769 +	}
 32.3770 +
 32.3771 +	if (intState)
 32.3772 +	{
 32.3773 +		cpuLoopTicks  = 5;
 32.3774 +		cpuSavedTicks = 5;
 32.3775 +	}
 32.3776 +
 32.3777 +	if (newFrame)
 32.3778 +	{
 32.3779 +		extern void VBAOnExitingFrameBoundary();
 32.3780 +		VBAOnExitingFrameBoundary();
 32.3781 +
 32.3782 +		// update joystick information
 32.3783 +		systemReadJoypads();
 32.3784 +
 32.3785 +		u32 joy = systemGetJoypad(0, cpuEEPROMSensorEnabled);
 32.3786 +
 32.3787 +//		if (cpuEEPROMSensorEnabled)
 32.3788 +//			systemUpdateMotionSensor(0);
 32.3789 +
 32.3790 +		P1 = 0x03FF ^ (joy & 0x3FF);
 32.3791 +		UPDATE_REG(0x130, P1);
 32.3792 +		u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132]));
 32.3793 +		// this seems wrong, but there are cases where the game
 32.3794 +		// can enter the stop state without requesting an IRQ from
 32.3795 +		// the joypad.
 32.3796 +		if ((P1CNT & 0x4000) || stopState)
 32.3797 +		{
 32.3798 +			u16 p1 = (0x3FF ^ P1) & 0x3FF;
 32.3799 +			if (P1CNT & 0x8000)
 32.3800 +			{
 32.3801 +				if (p1 == (P1CNT & 0x3FF))
 32.3802 +				{
 32.3803 +					IF |= 0x1000;
 32.3804 +					UPDATE_REG(0x202, IF);
 32.3805 +				}
 32.3806 +			}
 32.3807 +			else
 32.3808 +			{
 32.3809 +				if (p1 & P1CNT)
 32.3810 +				{
 32.3811 +					IF |= 0x1000;
 32.3812 +					UPDATE_REG(0x202, IF);
 32.3813 +				}
 32.3814 +			}
 32.3815 +		}
 32.3816 +
 32.3817 +		// HACK: some special "buttons"
 32.3818 +		extButtons = (joy >> 18);
 32.3819 +		speedup	   = (extButtons & 1) != 0;
 32.3820 +
 32.3821 +		VBAMovieResetIfRequested();
 32.3822 +
 32.3823 +		CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION);
 32.3824 +
 32.3825 +		newFrame = false;
 32.3826 +	}
 32.3827 +
 32.3828 +	for (;; )
 32.3829 +	{
 32.3830 +#ifndef FINAL_VERSION
 32.3831 +		if (systemDebug)
 32.3832 +		{
 32.3833 +			if (systemDebug >= 10 && !holdState)
 32.3834 +			{
 32.3835 +				CPUUpdateCPSR();
 32.3836 +				sprintf(
 32.3837 +				    buffer,
 32.3838 +				    "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x"
 32.3839 +				    "R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
 32.3840 +				    reg[0].I,
 32.3841 +				    reg[1].I,
 32.3842 +				    reg[2].I,
 32.3843 +				    reg[3].I,
 32.3844 +				    reg[4].I,
 32.3845 +				    reg[5].I,
 32.3846 +				    reg[6].I,
 32.3847 +				    reg[7].I,
 32.3848 +				    reg[8].I,
 32.3849 +				    reg[9].I,
 32.3850 +				    reg[10].I,
 32.3851 +				    reg[11].I,
 32.3852 +				    reg[12].I,
 32.3853 +				    reg[13].I,
 32.3854 +				    reg[14].I,
 32.3855 +				    reg[15].I,
 32.3856 +				    reg[16].I,
 32.3857 +				    reg[17].I);
 32.3858 +#ifdef SDL
 32.3859 +				log(buffer);
 32.3860 +#else
 32.3861 +				winlog(buffer);
 32.3862 +#endif
 32.3863 +			}
 32.3864 +			else if (!holdState)
 32.3865 +			{
 32.3866 +				sprintf(buffer, "PC=%08x\n", armNextPC);
 32.3867 +#ifdef SDL
 32.3868 +				log(buffer);
 32.3869 +#else
 32.3870 +				winlog(buffer);
 32.3871 +#endif
 32.3872 +			}
 32.3873 +		}
 32.3874 +#endif
 32.3875 +
 32.3876 +		if (!holdState)
 32.3877 +		{
 32.3878 +			if (armState)
 32.3879 +			{
 32.3880 +				CallRegisteredLuaMemHook(armNextPC, 4, CPUReadMemoryQuick(armNextPC), LUAMEMHOOK_EXEC);
 32.3881 +#include "arm-new.h"
 32.3882 +			}
 32.3883 +			else
 32.3884 +			{
 32.3885 +				CallRegisteredLuaMemHook(armNextPC, 2, CPUReadHalfWordQuick(armNextPC), LUAMEMHOOK_EXEC);
 32.3886 +#include "thumb.h"
 32.3887 +			}
 32.3888 +		}
 32.3889 +		else
 32.3890 +		{
 32.3891 +			clockTicks = lcdTicks;
 32.3892 +
 32.3893 +			if (soundTicks < clockTicks)
 32.3894 +				clockTicks = soundTicks;
 32.3895 +
 32.3896 +			if (timer0On && (timer0Ticks < clockTicks))
 32.3897 +			{
 32.3898 +				clockTicks = timer0Ticks;
 32.3899 +			}
 32.3900 +			if (timer1On && (timer1Ticks < clockTicks))
 32.3901 +			{
 32.3902 +				clockTicks = timer1Ticks;
 32.3903 +			}
 32.3904 +			if (timer2On && (timer2Ticks < clockTicks))
 32.3905 +			{
 32.3906 +				clockTicks = timer2Ticks;
 32.3907 +			}
 32.3908 +			if (timer3On && (timer3Ticks < clockTicks))
 32.3909 +			{
 32.3910 +				clockTicks = timer3Ticks;
 32.3911 +			}
 32.3912 +#ifdef PROFILING
 32.3913 +			if (profilingTicksReload != 0)
 32.3914 +			{
 32.3915 +				if (profilingTicks < clockTicks)
 32.3916 +				{
 32.3917 +					clockTicks = profilingTicks;
 32.3918 +				}
 32.3919 +			}
 32.3920 +#endif
 32.3921 +		}
 32.3922 +
 32.3923 +		cpuLoopTicks -= clockTicks;
 32.3924 +		if ((cpuLoopTicks <= 0))
 32.3925 +		{
 32.3926 +			if (cpuSavedTicks)
 32.3927 +			{
 32.3928 +				clockTicks = cpuSavedTicks; // + cpuLoopTicks;
 32.3929 +			}
 32.3930 +			cpuDmaTicksToUpdate = -cpuLoopTicks;
 32.3931 +
 32.3932 +updateLoop:
 32.3933 +			lcdTicks -= clockTicks;
 32.3934 +
 32.3935 +			if (lcdTicks <= 0)
 32.3936 +			{
 32.3937 +				if (DISPSTAT & 1) // V-BLANK
 32.3938 +				{ // if in V-Blank mode, keep computing...
 32.3939 +					if (DISPSTAT & 2)
 32.3940 +					{
 32.3941 +						lcdTicks += 960;
 32.3942 +						VCOUNT++;
 32.3943 +						UPDATE_REG(0x06, VCOUNT);
 32.3944 +						DISPSTAT &= 0xFFFD;
 32.3945 +						UPDATE_REG(0x04, DISPSTAT);
 32.3946 +						CPUCompareVCOUNT();
 32.3947 +					}
 32.3948 +					else
 32.3949 +					{
 32.3950 +						lcdTicks += 272;
 32.3951 +						DISPSTAT |= 2;
 32.3952 +						UPDATE_REG(0x04, DISPSTAT);
 32.3953 +						if (DISPSTAT & 16)
 32.3954 +						{
 32.3955 +							IF |= 2;
 32.3956 +							UPDATE_REG(0x202, IF);
 32.3957 +						}
 32.3958 +					}
 32.3959 +
 32.3960 +					if (VCOUNT >= 228)
 32.3961 +					{
 32.3962 +						DISPSTAT &= 0xFFFC;
 32.3963 +						UPDATE_REG(0x04, DISPSTAT);
 32.3964 +						VCOUNT = 0;
 32.3965 +						UPDATE_REG(0x06, VCOUNT);
 32.3966 +						CPUCompareVCOUNT();
 32.3967 +					}
 32.3968 +				}
 32.3969 +				else
 32.3970 +				{
 32.3971 +					int framesToSkip = systemFramesToSkip();
 32.3972 +
 32.3973 +					if (DISPSTAT & 2)
 32.3974 +					{
 32.3975 +						// if in H-Blank, leave it and move to drawing mode
 32.3976 +						VCOUNT++;
 32.3977 +						UPDATE_REG(0x06, VCOUNT);
 32.3978 +
 32.3979 +						lcdTicks += 960;
 32.3980 +						DISPSTAT &= 0xFFFD;
 32.3981 +						if (VCOUNT == 160)
 32.3982 +						{
 32.3983 +							DISPSTAT |= 1;
 32.3984 +							DISPSTAT &= 0xFFFD;
 32.3985 +							UPDATE_REG(0x04, DISPSTAT);
 32.3986 +							if (DISPSTAT & 0x0008)
 32.3987 +							{
 32.3988 +								IF |= 1;
 32.3989 +								UPDATE_REG(0x202, IF);
 32.3990 +							}
 32.3991 +							CPUCheckDMA(1, 0x0f);
 32.3992 +
 32.3993 +							systemFrame();
 32.3994 +
 32.3995 +							++gbaFrameCount;
 32.3996 +							u32 gbaCurrentTime = systemGetClock();
 32.3997 +							if (gbaCurrentTime - gbaLastTime >= 1000)
 32.3998 +							{
 32.3999 +								systemShowSpeed(int(float(gbaFrameCount) * 100000 / (float(gbaCurrentTime - gbaLastTime) * 60) + .5f));
 32.4000 +								gbaLastTime	  = gbaCurrentTime;
 32.4001 +								gbaFrameCount = 0;
 32.4002 +							}
 32.4003 +
 32.4004 +							++GBASystemCounters.frameCount;
 32.4005 +							if (GBASystemCounters.lagged)
 32.4006 +							{
 32.4007 +								++GBASystemCounters.lagCount;
 32.4008 +							}
 32.4009 +							GBASystemCounters.laggedLast = GBASystemCounters.lagged;
 32.4010 +							GBASystemCounters.lagged	 = true;
 32.4011 +
 32.4012 +							if (cheatsEnabled)
 32.4013 +								cheatsCheckKeys(P1 ^ 0x3FF, extButtons);
 32.4014 +
 32.4015 +							extern void VBAOnEnteringFrameBoundary();
 32.4016 +							VBAOnEnteringFrameBoundary();
 32.4017 +
 32.4018 +							newFrame = true;
 32.4019 +
 32.4020 +							pauseAfterFrameAdvance = systemPauseOnFrame();
 32.4021 +
 32.4022 +							if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance)
 32.4023 +							{
 32.4024 +								systemRenderFrame();
 32.4025 +								frameSkipCount = 0;
 32.4026 +
 32.4027 +								bool capturePressed = (extButtons & 2) != 0;
 32.4028 +								if (capturePressed && !capturePrevious)
 32.4029 +								{
 32.4030 +									captureNumber = systemScreenCapture(captureNumber);
 32.4031 +								}
 32.4032 +								capturePrevious = capturePressed && !pauseAfterFrameAdvance;
 32.4033 +							}
 32.4034 +							else
 32.4035 +							{
 32.4036 +								++frameSkipCount;
 32.4037 +							}
 32.4038 +
 32.4039 +							if (pauseAfterFrameAdvance)
 32.4040 +							{
 32.4041 +								systemSetPause(true);
 32.4042 +							}
 32.4043 +						}
 32.4044 +
 32.4045 +						UPDATE_REG(0x04, DISPSTAT);
 32.4046 +						CPUCompareVCOUNT();
 32.4047 +					}
 32.4048 +					else
 32.4049 +					{
 32.4050 +						if (frameSkipCount >= framesToSkip || pauseAfterFrameAdvance)
 32.4051 +						{
 32.4052 +							(*renderLine)();
 32.4053 +
 32.4054 +							switch (systemColorDepth)
 32.4055 +							{
 32.4056 +							case 16:
 32.4057 +							{
 32.4058 +								u16 *dest = (u16 *)pix + 242 * (VCOUNT + 1);
 32.4059 +								for (int x = 0; x < 240; )
 32.4060 +								{
 32.4061 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4062 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4063 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4064 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4065 +
 32.4066 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4067 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4068 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4069 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4070 +
 32.4071 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4072 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4073 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4074 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4075 +
 32.4076 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4077 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4078 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4079 +									*dest++ = systemColorMap16[lineMix[x++] & 0xFFFF];
 32.4080 +								}
 32.4081 +								// for filters that read past the screen
 32.4082 +								*dest++ = 0;
 32.4083 +								break;
 32.4084 +							}
 32.4085 +							case 24:
 32.4086 +							{
 32.4087 +								u8 *dest = (u8 *)pix + 240 * VCOUNT * 3;
 32.4088 +								for (int x = 0; x < 240; )
 32.4089 +								{
 32.4090 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4091 +									dest += 3;
 32.4092 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4093 +									dest += 3;
 32.4094 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4095 +									dest += 3;
 32.4096 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4097 +									dest += 3;
 32.4098 +
 32.4099 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4100 +									dest += 3;
 32.4101 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4102 +									dest += 3;
 32.4103 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4104 +									dest += 3;
 32.4105 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4106 +									dest += 3;
 32.4107 +
 32.4108 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4109 +									dest += 3;
 32.4110 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4111 +									dest += 3;
 32.4112 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4113 +									dest += 3;
 32.4114 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4115 +									dest += 3;
 32.4116 +
 32.4117 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4118 +									dest += 3;
 32.4119 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4120 +									dest += 3;
 32.4121 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4122 +									dest += 3;
 32.4123 +									*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4124 +									dest += 3;
 32.4125 +								}
 32.4126 +								break;
 32.4127 +							}
 32.4128 +							case 32:
 32.4129 +							{
 32.4130 +								u32 *dest = (u32 *)pix + 241 * (VCOUNT + 1);
 32.4131 +								for (int x = 0; x < 240; )
 32.4132 +								{
 32.4133 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4134 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4135 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4136 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4137 +
 32.4138 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4139 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4140 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4141 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4142 +
 32.4143 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4144 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4145 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4146 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4147 +
 32.4148 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4149 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4150 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4151 +									*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
 32.4152 +								}
 32.4153 +								break;
 32.4154 +							}
 32.4155 +							}
 32.4156 +						}
 32.4157 +						// entering H-Blank
 32.4158 +						DISPSTAT |= 2;
 32.4159 +						UPDATE_REG(0x04, DISPSTAT);
 32.4160 +						lcdTicks += 272;
 32.4161 +						CPUCheckDMA(2, 0x0f);
 32.4162 +						if (DISPSTAT & 16)
 32.4163 +						{
 32.4164 +							IF |= 2;
 32.4165 +							UPDATE_REG(0x202, IF);
 32.4166 +						}
 32.4167 +					}
 32.4168 +				}
 32.4169 +			}
 32.4170 +
 32.4171 +			if (!stopState)
 32.4172 +			{
 32.4173 +				if (timer0On)
 32.4174 +				{
 32.4175 +					if (timer0ClockReload == 1)
 32.4176 +					{
 32.4177 +						u32 tm0d = TM0D + clockTicks;
 32.4178 +						if (tm0d > 0xffff)
 32.4179 +						{
 32.4180 +							tm0d += timer0Reload;
 32.4181 +							timerOverflow |= 1;
 32.4182 +							soundTimerOverflow(0);
 32.4183 +							if (TM0CNT & 0x40)
 32.4184 +							{
 32.4185 +								IF |= 0x08;
 32.4186 +								UPDATE_REG(0x202, IF);
 32.4187 +							}
 32.4188 +						}
 32.4189 +						TM0D		= tm0d & 0xFFFF;
 32.4190 +						timer0Ticks = 0x10000 - TM0D;
 32.4191 +						UPDATE_REG(0x100, TM0D);
 32.4192 +					}
 32.4193 +					else
 32.4194 +					{
 32.4195 +						timer0Ticks -= clockTicks;
 32.4196 +						if (timer0Ticks <= 0)
 32.4197 +						{
 32.4198 +							timer0Ticks += timer0ClockReload;
 32.4199 +							TM0D++;
 32.4200 +							if (TM0D == 0)
 32.4201 +							{
 32.4202 +								TM0D = timer0Reload;
 32.4203 +								timerOverflow |= 1;
 32.4204 +								soundTimerOverflow(0);
 32.4205 +								if (TM0CNT & 0x40)
 32.4206 +								{
 32.4207 +									IF |= 0x08;
 32.4208 +									UPDATE_REG(0x202, IF);
 32.4209 +								}
 32.4210 +							}
 32.4211 +							UPDATE_REG(0x100, TM0D);
 32.4212 +						}
 32.4213 +					}
 32.4214 +				}
 32.4215 +
 32.4216 +				if (timer1On)
 32.4217 +				{
 32.4218 +					if (TM1CNT & 4)
 32.4219 +					{
 32.4220 +						if (timerOverflow & 1)
 32.4221 +						{
 32.4222 +							TM1D++;
 32.4223 +							if (TM1D == 0)
 32.4224 +							{
 32.4225 +								TM1D += timer1Reload;
 32.4226 +								timerOverflow |= 2;
 32.4227 +								soundTimerOverflow(1);
 32.4228 +								if (TM1CNT & 0x40)
 32.4229 +								{
 32.4230 +									IF |= 0x10;
 32.4231 +									UPDATE_REG(0x202, IF);
 32.4232 +								}
 32.4233 +							}
 32.4234 +							UPDATE_REG(0x104, TM1D);
 32.4235 +						}
 32.4236 +					}
 32.4237 +					else
 32.4238 +					{
 32.4239 +						if (timer1ClockReload == 1)
 32.4240 +						{
 32.4241 +							u32 tm1d = TM1D + clockTicks;
 32.4242 +							if (tm1d > 0xffff)
 32.4243 +							{
 32.4244 +								tm1d += timer1Reload;
 32.4245 +								timerOverflow |= 2;
 32.4246 +								soundTimerOverflow(1);
 32.4247 +								if (TM1CNT & 0x40)
 32.4248 +								{
 32.4249 +									IF |= 0x10;
 32.4250 +									UPDATE_REG(0x202, IF);
 32.4251 +								}
 32.4252 +							}
 32.4253 +							TM1D		= tm1d & 0xFFFF;
 32.4254 +							timer1Ticks = 0x10000 - TM1D;
 32.4255 +							UPDATE_REG(0x104, TM1D);
 32.4256 +						}
 32.4257 +						else
 32.4258 +						{
 32.4259 +							timer1Ticks -= clockTicks;
 32.4260 +							if (timer1Ticks <= 0)
 32.4261 +							{
 32.4262 +								timer1Ticks += timer1ClockReload;
 32.4263 +								TM1D++;
 32.4264 +
 32.4265 +								if (TM1D == 0)
 32.4266 +								{
 32.4267 +									TM1D = timer1Reload;
 32.4268 +									timerOverflow |= 2;
 32.4269 +									soundTimerOverflow(1);
 32.4270 +									if (TM1CNT & 0x40)
 32.4271 +									{
 32.4272 +										IF |= 0x10;
 32.4273 +										UPDATE_REG(0x202, IF);
 32.4274 +									}
 32.4275 +								}
 32.4276 +								UPDATE_REG(0x104, TM1D);
 32.4277 +							}
 32.4278 +						}
 32.4279 +					}
 32.4280 +				}
 32.4281 +
 32.4282 +				if (timer2On)
 32.4283 +				{
 32.4284 +					if (TM2CNT & 4)
 32.4285 +					{
 32.4286 +						if (timerOverflow & 2)
 32.4287 +						{
 32.4288 +							TM2D++;
 32.4289 +							if (TM2D == 0)
 32.4290 +							{
 32.4291 +								TM2D += timer2Reload;
 32.4292 +								timerOverflow |= 4;
 32.4293 +								if (TM2CNT & 0x40)
 32.4294 +								{
 32.4295 +									IF |= 0x20;
 32.4296 +									UPDATE_REG(0x202, IF);
 32.4297 +								}
 32.4298 +							}
 32.4299 +							UPDATE_REG(0x108, TM2D);
 32.4300 +						}
 32.4301 +					}
 32.4302 +					else
 32.4303 +					{
 32.4304 +						if (timer2ClockReload == 1)
 32.4305 +						{
 32.4306 +							u32 tm2d = TM2D + clockTicks;
 32.4307 +							if (tm2d > 0xffff)
 32.4308 +							{
 32.4309 +								tm2d += timer2Reload;
 32.4310 +								timerOverflow |= 4;
 32.4311 +								if (TM2CNT & 0x40)
 32.4312 +								{
 32.4313 +									IF |= 0x20;
 32.4314 +									UPDATE_REG(0x202, IF);
 32.4315 +								}
 32.4316 +							}
 32.4317 +							TM2D		= tm2d & 0xFFFF;
 32.4318 +							timer2Ticks = 0x10000 - TM2D;
 32.4319 +							UPDATE_REG(0x108, TM2D);
 32.4320 +						}
 32.4321 +						else
 32.4322 +						{
 32.4323 +							timer2Ticks -= clockTicks;
 32.4324 +							if (timer2Ticks <= 0)
 32.4325 +							{
 32.4326 +								timer2Ticks += timer2ClockReload;
 32.4327 +								TM2D++;
 32.4328 +
 32.4329 +								if (TM2D == 0)
 32.4330 +								{
 32.4331 +									TM2D = timer2Reload;
 32.4332 +									timerOverflow |= 4;
 32.4333 +									if (TM2CNT & 0x40)
 32.4334 +									{
 32.4335 +										IF |= 0x20;
 32.4336 +										UPDATE_REG(0x202, IF);
 32.4337 +									}
 32.4338 +								}
 32.4339 +								UPDATE_REG(0x108, TM2D);
 32.4340 +							}
 32.4341 +						}
 32.4342 +					}
 32.4343 +				}
 32.4344 +
 32.4345 +				if (timer3On)
 32.4346 +				{
 32.4347 +					if (TM3CNT & 4)
 32.4348 +					{
 32.4349 +						if (timerOverflow & 4)
 32.4350 +						{
 32.4351 +							TM3D++;
 32.4352 +							if (TM3D == 0)
 32.4353 +							{
 32.4354 +								TM3D += timer3Reload;
 32.4355 +								if (TM3CNT & 0x40)
 32.4356 +								{
 32.4357 +									IF |= 0x40;
 32.4358 +									UPDATE_REG(0x202, IF);
 32.4359 +								}
 32.4360 +							}
 32.4361 +							UPDATE_REG(0x10c, TM3D);
 32.4362 +						}
 32.4363 +					}
 32.4364 +					else
 32.4365 +					{
 32.4366 +						if (timer3ClockReload == 1)
 32.4367 +						{
 32.4368 +							u32 tm3d = TM3D + clockTicks;
 32.4369 +							if (tm3d > 0xffff)
 32.4370 +							{
 32.4371 +								tm3d += timer3Reload;
 32.4372 +								if (TM3CNT & 0x40)
 32.4373 +								{
 32.4374 +									IF |= 0x40;
 32.4375 +									UPDATE_REG(0x202, IF);
 32.4376 +								}
 32.4377 +							}
 32.4378 +							TM3D		= tm3d & 0xFFFF;
 32.4379 +							timer3Ticks = 0x10000 - TM3D;
 32.4380 +							UPDATE_REG(0x10C, TM3D);
 32.4381 +						}
 32.4382 +						else
 32.4383 +						{
 32.4384 +							timer3Ticks -= clockTicks;
 32.4385 +							if (timer3Ticks <= 0)
 32.4386 +							{
 32.4387 +								timer3Ticks += timer3ClockReload;
 32.4388 +								TM3D++;
 32.4389 +
 32.4390 +								if (TM3D == 0)
 32.4391 +								{
 32.4392 +									TM3D = timer3Reload;
 32.4393 +									if (TM3CNT & 0x40)
 32.4394 +									{
 32.4395 +										IF |= 0x40;
 32.4396 +										UPDATE_REG(0x202, IF);
 32.4397 +									}
 32.4398 +								}
 32.4399 +								UPDATE_REG(0x10C, TM3D);
 32.4400 +							}
 32.4401 +						}
 32.4402 +					}
 32.4403 +				}
 32.4404 +			}
 32.4405 +			// we shouldn't be doing sound in stop state, but we lose synchronization
 32.4406 +			// if sound is disabled, so in stop state, soundTick will just produce
 32.4407 +			// mute sound
 32.4408 +			soundTicks -= clockTicks;
 32.4409 +			if (soundTicks < 1)
 32.4410 +			{
 32.4411 +				soundTick();
 32.4412 +				soundTicks += SOUND_CLOCK_TICKS;
 32.4413 +			}
 32.4414 +			timerOverflow = 0;
 32.4415 +
 32.4416 +#ifdef PROFILING
 32.4417 +			profilingTicks -= clockTicks;
 32.4418 +			if (profilingTicks <= 0)
 32.4419 +			{
 32.4420 +				profilingTicks += profilingTicksReload;
 32.4421 +				if (profilBuffer && profilSize)
 32.4422 +				{
 32.4423 +					u16 *b	= (u16 *)profilBuffer;
 32.4424 +					int	 pc = ((reg[15].I - profilLowPC) * profilScale) / 0x10000;
 32.4425 +					if (pc >= 0 && pc < profilSize)
 32.4426 +					{
 32.4427 +						b[pc]++;
 32.4428 +					}
 32.4429 +				}
 32.4430 +			}
 32.4431 +#endif
 32.4432 +
 32.4433 +			ticks		-= clockTicks;
 32.4434 +			cpuLoopTicks = CPUUpdateTicks();
 32.4435 +
 32.4436 +			// FIXME: it is too bad that it is still not determined whether the loop can be exited at this point
 32.4437 +			if (cpuDmaTicksToUpdate > 0)
 32.4438 +			{
 32.4439 +				clockTicks = cpuSavedTicks;
 32.4440 +				if (clockTicks > cpuDmaTicksToUpdate)
 32.4441 +					clockTicks = cpuDmaTicksToUpdate;
 32.4442 +				cpuDmaTicksToUpdate -= clockTicks;
 32.4443 +				if (cpuDmaTicksToUpdate < 0)
 32.4444 +					cpuDmaTicksToUpdate = 0;
 32.4445 +				goto updateLoop;    // this is evil
 32.4446 +			}
 32.4447 +
 32.4448 +			if (IF && (IME & 1) && armIrqEnable)
 32.4449 +			{
 32.4450 +				int res = IF & IE;
 32.4451 +				if (stopState)
 32.4452 +					res &= 0x3080;
 32.4453 +				if (res)
 32.4454 +				{
 32.4455 +					if (intState)
 32.4456 +					{
 32.4457 +						CPUInterrupt();
 32.4458 +						intState = false;
 32.4459 +						if (holdState)
 32.4460 +						{
 32.4461 +							holdState = false;
 32.4462 +							stopState = false;
 32.4463 +						}
 32.4464 +					}
 32.4465 +					else
 32.4466 +					{
 32.4467 +						if (!holdState)
 32.4468 +						{
 32.4469 +							intState	  = true;
 32.4470 +							cpuLoopTicks  = 5;
 32.4471 +							cpuSavedTicks = 5;
 32.4472 +						}
 32.4473 +						else
 32.4474 +						{
 32.4475 +							CPUInterrupt();
 32.4476 +							if (holdState)
 32.4477 +							{
 32.4478 +								holdState = false;
 32.4479 +								stopState = false;
 32.4480 +							}
 32.4481 +						}
 32.4482 +					}
 32.4483 +				}
 32.4484 +			}
 32.4485 +
 32.4486 +			if (useOldFrameTiming)
 32.4487 +			{
 32.4488 +				if (ticks <= 0)
 32.4489 +				{
 32.4490 +					newFrame = true;
 32.4491 +					break;
 32.4492 +				}
 32.4493 +			}
 32.4494 +			else if (newFrame)
 32.4495 +			{
 32.4496 +				// FIXME: it should be enough to use frameBoundary only if there were no need for supporting the old timing
 32.4497 +				// but is there still any GBA .vbm that uses the old timing?
 32.4498 +///				extern void VBAOnEnteringFrameBoundary();
 32.4499 +///				VBAOnEnteringFrameBoundary();
 32.4500 +
 32.4501 +				break;
 32.4502 +			}
 32.4503 +		}
 32.4504 +	}
 32.4505 +}
 32.4506 +
 32.4507 +struct EmulatedSystem GBASystem =
 32.4508 +{
 32.4509 +	// emuMain
 32.4510 +	CPULoop,
 32.4511 +	// emuReset
 32.4512 +	CPUReset,
 32.4513 +	// emuCleanUp
 32.4514 +	CPUCleanUp,
 32.4515 +	// emuReadBattery
 32.4516 +	CPUReadBatteryFile,
 32.4517 +	// emuWriteBattery
 32.4518 +	CPUWriteBatteryFile,
 32.4519 +	// emuReadBatteryFromStream
 32.4520 +	CPUReadBatteryFromStream,
 32.4521 +	// emuWriteBatteryToStream
 32.4522 +	CPUWriteBatteryToStream,
 32.4523 +	// emuReadState
 32.4524 +	CPUReadState,
 32.4525 +	// emuWriteState
 32.4526 +	CPUWriteState,
 32.4527 +	// emuReadStateFromStream
 32.4528 +	CPUReadStateFromStream,
 32.4529 +	// emuWriteStateToStream
 32.4530 +	CPUWriteStateToStream,
 32.4531 +	// emuReadMemState
 32.4532 +	CPUReadMemState,
 32.4533 +	// emuWriteMemState
 32.4534 +	CPUWriteMemState,
 32.4535 +	// emuWritePNG
 32.4536 +	CPUWritePNGFile,
 32.4537 +	// emuWriteBMP
 32.4538 +	CPUWriteBMPFile,
 32.4539 +	// emuUpdateCPSR
 32.4540 +	CPUUpdateCPSR,
 32.4541 +	// emuHasDebugger
 32.4542 +	true,
 32.4543 +	// emuCount
 32.4544 +#ifdef FINAL_VERSION
 32.4545 +	250000,
 32.4546 +#else
 32.4547 +	5000,
 32.4548 +#endif
 32.4549 +};
 32.4550 +
 32.4551 +// is there a reason to use more than one set of counters?
 32.4552 +EmulatedSystemCounters &GBASystemCounters = systemCounters;
 32.4553 +
 32.4554 +/*
 32.4555 +   EmulatedSystemCounters GBASystemCounters =
 32.4556 +   {
 32.4557 +    // frameCount
 32.4558 +    0,
 32.4559 +    // lagCount
 32.4560 +    0,
 32.4561 +    // lagged
 32.4562 +    true,
 32.4563 +    // laggedLast
 32.4564 +    true,
 32.4565 +   };
 32.4566 + */
 32.4567 +
 32.4568 +
 32.4569 +#undef CPU_BREAK_LOOP
 32.4570 +#undef CPU_BREAK_LOOP2
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/gba/GBA.h	Sun Mar 04 14:33:52 2012 -0600
    33.3 @@ -0,0 +1,122 @@
    33.4 +#ifndef VBA_GBA_H
    33.5 +#define VBA_GBA_H
    33.6 +
    33.7 +#if _MSC_VER > 1000
    33.8 +#pragma once
    33.9 +#endif // _MSC_VER > 1000
   33.10 +
   33.11 +#include "zlib.h"
   33.12 +#include "../Port.h"
   33.13 +
   33.14 +#if (defined(WIN32) && !defined(SDL))
   33.15 +#include "../win32/stdafx.h" // for HANDLE
   33.16 +//#include <windows.h> // for HANDLE
   33.17 +// NOTE: if you get this error:
   33.18 +// #error WINDOWS.H already included.  MFC apps must not #include <windows.h>
   33.19 +// it is probably because stdafx.h is getting included at the wrong place
   33.20 +// (i.e. after anything else) in a file, or your precompiled headers are otherwise wrong
   33.21 +#endif
   33.22 +
   33.23 +#define SAVE_GAME_VERSION_1 1
   33.24 +#define SAVE_GAME_VERSION_2 2
   33.25 +#define SAVE_GAME_VERSION_3 3
   33.26 +#define SAVE_GAME_VERSION_4 4
   33.27 +#define SAVE_GAME_VERSION_5 5
   33.28 +#define SAVE_GAME_VERSION_6 6
   33.29 +#define SAVE_GAME_VERSION_7 7
   33.30 +#define SAVE_GAME_VERSION_8 8
   33.31 +#define SAVE_GAME_VERSION_9 9
   33.32 +#define SAVE_GAME_VERSION_10 10
   33.33 +#define SAVE_GAME_VERSION_11 11
   33.34 +#define SAVE_GAME_VERSION_12 12
   33.35 +#define SAVE_GAME_VERSION_13 13
   33.36 +#define SAVE_GAME_VERSION  SAVE_GAME_VERSION_13
   33.37 +
   33.38 +#if (defined(WIN32) && !defined(SDL))
   33.39 +extern HANDLE mapROM;        // shared memory handles
   33.40 +extern HANDLE mapWORKRAM;
   33.41 +extern HANDLE mapBIOS;
   33.42 +extern HANDLE mapIRAM;
   33.43 +extern HANDLE mapPALETTERAM;
   33.44 +extern HANDLE mapVRAM;
   33.45 +extern HANDLE mapOAM;
   33.46 +extern HANDLE mapPIX;
   33.47 +extern HANDLE mapIOMEM;
   33.48 +#endif
   33.49 +
   33.50 +/*
   33.51 +extern reg_pair reg[45];
   33.52 +extern u8       biosProtected[4];
   33.53 +
   33.54 +extern bool8 N_FLAG;
   33.55 +extern bool8 Z_FLAG;
   33.56 +extern bool8 C_FLAG;
   33.57 +extern bool8 V_FLAG;
   33.58 +extern bool8 armIrqEnable;
   33.59 +extern bool8 armState;
   33.60 +extern int32 armMode;
   33.61 +*/
   33.62 +extern void  (*cpuSaveGameFunc)(u32, u8);
   33.63 +
   33.64 +extern bool8 freezeWorkRAM[0x40000];
   33.65 +extern bool8 freezeInternalRAM[0x8000];
   33.66 +extern bool CPUReadGSASnapshot(const char *);
   33.67 +extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *);
   33.68 +extern bool CPUWriteBatteryFile(const char *);
   33.69 +extern bool CPUReadBatteryFile(const char *);
   33.70 +extern bool CPUWriteBatteryToStream(gzFile);
   33.71 +extern bool CPUReadBatteryFromStream(gzFile);
   33.72 +extern bool CPUExportEepromFile(const char *);
   33.73 +extern bool CPUImportEepromFile(const char *);
   33.74 +extern bool CPUWritePNGFile(const char *);
   33.75 +extern bool CPUWriteBMPFile(const char *);
   33.76 +extern void CPUCleanUp();
   33.77 +extern void CPUUpdateRender();
   33.78 +extern void CPUUpdateRenderBuffers(bool force);
   33.79 +extern bool CPUReadMemState(char *, int);
   33.80 +extern bool CPUReadState(const char *);
   33.81 +extern bool CPUWriteMemState(char *, int);
   33.82 +extern bool CPUWriteState(const char *);
   33.83 +extern bool CPUReadStateFromStream(gzFile);
   33.84 +extern bool CPUWriteStateToStream(gzFile);
   33.85 +extern int CPULoadRom(const char *);
   33.86 +extern void CPUUpdateRegister(u32, u16);
   33.87 +extern void CPUWriteHalfWord(u32, u16);
   33.88 +extern void CPUWriteByte(u32, u8);
   33.89 +extern bool CPULoadBios(const char *, bool);
   33.90 +extern void CPUInit();
   33.91 +extern void CPUReset(bool userReset = false);
   33.92 +extern void CPULoop(int);
   33.93 +extern void CPUCheckDMA(int, int);
   33.94 +#ifdef PROFILING
   33.95 +extern void cpuProfil(char *buffer, int, u32, int);
   33.96 +extern void cpuEnableProfiling(int hz);
   33.97 +#endif
   33.98 +
   33.99 +extern struct EmulatedSystem GBASystem;
  33.100 +extern struct EmulatedSystemCounters &GBASystemCounters;
  33.101 +
  33.102 +#define R13_IRQ  18
  33.103 +#define R14_IRQ  19
  33.104 +#define SPSR_IRQ 20
  33.105 +#define R13_USR  26
  33.106 +#define R14_USR  27
  33.107 +#define R13_SVC  28
  33.108 +#define R14_SVC  29
  33.109 +#define SPSR_SVC 30
  33.110 +#define R13_ABT  31
  33.111 +#define R14_ABT  32
  33.112 +#define SPSR_ABT 33
  33.113 +#define R13_UND  34
  33.114 +#define R14_UND  35
  33.115 +#define SPSR_UND 36
  33.116 +#define R8_FIQ   37
  33.117 +#define R9_FIQ   38
  33.118 +#define R10_FIQ  39
  33.119 +#define R11_FIQ  40
  33.120 +#define R12_FIQ  41
  33.121 +#define R13_FIQ  42
  33.122 +#define R14_FIQ  43
  33.123 +#define SPSR_FIQ 44
  33.124 +
  33.125 +#endif // VBA_GBA_H
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/src/gba/GBACheats.cpp	Sun Mar 04 14:33:52 2012 -0600
    34.3 @@ -0,0 +1,1822 @@
    34.4 +#include <cstdio>
    34.5 +#include <cctype>
    34.6 +#include <cstring>
    34.7 +
    34.8 +#include "../common/System.h"
    34.9 +#include "../common/Util.h"
   34.10 +#include "../NLS.h"
   34.11 +#include "GBACheats.h"
   34.12 +#include "GBA.h"
   34.13 +#include "GBAinline.h"
   34.14 +#include "GBAGlobals.h"
   34.15 +
   34.16 +/**
   34.17 + * Gameshark code types:
   34.18 + *
   34.19 + * NNNNNNNN 001DC0DE - ID code for the game (game 4 character name) from ROM
   34.20 + * DEADFACE XXXXXXXX - changes decryption seeds
   34.21 + * 0AAAAAAA 000000YY - 8-bit constant write
   34.22 + * 1AAAAAAA 0000YYYY - 16-bit constant write
   34.23 + * 2AAAAAAA YYYYYYYY - 32-bit constant write
   34.24 + * 3AAAAAAA YYYYYYYY - ??
   34.25 + * 6AAAAAAA 0000YYYY - 16-bit ROM Patch (address >> 1)
   34.26 + * 6AAAAAAA 1000YYYY - 16-bit ROM Patch ? (address >> 1)
   34.27 + * 6AAAAAAA 2000YYYY - 16-bit ROM Patch ? (address >> 1)
   34.28 + * 8A1AAAAA 000000YY - 8-bit button write
   34.29 + * 8A2AAAAA 0000YYYY - 16-bit button write
   34.30 + * 8A3AAAAA YYYYYYYY - 32-bit button write
   34.31 + * 80F00000 0000YYYY - button slow motion
   34.32 + * DAAAAAAA 0000YYYY - if address contains 16-bit value enable next code
   34.33 + * FAAAAAAA 0000YYYY - Master code function
   34.34 + *
   34.35 + * CodeBreaker codes types:
   34.36 + *
   34.37 + * 0000AAAA 000Y - Game CRC (Y are flags: 8 - CRC, 2 - DI)
   34.38 + * 1AAAAAAA YYYY - Master Code function (store address at ((YYYY << 0x16)
   34.39 + *                 + 0x08000100))
   34.40 + * 2AAAAAAA YYYY - 16-bit or
   34.41 + * 3AAAAAAA YYYY - 8-bit constant write
   34.42 + * 4AAAAAAA YYYY - Slide code
   34.43 + * XXXXCCCC IIII   (C is count and I is address increment, X is value incr.)
   34.44 + * 5AAAAAAA CCCC - Super code (Write bytes to address, CCCC is count)
   34.45 + * BBBBBBBB BBBB
   34.46 + * 6AAAAAAA YYYY - 16-bit and
   34.47 + * 7AAAAAAA YYYY - if address contains 16-bit value enable next code
   34.48 + * 8AAAAAAA YYYY - 16-bit constant write
   34.49 + * 9AAAAAAA YYYY - change decryption (when first code only?)
   34.50 + * AAAAAAAA YYYY - if address does not contain 16-bit value enable next code
   34.51 + * BAAAAAAA YYYY - if 16-bit < YYYY
   34.52 + * CAAAAAAA YYYY - if 16-bit > YYYY
   34.53 + * D0000020 YYYY - if button keys equal value enable next code
   34.54 + * EAAAAAAA YYYY - increase value stored in address
   34.55 + */
   34.56 +#define UNKNOWN_CODE           -1
   34.57 +#define INT_8_BIT_WRITE        0
   34.58 +#define INT_16_BIT_WRITE       1
   34.59 +#define INT_32_BIT_WRITE       2
   34.60 +#define GSA_16_BIT_ROM_PATCH   3
   34.61 +#define GSA_8_BIT_GS_WRITE     4
   34.62 +#define GSA_16_BIT_GS_WRITE    5
   34.63 +#define GSA_32_BIT_GS_WRITE    6
   34.64 +#define CBA_IF_KEYS_PRESSED    7
   34.65 +#define CBA_IF_TRUE            8
   34.66 +#define CBA_SLIDE_CODE         9
   34.67 +#define CBA_IF_FALSE           10
   34.68 +#define CBA_AND                11
   34.69 +#define GSA_8_BIT_GS_WRITE2    12
   34.70 +#define GSA_16_BIT_GS_WRITE2   13
   34.71 +#define GSA_32_BIT_GS_WRITE2   14
   34.72 +#define GSA_16_BIT_ROM_PATCH2  15
   34.73 +#define GSA_8_BIT_SLIDE        16
   34.74 +#define GSA_16_BIT_SLIDE       17
   34.75 +#define GSA_32_BIT_SLIDE       18
   34.76 +#define GSA_8_BIT_IF_TRUE      19
   34.77 +#define GSA_32_BIT_IF_TRUE     20
   34.78 +#define GSA_8_BIT_IF_FALSE     21
   34.79 +#define GSA_32_BIT_IF_FALSE    22
   34.80 +#define GSA_8_BIT_FILL         23
   34.81 +#define GSA_16_BIT_FILL        24
   34.82 +#define GSA_8_BIT_IF_TRUE2     25
   34.83 +#define GSA_16_BIT_IF_TRUE2    26
   34.84 +#define GSA_32_BIT_IF_TRUE2    27
   34.85 +#define GSA_8_BIT_IF_FALSE2    28
   34.86 +#define GSA_16_BIT_IF_FALSE2   29
   34.87 +#define GSA_32_BIT_IF_FALSE2   30
   34.88 +#define GSA_SLOWDOWN           31
   34.89 +#define CBA_ADD                32
   34.90 +#define CBA_OR                 33
   34.91 +#define CBA_LT                 34
   34.92 +#define CBA_GT                 35
   34.93 +#define CBA_SUPER              36
   34.94 +
   34.95 +CheatsData cheatsList[100];
   34.96 +int        cheatsNumber = 0;
   34.97 +
   34.98 +u8   cheatsCBASeedBuffer[0x30];
   34.99 +u32  cheatsCBASeed[4];
  34.100 +u32  cheatsCBATemporaryValue = 0;
  34.101 +u16  cheatsCBATable[256];
  34.102 +bool cheatsCBATableGenerated = false;
  34.103 +
  34.104 +u8 cheatsCBACurrentSeed[12] = {
  34.105 +	0x00, 0x00, 0x00, 0x00,
  34.106 +	0x00, 0x00, 0x00, 0x00,
  34.107 +	0x00, 0x00, 0x00, 0x00
  34.108 +};
  34.109 +
  34.110 +#define CHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9'))
  34.111 +
  34.112 +#define CHEAT_PATCH_ROM_16BIT(a, v) \
  34.113 +    WRITE16LE(((u16 *)&rom[(a) & 0x1ffffff]), v);
  34.114 +
  34.115 +static bool isMultilineWithData(int i)
  34.116 +{
  34.117 +	// we consider it a multiline code if it has more than one line of data
  34.118 +	// otherwise, it can still be considered a single code
  34.119 +	if (i < cheatsNumber && i >= 0)
  34.120 +		switch (cheatsList[i].size)
  34.121 +		{
  34.122 +		case INT_8_BIT_WRITE:
  34.123 +		case INT_16_BIT_WRITE:
  34.124 +		case INT_32_BIT_WRITE:
  34.125 +		case GSA_16_BIT_ROM_PATCH:
  34.126 +		case GSA_8_BIT_GS_WRITE:
  34.127 +		case GSA_16_BIT_GS_WRITE:
  34.128 +		case GSA_32_BIT_GS_WRITE:
  34.129 +		case CBA_AND:
  34.130 +		case CBA_IF_KEYS_PRESSED:
  34.131 +		case CBA_IF_TRUE:
  34.132 +		case CBA_IF_FALSE:
  34.133 +		case GSA_8_BIT_IF_TRUE:
  34.134 +		case GSA_32_BIT_IF_TRUE:
  34.135 +		case GSA_8_BIT_IF_FALSE:
  34.136 +		case GSA_32_BIT_IF_FALSE:
  34.137 +		case GSA_8_BIT_FILL:
  34.138 +		case GSA_16_BIT_FILL:
  34.139 +		case GSA_8_BIT_IF_TRUE2:
  34.140 +		case GSA_16_BIT_IF_TRUE2:
  34.141 +		case GSA_32_BIT_IF_TRUE2:
  34.142 +		case GSA_8_BIT_IF_FALSE2:
  34.143 +		case GSA_16_BIT_IF_FALSE2:
  34.144 +		case GSA_32_BIT_IF_FALSE2:
  34.145 +		case GSA_SLOWDOWN:
  34.146 +		case CBA_ADD:
  34.147 +		case CBA_OR:
  34.148 +			return false;
  34.149 +		// the codes below have two lines of data
  34.150 +		case CBA_SLIDE_CODE:
  34.151 +		case GSA_8_BIT_GS_WRITE2:
  34.152 +		case GSA_16_BIT_GS_WRITE2:
  34.153 +		case GSA_32_BIT_GS_WRITE2:
  34.154 +		case GSA_16_BIT_ROM_PATCH2:
  34.155 +		case GSA_8_BIT_SLIDE:
  34.156 +		case GSA_16_BIT_SLIDE:
  34.157 +		case GSA_32_BIT_SLIDE:
  34.158 +		case CBA_LT:
  34.159 +		case CBA_GT:
  34.160 +		case CBA_SUPER:
  34.161 +			return true;
  34.162 +		}
  34.163 +	return false;
  34.164 +}
  34.165 +
  34.166 +static int getCodeLength(int num)
  34.167 +{
  34.168 +	if (num >= cheatsNumber || num < 0)
  34.169 +		return 1;
  34.170 +
  34.171 +	// this is for all the codes that are true multiline
  34.172 +	switch (cheatsList[num].size)
  34.173 +	{
  34.174 +	case INT_8_BIT_WRITE:
  34.175 +	case INT_16_BIT_WRITE:
  34.176 +	case INT_32_BIT_WRITE:
  34.177 +	case GSA_16_BIT_ROM_PATCH:
  34.178 +	case GSA_8_BIT_GS_WRITE:
  34.179 +	case GSA_16_BIT_GS_WRITE:
  34.180 +	case GSA_32_BIT_GS_WRITE:
  34.181 +	case CBA_AND:
  34.182 +	case GSA_8_BIT_FILL:
  34.183 +	case GSA_16_BIT_FILL:
  34.184 +	case GSA_SLOWDOWN:
  34.185 +	case CBA_ADD:
  34.186 +	case CBA_OR:
  34.187 +		return 1;
  34.188 +	case CBA_IF_KEYS_PRESSED:
  34.189 +	case CBA_IF_TRUE:
  34.190 +	case CBA_IF_FALSE:
  34.191 +	case CBA_SLIDE_CODE:
  34.192 +	case GSA_8_BIT_GS_WRITE2:
  34.193 +	case GSA_16_BIT_GS_WRITE2:
  34.194 +	case GSA_32_BIT_GS_WRITE2:
  34.195 +	case GSA_16_BIT_ROM_PATCH2:
  34.196 +	case GSA_8_BIT_SLIDE:
  34.197 +	case GSA_16_BIT_SLIDE:
  34.198 +	case GSA_32_BIT_SLIDE:
  34.199 +	case GSA_8_BIT_IF_TRUE:
  34.200 +	case GSA_32_BIT_IF_TRUE:
  34.201 +	case GSA_8_BIT_IF_FALSE:
  34.202 +	case GSA_32_BIT_IF_FALSE:
  34.203 +	case CBA_LT:
  34.204 +	case CBA_GT:
  34.205 +		return 2;
  34.206 +	case GSA_8_BIT_IF_TRUE2:
  34.207 +	case GSA_16_BIT_IF_TRUE2:
  34.208 +	case GSA_32_BIT_IF_TRUE2:
  34.209 +	case GSA_8_BIT_IF_FALSE2:
  34.210 +	case GSA_16_BIT_IF_FALSE2:
  34.211 +	case GSA_32_BIT_IF_FALSE2:
  34.212 +		return 3;
  34.213 +	case CBA_SUPER:
  34.214 +		return (cheatsList[num].value+5)/6;
  34.215 +	}
  34.216 +	return 1;
  34.217 +}
  34.218 +
  34.219 +int cheatsCheckKeys(u32 keys, u32 extended)
  34.220 +{
  34.221 +	int ticks = 0;
  34.222 +	for (int i = 0; i < cheatsNumber; i++)
  34.223 +	{
  34.224 +		if (!cheatsList[i].enabled)
  34.225 +		{
  34.226 +			// make sure we skip other lines in this code
  34.227 +			i += getCodeLength(i)-1;
  34.228 +			continue;
  34.229 +		}
  34.230 +		switch (cheatsList[i].size)
  34.231 +		{
  34.232 +		case INT_8_BIT_WRITE:
  34.233 +			CPUWriteByte(cheatsList[i].address, cheatsList[i].value);
  34.234 +			break;
  34.235 +		case INT_16_BIT_WRITE:
  34.236 +			CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value);
  34.237 +			break;
  34.238 +		case INT_32_BIT_WRITE:
  34.239 +			CPUWriteMemory(cheatsList[i].address, cheatsList[i].value);
  34.240 +			break;
  34.241 +		case GSA_16_BIT_ROM_PATCH:
  34.242 +			if ((cheatsList[i].status & 1) == 0)
  34.243 +			{
  34.244 +				if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)
  34.245 +				{
  34.246 +					cheatsList[i].oldValue = CPUReadHalfWord(cheatsList[i].address);
  34.247 +					cheatsList[i].status  |= 1;
  34.248 +					CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value);
  34.249 +				}
  34.250 +			}
  34.251 +			break;
  34.252 +		case GSA_8_BIT_GS_WRITE:
  34.253 +			if (extended & 4)
  34.254 +			{
  34.255 +				CPUWriteByte(cheatsList[i].address, cheatsList[i].value);
  34.256 +			}
  34.257 +			break;
  34.258 +		case GSA_16_BIT_GS_WRITE:
  34.259 +			if (extended & 4)
  34.260 +			{
  34.261 +				CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value);
  34.262 +			}
  34.263 +			break;
  34.264 +		case GSA_32_BIT_GS_WRITE:
  34.265 +			if (extended & 4)
  34.266 +			{
  34.267 +				CPUWriteMemory(cheatsList[i].address, cheatsList[i].value);
  34.268 +			}
  34.269 +			break;
  34.270 +		case CBA_IF_KEYS_PRESSED:
  34.271 +		{
  34.272 +			u16 value = cheatsList[i].value;
  34.273 +			u32 addr  = cheatsList[i].address;
  34.274 +			if ((addr & 0x30) == 0x20)
  34.275 +			{
  34.276 +				if ((keys & value) != value)
  34.277 +				{
  34.278 +					i++;
  34.279 +				}
  34.280 +			}
  34.281 +			else if ((addr & 0x30) == 0x10)
  34.282 +			{
  34.283 +				if ((keys & value) == value)
  34.284 +				{
  34.285 +					i++;
  34.286 +				}
  34.287 +			}
  34.288 +			break;
  34.289 +		}
  34.290 +		case CBA_IF_TRUE:
  34.291 +			if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)
  34.292 +			{
  34.293 +				i++;
  34.294 +			}
  34.295 +			break;
  34.296 +		case CBA_SLIDE_CODE:
  34.297 +		{
  34.298 +			u32 address = cheatsList[i].address;
  34.299 +			u16 value   = cheatsList[i].value;
  34.300 +			i++;
  34.301 +			if (i < cheatsNumber)
  34.302 +			{
  34.303 +				int count = (cheatsList[i].address & 0xFFFF);
  34.304 +				u16 vinc  = (cheatsList[i].address >> 16) & 0xFFFF;
  34.305 +				int inc   = cheatsList[i].value;
  34.306 +
  34.307 +				for (int x = 0; x < count; x++)
  34.308 +				{
  34.309 +					CPUWriteHalfWord(address, value);
  34.310 +					address += inc;
  34.311 +					value   += vinc;
  34.312 +				}
  34.313 +			}
  34.314 +			break;
  34.315 +		}
  34.316 +		case CBA_IF_FALSE:
  34.317 +			if (CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value)
  34.318 +			{
  34.319 +				i++;
  34.320 +			}
  34.321 +			break;
  34.322 +		case CBA_AND:
  34.323 +			CPUWriteHalfWord(cheatsList[i].address,
  34.324 +			                 CPUReadHalfWord(cheatsList[i].address) &
  34.325 +			                 cheatsList[i].value);
  34.326 +			break;
  34.327 +		case GSA_8_BIT_GS_WRITE2:
  34.328 +			i++;
  34.329 +			if (i < cheatsNumber)
  34.330 +			{
  34.331 +				if (extended & 4)
  34.332 +				{
  34.333 +					CPUWriteByte(cheatsList[i-1].value, cheatsList[i].address);
  34.334 +				}
  34.335 +			}
  34.336 +			break;
  34.337 +		case GSA_16_BIT_GS_WRITE2:
  34.338 +			i++;
  34.339 +			if (i < cheatsNumber)
  34.340 +			{
  34.341 +				if (extended & 4)
  34.342 +				{
  34.343 +					CPUWriteHalfWord(cheatsList[i-1].value, cheatsList[i].address);
  34.344 +				}
  34.345 +			}
  34.346 +			break;
  34.347 +		case GSA_32_BIT_GS_WRITE2:
  34.348 +			i++;
  34.349 +			if (i < cheatsNumber)
  34.350 +			{
  34.351 +				if (extended & 4)
  34.352 +				{
  34.353 +					CPUWriteMemory(cheatsList[i-1].value, cheatsList[i].address);
  34.354 +				}
  34.355 +			}
  34.356 +			break;
  34.357 +		case GSA_16_BIT_ROM_PATCH2:
  34.358 +			i++;
  34.359 +			if (i < cheatsNumber)
  34.360 +			{
  34.361 +				if ((cheatsList[i-1].status & 1) == 0)
  34.362 +				{
  34.363 +					u32 addr = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000;
  34.364 +					if (CPUReadHalfWord(addr) != (cheatsList[i].address & 0xFFFF))
  34.365 +					{
  34.366 +						cheatsList[i-1].oldValue = CPUReadHalfWord(addr);
  34.367 +						cheatsList[i-1].status  |= 1;
  34.368 +						CHEAT_PATCH_ROM_16BIT(addr, cheatsList[i].address & 0xFFFF);
  34.369 +					}
  34.370 +				}
  34.371 +			}
  34.372 +			break;
  34.373 +		case GSA_8_BIT_SLIDE:
  34.374 +			i++;
  34.375 +			if (i < cheatsNumber)
  34.376 +			{
  34.377 +				u32 addr  = cheatsList[i-1].value;
  34.378 +				u8  value = cheatsList[i].address;
  34.379 +				int vinc  = (cheatsList[i].value >> 24) & 255;
  34.380 +				int count = (cheatsList[i].value >> 16) & 255;
  34.381 +				int ainc  = (cheatsList[i].value & 0xffff);
  34.382 +				while (count > 0)
  34.383 +				{
  34.384 +					CPUWriteByte(addr, value);
  34.385 +					value += vinc;
  34.386 +					addr  += ainc;
  34.387 +					count--;
  34.388 +				}
  34.389 +			}
  34.390 +			break;
  34.391 +		case GSA_16_BIT_SLIDE:
  34.392 +			i++;
  34.393 +			if (i < cheatsNumber)
  34.394 +			{
  34.395 +				u32 addr  = cheatsList[i-1].value;
  34.396 +				u16 value = cheatsList[i].address;
  34.397 +				int vinc  = (cheatsList[i].value >> 24) & 255;
  34.398 +				int count = (cheatsList[i].value >> 16) & 255;
  34.399 +				int ainc  = (cheatsList[i].value & 0xffff)*2;
  34.400 +				while (count > 0)
  34.401 +				{
  34.402 +					CPUWriteHalfWord(addr, value);
  34.403 +					value += vinc;
  34.404 +					addr  += ainc;
  34.405 +					count--;
  34.406 +				}
  34.407 +			}
  34.408 +			break;
  34.409 +		case GSA_32_BIT_SLIDE:
  34.410 +			i++;
  34.411 +			if (i < cheatsNumber)
  34.412 +			{
  34.413 +				u32 addr  = cheatsList[i-1].value;
  34.414 +				u32 value = cheatsList[i].address;
  34.415 +				int vinc  = (cheatsList[i].value >> 24) & 255;
  34.416 +				int count = (cheatsList[i].value >> 16) & 255;
  34.417 +				int ainc  = (cheatsList[i].value & 0xffff)*4;
  34.418 +				while (count > 0)
  34.419 +				{
  34.420 +					CPUWriteMemory(addr, value);
  34.421 +					value += vinc;
  34.422 +					addr  += ainc;
  34.423 +					count--;
  34.424 +				}
  34.425 +			}
  34.426 +			break;
  34.427 +		case GSA_8_BIT_IF_TRUE:
  34.428 +			if (CPUReadByte(cheatsList[i].address) != cheatsList[i].value)
  34.429 +			{
  34.430 +				i++;
  34.431 +			}
  34.432 +			break;
  34.433 +		case GSA_32_BIT_IF_TRUE:
  34.434 +			if (CPUReadMemory(cheatsList[i].address) != cheatsList[i].value)
  34.435 +			{
  34.436 +				i++;
  34.437 +			}
  34.438 +			break;
  34.439 +		case GSA_8_BIT_IF_FALSE:
  34.440 +			if (CPUReadByte(cheatsList[i].address) == cheatsList[i].value)
  34.441 +			{
  34.442 +				i++;
  34.443 +			}
  34.444 +			break;
  34.445 +		case GSA_32_BIT_IF_FALSE:
  34.446 +			if (CPUReadMemory(cheatsList[i].address) == cheatsList[i].value)
  34.447 +			{
  34.448 +				i++;
  34.449 +			}
  34.450 +			break;
  34.451 +		case GSA_8_BIT_FILL:
  34.452 +		{
  34.453 +			u32 addr = cheatsList[i].address;
  34.454 +			u8  v    = cheatsList[i].value & 0xff;
  34.455 +			u32 end  = addr + (cheatsList[i].value >> 8);
  34.456 +			do
  34.457 +			{
  34.458 +				CPUWriteByte(addr, v);
  34.459 +				addr++;
  34.460 +			}
  34.461 +			while (addr <= end);
  34.462 +			break;
  34.463 +		}
  34.464 +		case GSA_16_BIT_FILL:
  34.465 +		{
  34.466 +			u32 addr = cheatsList[i].address;
  34.467 +			u16 v    = cheatsList[i].value & 0xffff;
  34.468 +			u32 end  = addr + ((cheatsList[i].value >> 16) << 1);
  34.469 +			do
  34.470 +			{
  34.471 +				CPUWriteHalfWord(addr, v);
  34.472 +				addr += 2;
  34.473 +			}
  34.474 +			while (addr <= end);
  34.475 +			break;
  34.476 +		}
  34.477 +		case GSA_8_BIT_IF_TRUE2:
  34.478 +			if (CPUReadByte(cheatsList[i].address) != cheatsList[i].value)
  34.479 +			{
  34.480 +				i += 2;
  34.481 +			}
  34.482 +			break;
  34.483 +		case GSA_16_BIT_IF_TRUE2:
  34.484 +			if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)
  34.485 +			{
  34.486 +				i += 2;
  34.487 +			}
  34.488 +			break;
  34.489 +		case GSA_32_BIT_IF_TRUE2:
  34.490 +			if (CPUReadMemory(cheatsList[i].address) != cheatsList[i].value)
  34.491 +			{
  34.492 +				i += 2;
  34.493 +			}
  34.494 +			break;
  34.495 +		case GSA_8_BIT_IF_FALSE2:
  34.496 +			if (CPUReadByte(cheatsList[i].address) == cheatsList[i].value)
  34.497 +			{
  34.498 +				i += 2;
  34.499 +			}
  34.500 +			break;
  34.501 +		case GSA_16_BIT_IF_FALSE2:
  34.502 +			if (CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value)
  34.503 +			{
  34.504 +				i += 2;
  34.505 +			}
  34.506 +			break;
  34.507 +		case GSA_32_BIT_IF_FALSE2:
  34.508 +			if (CPUReadMemory(cheatsList[i].address) == cheatsList[i].value)
  34.509 +			{
  34.510 +				i += 2;
  34.511 +			}
  34.512 +			break;
  34.513 +		case GSA_SLOWDOWN:
  34.514 +			// check if button was pressed and released, if so toggle our state
  34.515 +			if ((cheatsList[i].status & 4) && !(extended & 4))
  34.516 +				cheatsList[i].status ^= 1;
  34.517 +			if (extended & 4)
  34.518 +				cheatsList[i].status |= 4;
  34.519 +			else
  34.520 +				cheatsList[i].status &= ~4;
  34.521 +
  34.522 +			if (cheatsList[i].status & 1)
  34.523 +				ticks += 2*256*((cheatsList[i].value >> 8) & 255);
  34.524 +			break;
  34.525 +		case CBA_ADD:
  34.526 +			CPUWriteHalfWord(cheatsList[i].address,
  34.527 +			                 CPUReadHalfWord(cheatsList[i].address) +
  34.528 +			                 (u16)cheatsList[i].value);
  34.529 +			break;
  34.530 +		case CBA_OR:
  34.531 +			CPUWriteHalfWord(cheatsList[i].address,
  34.532 +			                 CPUReadHalfWord(cheatsList[i].address) |
  34.533 +			                 cheatsList[i].value);
  34.534 +			break;
  34.535 +		case CBA_LT:
  34.536 +			if (CPUReadHalfWord(cheatsList[i].address) >= cheatsList[i].value)
  34.537 +				i++;
  34.538 +			break;
  34.539 +		case CBA_GT:
  34.540 +			if (CPUReadHalfWord(cheatsList[i].address) <= cheatsList[i].value)
  34.541 +				i++;
  34.542 +			break;
  34.543 +		case CBA_SUPER:
  34.544 +		{
  34.545 +			int count   = 2*cheatsList[i].value;
  34.546 +			u32 address = cheatsList[i].address;
  34.547 +			for (int x = 0; x < count; x++)
  34.548 +			{
  34.549 +				u8  b;
  34.550 +				int res = x % 6;
  34.551 +				if (res < 4)
  34.552 +					b = (cheatsList[i].address >> (24-8*res)) & 0xFF;
  34.553 +				else
  34.554 +					b = (cheatsList[i].value >> (8 - 8*(res-4))) & 0x0FF;
  34.555 +				CPUWriteByte(address, b);
  34.556 +				address++;
  34.557 +				if (x && !res)
  34.558 +					i++;
  34.559 +			}
  34.560 +			if (count % 6)
  34.561 +				i++;
  34.562 +			break;
  34.563 +		}
  34.564 +		}
  34.565 +	}
  34.566 +	return ticks;
  34.567 +}
  34.568 +
  34.569 +void cheatsAdd(const char *codeStr,
  34.570 +               const char *desc,
  34.571 +               u32 address,
  34.572 +               u32 value,
  34.573 +               int code,
  34.574 +               int size)
  34.575 +{
  34.576 +	if (cheatsNumber < 100)
  34.577 +	{
  34.578 +		int x = cheatsNumber;
  34.579 +		cheatsList[x].code    = code;
  34.580 +		cheatsList[x].size    = size;
  34.581 +		cheatsList[x].address = address;
  34.582 +		cheatsList[x].value   = value;
  34.583 +		strcpy(cheatsList[x].codestring, codeStr);
  34.584 +		strcpy(cheatsList[x].desc, desc);
  34.585 +		cheatsList[x].enabled = true;
  34.586 +		cheatsList[x].status  = 0;
  34.587 +
  34.588 +		// we only store the old value for this simple codes. ROM patching
  34.589 +		// is taken care when it actually patches the ROM
  34.590 +		switch (cheatsList[x].size)
  34.591 +		{
  34.592 +		case INT_8_BIT_WRITE:
  34.593 +			cheatsList[x].oldValue = CPUReadByte(address);
  34.594 +			break;
  34.595 +		case INT_16_BIT_WRITE:
  34.596 +			cheatsList[x].oldValue = CPUReadHalfWord(address);
  34.597 +			break;
  34.598 +		case INT_32_BIT_WRITE:
  34.599 +			cheatsList[x].oldValue = CPUReadMemory(address);
  34.600 +			break;
  34.601 +		}
  34.602 +		cheatsNumber++;
  34.603 +	}
  34.604 +}
  34.605 +
  34.606 +void cheatsDelete(int number, bool restore)
  34.607 +{
  34.608 +	if (number < cheatsNumber && number >= 0)
  34.609 +	{
  34.610 +		int x = number;
  34.611 +
  34.612 +		if (restore)
  34.613 +		{
  34.614 +			switch (cheatsList[x].size)
  34.615 +			{
  34.616 +			case INT_8_BIT_WRITE:
  34.617 +				CPUWriteByte(cheatsList[x].address, (u8)cheatsList[x].oldValue);
  34.618 +				break;
  34.619 +			case INT_16_BIT_WRITE:
  34.620 +				CPUWriteHalfWord(cheatsList[x].address, (u16)cheatsList[x].oldValue);
  34.621 +				break;
  34.622 +			case INT_32_BIT_WRITE:
  34.623 +				CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue);
  34.624 +				break;
  34.625 +			case GSA_16_BIT_ROM_PATCH:
  34.626 +				if (cheatsList[x].status & 1)
  34.627 +				{
  34.628 +					cheatsList[x].status &= ~1;
  34.629 +					CHEAT_PATCH_ROM_16BIT(cheatsList[x].address,
  34.630 +					                      cheatsList[x].oldValue);
  34.631 +				}
  34.632 +				break;
  34.633 +			case GSA_16_BIT_ROM_PATCH2:
  34.634 +				if (cheatsList[x].status & 1)
  34.635 +				{
  34.636 +					cheatsList[x].status &= ~1;
  34.637 +					CHEAT_PATCH_ROM_16BIT(((cheatsList[x].value & 0x00FFFFFF) << 1)+
  34.638 +					                      0x8000000,
  34.639 +					                      cheatsList[x].oldValue);
  34.640 +				}
  34.641 +				break;
  34.642 +			}
  34.643 +		}
  34.644 +		if ((x+1) <  cheatsNumber)
  34.645 +		{
  34.646 +			memcpy(&cheatsList[x], &cheatsList[x+1], sizeof(CheatsData)*
  34.647 +			       (cheatsNumber-x-1));
  34.648 +		}
  34.649 +		cheatsNumber--;
  34.650 +	}
  34.651 +}
  34.652 +
  34.653 +void cheatsDeleteAll(bool restore)
  34.654 +{
  34.655 +	for (int i = cheatsNumber-1; i >= 0; i--)
  34.656 +	{
  34.657 +		cheatsDelete(i, restore);
  34.658 +	}
  34.659 +}
  34.660 +
  34.661 +void cheatsEnable(int i)
  34.662 +{
  34.663 +	if (i >= 0 && i < cheatsNumber)
  34.664 +	{
  34.665 +		cheatsList[i].enabled = true;
  34.666 +	}
  34.667 +}
  34.668 +
  34.669 +void cheatsDisable(int i)
  34.670 +{
  34.671 +	if (i >= 0 && i < cheatsNumber)
  34.672 +	{
  34.673 +		switch (cheatsList[i].size)
  34.674 +		{
  34.675 +		case GSA_16_BIT_ROM_PATCH:
  34.676 +			if (cheatsList[i].status & 1)
  34.677 +			{
  34.678 +				cheatsList[i].status &= ~1;
  34.679 +				CHEAT_PATCH_ROM_16BIT(cheatsList[i].address,
  34.680 +				                      cheatsList[i].oldValue);
  34.681 +			}
  34.682 +			break;
  34.683 +		case GSA_16_BIT_ROM_PATCH2:
  34.684 +			if (cheatsList[i].status & 1)
  34.685 +			{
  34.686 +				cheatsList[i].status &= ~1;
  34.687 +				CHEAT_PATCH_ROM_16BIT(((cheatsList[i].value & 0x00FFFFFF) << 1)+
  34.688 +				                      0x8000000,
  34.689 +				                      cheatsList[i].oldValue);
  34.690 +			}
  34.691 +			break;
  34.692 +		}
  34.693 +		cheatsList[i].enabled = false;
  34.694 +	}
  34.695 +}
  34.696 +
  34.697 +bool cheatsVerifyCheatCode(const char *code, const char *desc)
  34.698 +{
  34.699 +	int len = strlen(code);
  34.700 +	if (len != 11 && len != 13 && len != 17)
  34.701 +	{
  34.702 +		systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code);
  34.703 +		return false;
  34.704 +	}
  34.705 +
  34.706 +	if (code[8] != ':')
  34.707 +	{
  34.708 +		systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code);
  34.709 +		return false;
  34.710 +	}
  34.711 +
  34.712 +	int i;
  34.713 +	for (i = 0; i < 8; i++)
  34.714 +	{
  34.715 +		if (!CHEAT_IS_HEX(code[i]))
  34.716 +		{
  34.717 +			// wrong cheat
  34.718 +			systemMessage(MSG_INVALID_CHEAT_CODE,
  34.719 +			              N_("Invalid cheat code '%s'"), code);
  34.720 +			return false;
  34.721 +		}
  34.722 +	}
  34.723 +	for (i = 9; i < len; i++)
  34.724 +	{
  34.725 +		if (!CHEAT_IS_HEX(code[i]))
  34.726 +		{
  34.727 +			// wrong cheat
  34.728 +			systemMessage(MSG_INVALID_CHEAT_CODE,
  34.729 +			              N_("Invalid cheat code '%s'"), code);
  34.730 +			return false;
  34.731 +		}
  34.732 +	}
  34.733 +
  34.734 +	u32 address = 0;
  34.735 +	u32 value   = 0;
  34.736 +
  34.737 +	char buffer[10];
  34.738 +	strncpy(buffer, code, 8);
  34.739 +	buffer[8] = 0;
  34.740 +	sscanf(buffer, "%x", &address);
  34.741 +
  34.742 +	switch (address >> 24)
  34.743 +	{
  34.744 +	case 2:
  34.745 +	case 3:
  34.746 +		break;
  34.747 +	default:
  34.748 +		systemMessage(MSG_INVALID_CHEAT_CODE_ADDRESS,
  34.749 +		              N_("Invalid cheat code address: %08x"),
  34.750 +		              address);
  34.751 +		return false;
  34.752 +	}
  34.753 +
  34.754 +	strncpy(buffer, &code[9], 8);
  34.755 +	sscanf(buffer, "%x", &value);
  34.756 +	int type = 0;
  34.757 +	if (len == 13)
  34.758 +		type = 1;
  34.759 +	if (len == 17)
  34.760 +		type = 2;
  34.761 +	cheatsAdd(code, desc, address, value, type, type);
  34.762 +	return true;
  34.763 +}
  34.764 +
  34.765 +void cheatsAddCheatCode(const char *code, const char *desc)
  34.766 +{
  34.767 +	cheatsVerifyCheatCode(code, desc);
  34.768 +}
  34.769 +
  34.770 +void cheatsDecryptGSACode(u32& address, u32& value, bool v3)
  34.771 +{
  34.772 +	u32  rollingseed = 0xC6EF3720;
  34.773 +	u32  seeds_v1[]  =  { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 };
  34.774 +	u32  seeds_v3[]  = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 };
  34.775 +	u32 *seeds       = v3 ? seeds_v3 : seeds_v1;
  34.776 +
  34.777 +	int bitsleft = 32;
  34.778 +	while (bitsleft > 0)
  34.779 +	{
  34.780 +		value -= ((((address << 4) + seeds[2]) ^ (address + rollingseed)) ^
  34.781 +		          ((address >> 5) + seeds[3]));
  34.782 +		address -= ((((value << 4) + seeds[0]) ^ (value + rollingseed)) ^
  34.783 +		            ((value >> 5) + seeds[1]));
  34.784 +		rollingseed -= 0x9E3779B9;
  34.785 +		bitsleft--;
  34.786 +	}
  34.787 +}
  34.788 +
  34.789 +void cheatsAddGSACode(const char *code, const char *desc, bool v3)
  34.790 +{
  34.791 +	if (strlen(code) != 16)
  34.792 +	{
  34.793 +		// wrong cheat
  34.794 +		systemMessage(MSG_INVALID_GSA_CODE,
  34.795 +		              N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY"));
  34.796 +		return;
  34.797 +	}
  34.798 +
  34.799 +	int i;
  34.800 +	for (i = 0; i < 16; i++)
  34.801 +	{
  34.802 +		if (!CHEAT_IS_HEX(code[i]))
  34.803 +		{
  34.804 +			// wrong cheat
  34.805 +			systemMessage(MSG_INVALID_GSA_CODE,
  34.806 +			              N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY"));
  34.807 +			return;
  34.808 +		}
  34.809 +	}
  34.810 +
  34.811 +	char buffer[10];
  34.812 +	strncpy(buffer, code, 8);
  34.813 +	buffer[8] = 0;
  34.814 +	u32 address;
  34.815 +	sscanf(buffer, "%x", &address);
  34.816 +	strncpy(buffer, &code[8], 8);
  34.817 +	buffer[8] = 0;
  34.818 +	u32 value;
  34.819 +	sscanf(buffer, "%x", &value);
  34.820 +
  34.821 +	cheatsDecryptGSACode(address, value, v3);
  34.822 +
  34.823 +	if (value == 0x1DC0DE)
  34.824 +	{
  34.825 +		u32 gamecode = READ32LE(((u32 *)&rom[0xac]));
  34.826 +		if (gamecode != address)
  34.827 +		{
  34.828 +			char buffer[5];
  34.829 +			*((u32 *)buffer) = address;
  34.830 +			buffer[4]        = 0;
  34.831 +			char buffer2[5];
  34.832 +			*((u32 *)buffer2) = READ32LE(((u32 *)&rom[0xac]));
  34.833 +			buffer2[4]        = 0;
  34.834 +			systemMessage(MSG_GBA_CODE_WARNING,
  34.835 +			              N_("Warning: cheats are for game %s. Current game is %s.\nCodes may not work correctly."),
  34.836 +			              buffer, buffer2);
  34.837 +		}
  34.838 +		cheatsAdd(code, desc, address & 0x0FFFFFFF, value, v3 ? 257 : 256,
  34.839 +		          UNKNOWN_CODE);
  34.840 +		return;
  34.841 +	}
  34.842 +	if (isMultilineWithData(cheatsNumber-1))
  34.843 +	{
  34.844 +		cheatsAdd(code, desc, address, value, v3 ? 257 : 256, UNKNOWN_CODE);
  34.845 +		return;
  34.846 +	}
  34.847 +	if (v3)
  34.848 +	{
  34.849 +		int type = (address >> 25) & 127;
  34.850 +		u32 addr = (address & 0x00F00000) << 4 | (address & 0x0003FFFF);
  34.851 +		switch (type)
  34.852 +		{
  34.853 +		case 0x00:
  34.854 +			if (address == 0)
  34.855 +			{
  34.856 +				type = (value >> 25) & 127;
  34.857 +				addr = (value & 0x00F00000) << 4 | (value & 0x0003FFFF);
  34.858 +				switch (type)
  34.859 +				{
  34.860 +				case 0x04:
  34.861 +					cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_SLOWDOWN);
  34.862 +					break;
  34.863 +				case 0x08:
  34.864 +					cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_GS_WRITE2);
  34.865 +					break;
  34.866 +				case 0x09:
  34.867 +					cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_GS_WRITE2);
  34.868 +					break;
  34.869 +				case 0x0a:
  34.870 +					cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_GS_WRITE2);
  34.871 +					break;
  34.872 +				case 0x0c:
  34.873 +				case 0x0d:
  34.874 +				case 0x0e:
  34.875 +				case 0x0f:
  34.876 +					cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2);
  34.877 +					break;
  34.878 +				case 0x40:
  34.879 +					cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_SLIDE);
  34.880 +					break;
  34.881 +				case 0x41:
  34.882 +					cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_SLIDE);
  34.883 +					break;
  34.884 +				case 0x42:
  34.885 +					cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_SLIDE);
  34.886 +					break;
  34.887 +				default:
  34.888 +					cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE);
  34.889 +					break;
  34.890 +				}
  34.891 +			}
  34.892 +			else
  34.893 +				cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_FILL);
  34.894 +			break;
  34.895 +		case 0x01:
  34.896 +			cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_FILL);
  34.897 +			break;
  34.898 +		case 0x02:
  34.899 +			cheatsAdd(code, desc, addr, value, 257, INT_32_BIT_WRITE);
  34.900 +			break;
  34.901 +		case 0x04:
  34.902 +			cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE);
  34.903 +			break;
  34.904 +		case 0x05:
  34.905 +			cheatsAdd(code, desc, addr, value, 257, CBA_IF_TRUE);
  34.906 +			break;
  34.907 +		case 0x06:
  34.908 +			cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE);
  34.909 +			break;
  34.910 +		case 0x08:
  34.911 +			cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE);
  34.912 +			break;
  34.913 +		case 0x09:
  34.914 +			cheatsAdd(code, desc, addr, value, 257, CBA_IF_FALSE);
  34.915 +			break;
  34.916 +		case 0x0a:
  34.917 +			cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE);
  34.918 +			break;
  34.919 +		case 0x24:
  34.920 +			cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE2);
  34.921 +			break;
  34.922 +		case 0x25:
  34.923 +			cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_TRUE2);
  34.924 +			break;
  34.925 +		case 0x26:
  34.926 +			cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE2);
  34.927 +			break;
  34.928 +		case 0x28:
  34.929 +			cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE2);
  34.930 +			break;
  34.931 +		case 0x29:
  34.932 +			cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_FALSE2);
  34.933 +			break;
  34.934 +		case 0x2a:
  34.935 +			cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE2);
  34.936 +			break;
  34.937 +		default:
  34.938 +			cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE);
  34.939 +			break;
  34.940 +		}
  34.941 +	}
  34.942 +	else
  34.943 +	{
  34.944 +		int type = (address >> 28) & 15;
  34.945 +		switch (type)
  34.946 +		{
  34.947 +		case 0:
  34.948 +		case 1:
  34.949 +		case 2:
  34.950 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, type);
  34.951 +			break;
  34.952 +		case 6:
  34.953 +			address <<= 1;
  34.954 +			type      = (address >> 28) & 15;
  34.955 +			if (type == 0x0c)
  34.956 +			{
  34.957 +				cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256,
  34.958 +				          GSA_16_BIT_ROM_PATCH);
  34.959 +				break;
  34.960 +			}
  34.961 +			// unsupported code
  34.962 +			cheatsAdd(code, desc, address, value, 256,
  34.963 +			          UNKNOWN_CODE);
  34.964 +			break;
  34.965 +		case 8:
  34.966 +			switch ((address >> 20) & 15)
  34.967 +			{
  34.968 +			case 1:
  34.969 +				cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,
  34.970 +				          GSA_8_BIT_GS_WRITE);
  34.971 +				break;
  34.972 +			case 2:
  34.973 +				cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,
  34.974 +				          GSA_16_BIT_GS_WRITE);
  34.975 +				break;
  34.976 +			case 3:
  34.977 +				cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,
  34.978 +				          GSA_32_BIT_GS_WRITE);
  34.979 +			case 15:
  34.980 +				cheatsAdd(code, desc, 0, value & 0xFF00, 256, GSA_SLOWDOWN);
  34.981 +				break;
  34.982 +			default:
  34.983 +				// unsupported code
  34.984 +				cheatsAdd(code, desc, address, value, 256,
  34.985 +				          UNKNOWN_CODE);
  34.986 +				break;
  34.987 +			}
  34.988 +			break;
  34.989 +		case 0x0d:
  34.990 +			if (address != 0xDEADFACE)
  34.991 +			{
  34.992 +				cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256,
  34.993 +				          CBA_IF_TRUE);
  34.994 +			}
  34.995 +			else
  34.996 +				cheatsAdd(code, desc, address, value, 256,
  34.997 +				          UNKNOWN_CODE);
  34.998 +			break;
  34.999 +		default:
 34.1000 +			// unsupported code
 34.1001 +			cheatsAdd(code, desc, address, value, 256,
 34.1002 +			          UNKNOWN_CODE);
 34.1003 +			break;
 34.1004 +		}
 34.1005 +	}
 34.1006 +}
 34.1007 +
 34.1008 +bool cheatsImportGSACodeFile(const char *name, int game, bool v3)
 34.1009 +{
 34.1010 +	FILE *f = fopen(name, "rb");
 34.1011 +	if (!f)
 34.1012 +		return false;
 34.1013 +
 34.1014 +	int games = 0;
 34.1015 +	int len   = 0;
 34.1016 +	fseek(f, 0x1e, SEEK_CUR);
 34.1017 +	fread(&games, 1, 4, f);
 34.1018 +	bool found = false;
 34.1019 +	int  g     = 0;
 34.1020 +	while (games > 0)
 34.1021 +	{
 34.1022 +		if (g == game)
 34.1023 +		{
 34.1024 +			found = true;
 34.1025 +			break;
 34.1026 +		}
 34.1027 +		fread(&len, 1, 4, f);
 34.1028 +		fseek(f, len, SEEK_CUR);
 34.1029 +		int codes = 0;
 34.1030 +		fread(&codes, 1, 4, f);
 34.1031 +		while (codes > 0)
 34.1032 +		{
 34.1033 +			fread(&len, 1, 4, f);
 34.1034 +			fseek(f, len, SEEK_CUR);
 34.1035 +			fseek(f, 8, SEEK_CUR);
 34.1036 +			fread(&len, 1, 4, f);
 34.1037 +			fseek(f, len*12, SEEK_CUR);
 34.1038 +			codes--;
 34.1039 +		}
 34.1040 +		games--;
 34.1041 +		g++;
 34.1042 +	}
 34.1043 +	if (found)
 34.1044 +	{
 34.1045 +		char desc[256];
 34.1046 +		char code[17];
 34.1047 +		fread(&len, 1, 4, f);
 34.1048 +		fseek(f, len, SEEK_CUR);
 34.1049 +		int codes = 0;
 34.1050 +		fread(&codes, 1, 4, f);
 34.1051 +		while (codes > 0)
 34.1052 +		{
 34.1053 +			fread(&len, 1, 4, f);
 34.1054 +			fread(desc, 1, len, f);
 34.1055 +			desc[len] = 0;
 34.1056 +			desc[31]  = 0;
 34.1057 +			fread(&len, 1, 4, f);
 34.1058 +			fseek(f, len, SEEK_CUR);
 34.1059 +			fseek(f, 4, SEEK_CUR);
 34.1060 +			fread(&len, 1, 4, f);
 34.1061 +			while (len)
 34.1062 +			{
 34.1063 +				fseek(f, 4, SEEK_CUR);
 34.1064 +				fread(code, 1, 8, f);
 34.1065 +				fseek(f, 4, SEEK_CUR);
 34.1066 +				fread(&code[8], 1, 8, f);
 34.1067 +				code[16] = 0;
 34.1068 +				cheatsAddGSACode(code, desc, v3);
 34.1069 +				len -= 2;
 34.1070 +			}
 34.1071 +			codes--;
 34.1072 +		}
 34.1073 +	}
 34.1074 +	fclose(f);
 34.1075 +	return false;
 34.1076 +}
 34.1077 +
 34.1078 +void cheatsCBAReverseArray(u8 *array, u8 *dest)
 34.1079 +{
 34.1080 +	dest[0] = array[3];
 34.1081 +	dest[1] = array[2];
 34.1082 +	dest[2] = array[1];
 34.1083 +	dest[3] = array[0];
 34.1084 +	dest[4] = array[5];
 34.1085 +	dest[5] = array[4];
 34.1086 +}
 34.1087 +
 34.1088 +void chatsCBAScramble(u8 *array, int count, u8 b)
 34.1089 +{
 34.1090 +	u8 *x  = array + (count >> 3);
 34.1091 +	u8 *y  = array + (b >> 3);
 34.1092 +	u32 z  = *x & (1 << (count & 7));
 34.1093 +	u32 x0 = (*x & (~(1 << (count & 7))));
 34.1094 +	if (z != 0)
 34.1095 +		z = 1;
 34.1096 +	if ((*y & (1 << (b & 7))) != 0)
 34.1097 +		x0 |= (1 << (count & 7));
 34.1098 +	*x = x0;
 34.1099 +	u32 temp = *y & (~(1 << (b & 7)));
 34.1100 +	if (z != 0)
 34.1101 +		temp |= (1 << (b & 7));
 34.1102 +	*y = temp;
 34.1103 +}
 34.1104 +
 34.1105 +u32 cheatsCBAGetValue(u8 *array)
 34.1106 +{
 34.1107 +	return array[0] | array[1]<<8 | array[2] << 16 | array[3]<<24;
 34.1108 +}
 34.1109 +
 34.1110 +u16 cheatsCBAGetData(u8 *array)
 34.1111 +{
 34.1112 +	return array[4] | array[5]<<8;
 34.1113 +}
 34.1114 +
 34.1115 +void cheatsCBAArrayToValue(u8 *array, u8 *dest)
 34.1116 +{
 34.1117 +	dest[0] = array[3];
 34.1118 +	dest[1] = array[2];
 34.1119 +	dest[2] = array[1];
 34.1120 +	dest[3] = array[0];
 34.1121 +	dest[4] = array[5];
 34.1122 +	dest[5] = array[4];
 34.1123 +}
 34.1124 +
 34.1125 +void cheatsCBAParseSeedCode(u32 address, u32 value, u32 *array)
 34.1126 +{
 34.1127 +	array[0] = 1;
 34.1128 +	array[1] = value & 0xFF;
 34.1129 +	array[2] = (address >> 0x10) & 0xFF;
 34.1130 +	array[3] = (value >> 8) & 0xFF;
 34.1131 +	array[4] = (address >> 0x18) & 0x0F;
 34.1132 +	array[5] = address & 0xFFFF;
 34.1133 +	array[6] = address;
 34.1134 +	array[7] = value;
 34.1135 +}
 34.1136 +
 34.1137 +u32 cheatsCBAEncWorker()
 34.1138 +{
 34.1139 +	u32 x = (cheatsCBATemporaryValue * 0x41c64e6d) + 0x3039;
 34.1140 +	u32 y = (x * 0x41c64e6d) + 0x3039;
 34.1141 +	u32 z = x >> 0x10;
 34.1142 +	x = ((y >> 0x10) & 0x7fff) << 0x0f;
 34.1143 +	z = (z << 0x1e) | x;
 34.1144 +	x = (y * 0x41c64e6d) + 0x3039;
 34.1145 +	cheatsCBATemporaryValue = x;
 34.1146 +	return z | ((x >> 0x10) & 0x7fff);
 34.1147 +}
 34.1148 +
 34.1149 +#define ROR(v, s) \
 34.1150 +    (((v) >> (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
 34.1151 +
 34.1152 +u32 cheatsCBACalcIndex(u32 x, u32 y)
 34.1153 +{
 34.1154 +	if (y != 0)
 34.1155 +	{
 34.1156 +		if (y == 1)
 34.1157 +			x = 0;
 34.1158 +		else if (x == y)
 34.1159 +			x = 0;
 34.1160 +		if (y < 1)
 34.1161 +			return x;
 34.1162 +		else if (x < y)
 34.1163 +			return x;
 34.1164 +		u32 x0 = 1;
 34.1165 +
 34.1166 +		while (y < 0x10000000)
 34.1167 +		{
 34.1168 +			if (y < x)
 34.1169 +			{
 34.1170 +				y  = y << 4;
 34.1171 +				x0 = x0 << 4;
 34.1172 +			}
 34.1173 +			else
 34.1174 +				break;
 34.1175 +		}
 34.1176 +
 34.1177 +		while (y < 0x80000000)
 34.1178 +		{
 34.1179 +			if (y < x)
 34.1180 +			{
 34.1181 +				y  = y << 1;
 34.1182 +				x0 = x0 << 1;
 34.1183 +			}
 34.1184 +			else
 34.1185 +				break;
 34.1186 +		}
 34.1187 +
 34.1188 +loop:
 34.1189 +		u32 z = 0;
 34.1190 +		if (x >= y)
 34.1191 +			x -= y;
 34.1192 +		if (x >= (y >> 1))
 34.1193 +		{
 34.1194 +			x -= (y >> 1);
 34.1195 +			z |= ROR(x0, 1);
 34.1196 +		}
 34.1197 +		if (x >= (y >> 2))
 34.1198 +		{
 34.1199 +			x -= (y >> 2);
 34.1200 +			z |= ROR(x0, 2);
 34.1201 +		}
 34.1202 +		if (x >= (y >> 3))
 34.1203 +		{
 34.1204 +			x -= (y >> 3);
 34.1205 +			z |= ROR(x0, 3);
 34.1206 +		}
 34.1207 +
 34.1208 +		u32 temp = x0;
 34.1209 +
 34.1210 +		if (x != 0)
 34.1211 +		{
 34.1212 +			x0 = x0 >> 4;
 34.1213 +			if (x0 != 0)
 34.1214 +			{
 34.1215 +				y = y >> 4;
 34.1216 +				goto loop;
 34.1217 +			}
 34.1218 +		}
 34.1219 +
 34.1220 +		z = z & 0xe0000000;
 34.1221 +
 34.1222 +		if (z != 0)
 34.1223 +		{
 34.1224 +			if ((temp & 7) == 0)
 34.1225 +				return x;
 34.1226 +		}
 34.1227 +		else
 34.1228 +			return x;
 34.1229 +
 34.1230 +		if ((z & ROR(temp, 3)) != 0)
 34.1231 +			x += y >> 3;
 34.1232 +		if ((z & ROR(temp, 2)) != 0)
 34.1233 +			x += y >> 2;
 34.1234 +		if ((z & ROR(temp, 1)) != 0)
 34.1235 +			x += y >> 1;
 34.1236 +		return x;
 34.1237 +	}
 34.1238 +	else
 34.1239 +	{}
 34.1240 +	// should not happen in the current code
 34.1241 +	return 0;
 34.1242 +}
 34.1243 +
 34.1244 +void cheatsCBAUpdateSeedBuffer(u32 a, u8 *buffer, int count)
 34.1245 +{
 34.1246 +	int i;
 34.1247 +	for (i = 0; i < count; i++)
 34.1248 +		buffer[i] = i;
 34.1249 +	for (i = 0; (u32)i < a; i++)
 34.1250 +	{
 34.1251 +		u32 a = cheatsCBACalcIndex(cheatsCBAEncWorker(), count);
 34.1252 +		u32 b = cheatsCBACalcIndex(cheatsCBAEncWorker(), count);
 34.1253 +		u32 t = buffer[a];
 34.1254 +		buffer[a] = buffer[b];
 34.1255 +		buffer[b] = t;
 34.1256 +	}
 34.1257 +}
 34.1258 +
 34.1259 +void cheatsCBAChangeEncryption(u32 *seed)
 34.1260 +{
 34.1261 +	int i;
 34.1262 +
 34.1263 +	cheatsCBATemporaryValue = (seed[1] ^ 0x1111);
 34.1264 +	cheatsCBAUpdateSeedBuffer(0x50, cheatsCBASeedBuffer, 0x30);
 34.1265 +	cheatsCBATemporaryValue = 0x4efad1c3;
 34.1266 +
 34.1267 +	for (i = 0; (u32)i < seed[4]; i++)
 34.1268 +	{
 34.1269 +		cheatsCBATemporaryValue = cheatsCBAEncWorker();
 34.1270 +	}
 34.1271 +	cheatsCBASeed[2] = cheatsCBAEncWorker();
 34.1272 +	cheatsCBASeed[3] = cheatsCBAEncWorker();
 34.1273 +
 34.1274 +	cheatsCBATemporaryValue = seed[3] ^ 0xf254;
 34.1275 +
 34.1276 +	for (i = 0; (u32)i < seed[3]; i++)
 34.1277 +	{
 34.1278 +		cheatsCBATemporaryValue = cheatsCBAEncWorker();
 34.1279 +	}
 34.1280 +
 34.1281 +	cheatsCBASeed[0] = cheatsCBAEncWorker();
 34.1282 +	cheatsCBASeed[1] = cheatsCBAEncWorker();
 34.1283 +
 34.1284 +	*((u32 *)&cheatsCBACurrentSeed[0]) = seed[6];
 34.1285 +	*((u32 *)&cheatsCBACurrentSeed[4]) = seed[7];
 34.1286 +	*((u32 *)&cheatsCBACurrentSeed[8]) = 0;
 34.1287 +}
 34.1288 +
 34.1289 +u16 cheatsCBAGenValue(u32 x, u32 y, u32 z)
 34.1290 +{
 34.1291 +	y <<= 0x10;
 34.1292 +	z <<= 0x10;
 34.1293 +	x <<= 0x18;
 34.1294 +	u32 x0 = (int)y >> 0x10;
 34.1295 +	z = (int)z >> 0x10;
 34.1296 +	x = (int)x >> 0x10;
 34.1297 +	for (int i = 0; i < 8; i++)
 34.1298 +	{
 34.1299 +		u32 temp = z ^ x;
 34.1300 +		if ((int)temp >= 0)
 34.1301 +		{
 34.1302 +			temp = z << 0x11;
 34.1303 +		}
 34.1304 +		else
 34.1305 +		{
 34.1306 +			temp  = z << 0x01;
 34.1307 +			temp ^= x0;
 34.1308 +			temp  = temp << 0x10;
 34.1309 +		}
 34.1310 +		z    = (int)temp >> 0x10;
 34.1311 +		temp = x << 0x11;
 34.1312 +		x    = (int)temp >> 0x10;
 34.1313 +	}
 34.1314 +	return z & 0xffff;
 34.1315 +}
 34.1316 +
 34.1317 +void cheatsCBAGenTable()
 34.1318 +{
 34.1319 +	for (int i = 0; i < 0x100; i++)
 34.1320 +	{
 34.1321 +		cheatsCBATable[i] = cheatsCBAGenValue(i, 0x1021, 0);
 34.1322 +	}
 34.1323 +	cheatsCBATableGenerated = true;
 34.1324 +}
 34.1325 +
 34.1326 +u16 cheatsCBACalcCRC(u8 *rom, int count)
 34.1327 +{
 34.1328 +	u32 crc = 0xffffffff;
 34.1329 +
 34.1330 +	if (count & 3)
 34.1331 +	{
 34.1332 +		// 0x08000EAE
 34.1333 +	}
 34.1334 +	else
 34.1335 +	{
 34.1336 +		count = (count >> 2) - 1;
 34.1337 +		if (count != -1)
 34.1338 +		{
 34.1339 +			while (count != -1)
 34.1340 +			{
 34.1341 +				crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)
 34.1342 +				                                       ^ *rom++]) << 0x10) >> 0x10;
 34.1343 +				crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)
 34.1344 +				                                       ^ *rom++]) << 0x10) >> 0x10;
 34.1345 +				crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)
 34.1346 +				                                       ^ *rom++]) << 0x10) >> 0x10;
 34.1347 +				crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)
 34.1348 +				                                       ^ *rom++]) << 0x10) >> 0x10;
 34.1349 +				count--;
 34.1350 +			}
 34.1351 +		}
 34.1352 +	}
 34.1353 +	return crc & 0xffff;
 34.1354 +}
 34.1355 +
 34.1356 +void cheatsCBADecrypt(u8 *decrypt)
 34.1357 +{
 34.1358 +	u8  buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 34.1359 +	u8 *array     = &buffer[1];
 34.1360 +
 34.1361 +	cheatsCBAReverseArray(decrypt, array);
 34.1362 +
 34.1363 +	for (int count = 0x2f; count >= 0; count--)
 34.1364 +	{
 34.1365 +		chatsCBAScramble(array, count, cheatsCBASeedBuffer[count]);
 34.1366 +	}
 34.1367 +	cheatsCBAArrayToValue(array, decrypt);
 34.1368 +	*((u32 *)decrypt) = cheatsCBAGetValue(decrypt) ^
 34.1369 +	                    cheatsCBASeed[0];
 34.1370 +	*((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) ^
 34.1371 +	                         cheatsCBASeed[1]) & 0xffff;
 34.1372 +
 34.1373 +	cheatsCBAReverseArray(decrypt, array);
 34.1374 +
 34.1375 +	u32 cs = cheatsCBAGetValue(cheatsCBACurrentSeed);
 34.1376 +	for (int i = 0; i <= 4; i++)
 34.1377 +	{
 34.1378 +		array[i] = ((cs >> 8) ^ array[i+1]) ^ array[i] ;
 34.1379 +	}
 34.1380 +
 34.1381 +	array[5] = (cs >> 8) ^ array[5];
 34.1382 +
 34.1383 +	for (int j = 5; j >= 0; j--)
 34.1384 +	{
 34.1385 +		array[j] = (cs ^ array[j-1]) ^ array[j];
 34.1386 +	}
 34.1387 +
 34.1388 +	cheatsCBAArrayToValue(array, decrypt);
 34.1389 +
 34.1390 +	*((u32 *)decrypt) = cheatsCBAGetValue(decrypt)
 34.1391 +	                    ^ cheatsCBASeed[2];
 34.1392 +	*((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt)
 34.1393 +	                         ^ cheatsCBASeed[3]) & 0xffff;
 34.1394 +}
 34.1395 +
 34.1396 +int cheatsCBAGetCount()
 34.1397 +{
 34.1398 +	int count = 0;
 34.1399 +	for (int i = 0; i < cheatsNumber; i++)
 34.1400 +	{
 34.1401 +		if (cheatsList[i].code == 512)
 34.1402 +			count++;
 34.1403 +	}
 34.1404 +	return count;
 34.1405 +}
 34.1406 +
 34.1407 +bool cheatsCBAShouldDecrypt()
 34.1408 +{
 34.1409 +	for (int i = 0; i < cheatsNumber; i++)
 34.1410 +	{
 34.1411 +		if (cheatsList[i].code == 512)
 34.1412 +		{
 34.1413 +			return (cheatsList[i].codestring[0] == '9');
 34.1414 +		}
 34.1415 +	}
 34.1416 +	return false;
 34.1417 +}
 34.1418 +
 34.1419 +void cheatsAddCBACode(const char *code, const char *desc)
 34.1420 +{
 34.1421 +	if (strlen(code) != 13)
 34.1422 +	{
 34.1423 +		// wrong cheat
 34.1424 +		systemMessage(MSG_INVALID_CBA_CODE,
 34.1425 +		              N_("Invalid CBA code. Format is XXXXXXXX YYYY."));
 34.1426 +		return;
 34.1427 +	}
 34.1428 +
 34.1429 +	int i;
 34.1430 +	for (i = 0; i < 8; i++)
 34.1431 +	{
 34.1432 +		if (!CHEAT_IS_HEX(code[i]))
 34.1433 +		{
 34.1434 +			// wrong cheat
 34.1435 +			systemMessage(MSG_INVALID_CBA_CODE,
 34.1436 +			              N_("Invalid CBA code. Format is XXXXXXXX YYYY."));
 34.1437 +			return;
 34.1438 +		}
 34.1439 +	}
 34.1440 +
 34.1441 +	if (code[8] != ' ')
 34.1442 +	{
 34.1443 +		systemMessage(MSG_INVALID_CBA_CODE,
 34.1444 +		              N_("Invalid CBA code. Format is XXXXXXXX YYYY."));
 34.1445 +		return;
 34.1446 +	}
 34.1447 +
 34.1448 +	for (i = 9; i < 13; i++)
 34.1449 +	{
 34.1450 +		if (!CHEAT_IS_HEX(code[i]))
 34.1451 +		{
 34.1452 +			// wrong cheat
 34.1453 +			systemMessage(MSG_INVALID_CBA_CODE,
 34.1454 +			              N_("Invalid CBA code. Format is XXXXXXXX YYYY."));
 34.1455 +			return;
 34.1456 +		}
 34.1457 +	}
 34.1458 +
 34.1459 +	char buffer[10];
 34.1460 +	strncpy(buffer, code, 8);
 34.1461 +	buffer[8] = 0;
 34.1462 +	u32 address;
 34.1463 +	sscanf(buffer, "%x", &address);
 34.1464 +	strncpy(buffer, &code[9], 4);
 34.1465 +	buffer[4] = 0;
 34.1466 +	u32 value;
 34.1467 +	sscanf(buffer, "%x", &value);
 34.1468 +
 34.1469 +	u8 array[8] = {
 34.1470 +		address &255,
 34.1471 +		(address >> 8) & 255,
 34.1472 +		(address >> 16) & 255,
 34.1473 +		(address >> 24) & 255,
 34.1474 +		(value & 255),
 34.1475 +		(value >> 8) & 255,
 34.1476 +		0,
 34.1477 +		0
 34.1478 +	};
 34.1479 +
 34.1480 +	if (cheatsCBAGetCount() == 0 &&
 34.1481 +	    (address >> 28) == 9)
 34.1482 +	{
 34.1483 +		u32 seed[8];
 34.1484 +		cheatsCBAParseSeedCode(address, value, seed);
 34.1485 +		cheatsCBAChangeEncryption(seed);
 34.1486 +		cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, UNKNOWN_CODE);
 34.1487 +	}
 34.1488 +	else
 34.1489 +	{
 34.1490 +		if (cheatsCBAShouldDecrypt())
 34.1491 +			cheatsCBADecrypt(array);
 34.1492 +
 34.1493 +		address = READ32LE(((u32 *)array));
 34.1494 +		value   = READ16LE(((u16 *)&array[4]));
 34.1495 +
 34.1496 +		int type = (address >> 28) & 15;
 34.1497 +
 34.1498 +		if (isMultilineWithData(cheatsNumber-1))
 34.1499 +		{
 34.1500 +			cheatsAdd(code, desc, address, value, 512, UNKNOWN_CODE);
 34.1501 +			return;
 34.1502 +		}
 34.1503 +
 34.1504 +		switch (type)
 34.1505 +		{
 34.1506 +		case 0x00:
 34.1507 +		{
 34.1508 +			if (!cheatsCBATableGenerated)
 34.1509 +				cheatsCBAGenTable();
 34.1510 +			u32 crc = cheatsCBACalcCRC(rom, 0x10000);
 34.1511 +			if (crc != address)
 34.1512 +			{
 34.1513 +				systemMessage(MSG_CBA_CODE_WARNING,
 34.1514 +				              N_("Warning: Codes seem to be for a different game.\nCodes may not work correctly."));
 34.1515 +			}
 34.1516 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1517 +			          UNKNOWN_CODE);
 34.1518 +			break;
 34.1519 +		}
 34.1520 +		case 0x02:
 34.1521 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1522 +			          CBA_OR);
 34.1523 +			break;
 34.1524 +		case 0x03:
 34.1525 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1526 +			          INT_8_BIT_WRITE);
 34.1527 +			break;
 34.1528 +		case 0x04:
 34.1529 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1530 +			          CBA_SLIDE_CODE);
 34.1531 +			break;
 34.1532 +		case 0x05:
 34.1533 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1534 +			          CBA_SUPER);
 34.1535 +			break;
 34.1536 +		case 0x06:
 34.1537 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1538 +			          CBA_AND);
 34.1539 +			break;
 34.1540 +		case 0x07:
 34.1541 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1542 +			          CBA_IF_TRUE);
 34.1543 +			break;
 34.1544 +		case 0x08:
 34.1545 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1546 +			          INT_16_BIT_WRITE);
 34.1547 +			break;
 34.1548 +		case 0x0a:
 34.1549 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1550 +			          CBA_IF_FALSE);
 34.1551 +			break;
 34.1552 +		case 0x0b:
 34.1553 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1554 +			          CBA_LT);
 34.1555 +			break;
 34.1556 +		case 0x0c:
 34.1557 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1558 +			          CBA_GT);
 34.1559 +			break;
 34.1560 +		case 0x0d:
 34.1561 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1562 +			          CBA_IF_KEYS_PRESSED);
 34.1563 +			break;
 34.1564 +		case 0x0e:
 34.1565 +			cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,
 34.1566 +			          CBA_ADD);
 34.1567 +			break;
 34.1568 +		default:
 34.1569 +			// unsupported code
 34.1570 +			cheatsAdd(code, desc, address & 0xFFFFFFFF, value, 512,
 34.1571 +			          UNKNOWN_CODE);
 34.1572 +			break;
 34.1573 +		}
 34.1574 +	}
 34.1575 +}
 34.1576 +
 34.1577 +void cheatsSaveGame(gzFile file)
 34.1578 +{
 34.1579 +	utilWriteInt(file, cheatsNumber);
 34.1580 +
 34.1581 +	utilGzWrite(file, cheatsList, sizeof(cheatsList));
 34.1582 +}
 34.1583 +
 34.1584 +void cheatsReadGame(gzFile file)
 34.1585 +{
 34.1586 +	cheatsNumber = 0;
 34.1587 +
 34.1588 +	cheatsNumber = utilReadInt(file);
 34.1589 +
 34.1590 +	utilGzRead(file, cheatsList, sizeof(cheatsList));
 34.1591 +
 34.1592 +	bool firstCodeBreaker = true;
 34.1593 +
 34.1594 +	for (int i = 0; i < cheatsNumber; i++)
 34.1595 +	{
 34.1596 +		cheatsList[i].status = 0;
 34.1597 +		if (!cheatsList[i].codestring[0])
 34.1598 +		{
 34.1599 +			switch (cheatsList[i].size)
 34.1600 +			{
 34.1601 +			case 0:
 34.1602 +				sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address,
 34.1603 +				        cheatsList[i].value);
 34.1604 +				break;
 34.1605 +			case 1:
 34.1606 +				sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address,
 34.1607 +				        cheatsList[i].value);
 34.1608 +				break;
 34.1609 +			case 2:
 34.1610 +				sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address,
 34.1611 +				        cheatsList[i].value);
 34.1612 +				break;
 34.1613 +			}
 34.1614 +		}
 34.1615 +
 34.1616 +		if (cheatsList[i].enabled)
 34.1617 +		{
 34.1618 +			cheatsEnable(i);
 34.1619 +		}
 34.1620 +
 34.1621 +		if (cheatsList[i].code == 512 && firstCodeBreaker)
 34.1622 +		{
 34.1623 +			firstCodeBreaker = false;
 34.1624 +			char buffer[10];
 34.1625 +			strncpy(buffer, cheatsList[i].codestring, 8);
 34.1626 +			buffer[8] = 0;
 34.1627 +			u32 address;
 34.1628 +			sscanf(buffer, "%x", &address);
 34.1629 +			if ((address >> 28) == 9)
 34.1630 +			{
 34.1631 +				strncpy(buffer, &cheatsList[i].codestring[9], 4);
 34.1632 +				buffer[4] = 0;
 34.1633 +				u32 value;
 34.1634 +				sscanf(buffer, "%x", &value);
 34.1635 +
 34.1636 +				u32 seed[8];
 34.1637 +				cheatsCBAParseSeedCode(address, value, seed);
 34.1638 +				cheatsCBAChangeEncryption(seed);
 34.1639 +			}
 34.1640 +		}
 34.1641 +	}
 34.1642 +}
 34.1643 +
 34.1644 +void cheatsSaveCheatList(const char *file)
 34.1645 +{
 34.1646 +	if (cheatsNumber == 0)
 34.1647 +		return;
 34.1648 +	FILE *f = fopen(file, "wb");
 34.1649 +	if (f == NULL)
 34.1650 +		return;
 34.1651 +	int version = 1;
 34.1652 +	fwrite(&version, 1, sizeof(version), f);
 34.1653 +	int type = 0;
 34.1654 +	fwrite(&type, 1, sizeof(type), f);
 34.1655 +	fwrite(&cheatsNumber, 1, sizeof(cheatsNumber), f);
 34.1656 +	fwrite(cheatsList, 1, sizeof(cheatsList), f);
 34.1657 +	fclose(f);
 34.1658 +}
 34.1659 +
 34.1660 +bool cheatsLoadCheatList(const char *file)
 34.1661 +{
 34.1662 +	cheatsNumber = 0;
 34.1663 +
 34.1664 +	int count = 0;
 34.1665 +
 34.1666 +	FILE *f = fopen(file, "rb");
 34.1667 +
 34.1668 +	if (f == NULL)
 34.1669 +		return false;
 34.1670 +
 34.1671 +	int version = 0;
 34.1672 +
 34.1673 +	if (fread(&version, 1, sizeof(version), f) != sizeof(version))
 34.1674 +	{
 34.1675 +		fclose(f);
 34.1676 +		return false;
 34.1677 +	}
 34.1678 +
 34.1679 +	if (version != 1)
 34.1680 +	{
 34.1681 +		systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,
 34.1682 +		              N_("Unsupported cheat list version %d"), version);
 34.1683 +		fclose(f);
 34.1684 +		return false;
 34.1685 +	}
 34.1686 +
 34.1687 +	int type = 0;
 34.1688 +	if (fread(&type, 1, sizeof(type), f) != sizeof(type))
 34.1689 +	{
 34.1690 +		fclose(f);
 34.1691 +		return false;
 34.1692 +	}
 34.1693 +
 34.1694 +	if (type != 0)
 34.1695 +	{
 34.1696 +		systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,
 34.1697 +		              N_("Unsupported cheat list type %d"), type);
 34.1698 +		fclose(f);
 34.1699 +		return false;
 34.1700 +	}
 34.1701 +
 34.1702 +	if (fread(&count, 1, sizeof(count), f) != sizeof(count))
 34.1703 +	{
 34.1704 +		fclose(f);
 34.1705 +		return false;
 34.1706 +	}
 34.1707 +
 34.1708 +	if (fread(cheatsList, 1, sizeof(cheatsList), f) != sizeof(cheatsList))
 34.1709 +	{
 34.1710 +		fclose(f);
 34.1711 +		return false;
 34.1712 +	}
 34.1713 +
 34.1714 +	bool firstCodeBreaker = true;
 34.1715 +
 34.1716 +	for (int i = 0; i < count; i++)
 34.1717 +	{
 34.1718 +		cheatsList[i].status = 0; // remove old status as it is not used
 34.1719 +		if (!cheatsList[i].codestring[0])
 34.1720 +		{
 34.1721 +			switch (cheatsList[i].size)
 34.1722 +			{
 34.1723 +			case 0:
 34.1724 +				sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address,
 34.1725 +				        cheatsList[i].value);
 34.1726 +				break;
 34.1727 +			case 1:
 34.1728 +				sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address,
 34.1729 +				        cheatsList[i].value);
 34.1730 +				break;
 34.1731 +			case 2:
 34.1732 +				sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address,
 34.1733 +				        cheatsList[i].value);
 34.1734 +				break;
 34.1735 +			}
 34.1736 +		}
 34.1737 +
 34.1738 +		if (cheatsList[i].code == 512 && firstCodeBreaker)
 34.1739 +		{
 34.1740 +			firstCodeBreaker = false;
 34.1741 +			char buffer[10];
 34.1742 +			strncpy(buffer, cheatsList[i].codestring, 8);
 34.1743 +			buffer[8] = 0;
 34.1744 +			u32 address;
 34.1745 +			sscanf(buffer, "%x", &address);
 34.1746 +			if ((address >> 28) == 9)
 34.1747 +			{
 34.1748 +				strncpy(buffer, &cheatsList[i].codestring[9], 4);
 34.1749 +				buffer[4] = 0;
 34.1750 +				u32 value;
 34.1751 +				sscanf(buffer, "%x", &value);
 34.1752 +
 34.1753 +				u32 seed[8];
 34.1754 +				cheatsCBAParseSeedCode(address, value, seed);
 34.1755 +				cheatsCBAChangeEncryption(seed);
 34.1756 +			}
 34.1757 +		}
 34.1758 +	}
 34.1759 +	cheatsNumber = count;
 34.1760 +	fclose(f);
 34.1761 +	return true;
 34.1762 +}
 34.1763 +
 34.1764 +extern int *extCpuLoopTicks;
 34.1765 +extern int *extClockTicks;
 34.1766 +extern int *extTicks;
 34.1767 +extern int  cpuSavedTicks;
 34.1768 +
 34.1769 +extern void debuggerBreakOnWrite(u32 *, u32, u32, int);
 34.1770 +
 34.1771 +#define CPU_BREAK_LOOP2 \
 34.1772 +    cpuSavedTicks    = cpuSavedTicks - *extCpuLoopTicks; \
 34.1773 +    *extCpuLoopTicks = *extClockTicks; \
 34.1774 +    *extTicks        = *extClockTicks;
 34.1775 +
 34.1776 +void cheatsWriteMemory(u32 *address, u32 value, u32 mask)
 34.1777 +{
 34.1778 +#ifdef BKPT_SUPPORT
 34.1779 +#ifdef SDL
 34.1780 +	if (cheatsNumber == 0)
 34.1781 +	{
 34.1782 +		debuggerBreakOnWrite(address, *address, value, 2);
 34.1783 +		CPU_BREAK_LOOP2;
 34.1784 +		*address = value;
 34.1785 +		return;
 34.1786 +	}
 34.1787 +#endif
 34.1788 +#endif
 34.1789 +}
 34.1790 +
 34.1791 +void cheatsWriteHalfWord(u16 *address, u16 value, u16 mask)
 34.1792 +{
 34.1793 +#ifdef BKPT_SUPPORT
 34.1794 +#ifdef SDL
 34.1795 +	if (cheatsNumber == 0)
 34.1796 +	{
 34.1797 +		debuggerBreakOnWrite((u32 *)address, *address, value, 1);
 34.1798 +		CPU_BREAK_LOOP2;
 34.1799 +		*address = value;
 34.1800 +		return;
 34.1801 +	}
 34.1802 +#endif
 34.1803 +#endif
 34.1804 +}
 34.1805 +
 34.1806 +#if defined BKPT_SUPPORT && defined SDL
 34.1807 +void cheatsWriteByte(u8 *address, u8 value)
 34.1808 +#else
 34.1809 +void cheatsWriteByte(u8 *, u8)
 34.1810 +#endif
 34.1811 +{
 34.1812 +#ifdef BKPT_SUPPORT
 34.1813 +#ifdef SDL
 34.1814 +	if (cheatsNumber == 0)
 34.1815 +	{
 34.1816 +		debuggerBreakOnWrite((u32 *)address, *address, value, 0);
 34.1817 +		CPU_BREAK_LOOP2;
 34.1818 +		*address = value;
 34.1819 +		return;
 34.1820 +	}
 34.1821 +#endif
 34.1822 +#endif
 34.1823 +}
 34.1824 +
 34.1825 +#undef CPU_BREAK_LOOP2
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/src/gba/GBACheats.h	Sun Mar 04 14:33:52 2012 -0600
    35.3 @@ -0,0 +1,44 @@
    35.4 +#ifndef VBA_GBA_CHEATS_H
    35.5 +#define VBA_GBA_CHEATS_H
    35.6 +
    35.7 +#if _MSC_VER > 1000
    35.8 +#pragma once
    35.9 +#endif // _MSC_VER > 1000
   35.10 +
   35.11 +#include "zlib.h"
   35.12 +#include "../Port.h"
   35.13 +
   35.14 +struct CheatsData
   35.15 +{
   35.16 +	int  code;
   35.17 +	int  size;
   35.18 +	int  status;
   35.19 +	bool enabled;
   35.20 +	u32  address;
   35.21 +	u32  value;
   35.22 +	u32  oldValue;
   35.23 +	char codestring[20];
   35.24 +	char desc[32];
   35.25 +};
   35.26 +
   35.27 +extern void cheatsAdd(const char *, const char *, u32, u32, int, int);
   35.28 +extern void cheatsAddCheatCode(const char *code, const char *desc);
   35.29 +extern void cheatsAddGSACode(const char *code, const char *desc, bool v3);
   35.30 +extern void cheatsAddCBACode(const char *code, const char *desc);
   35.31 +extern bool cheatsImportGSACodeFile(const char *name, int game, bool v3);
   35.32 +extern void cheatsDelete(int number, bool restore);
   35.33 +extern void cheatsDeleteAll(bool restore);
   35.34 +extern void cheatsEnable(int number);
   35.35 +extern void cheatsDisable(int number);
   35.36 +extern void cheatsSaveGame(gzFile file);
   35.37 +extern void cheatsReadGame(gzFile file);
   35.38 +extern void cheatsSaveCheatList(const char *file);
   35.39 +extern bool cheatsLoadCheatList(const char *file);
   35.40 +extern void       cheatsWriteMemory(u32 *, u32, u32);
   35.41 +extern void       cheatsWriteHalfWord(u16 *, u16, u16);
   35.42 +extern void       cheatsWriteByte(u8 *, u8);
   35.43 +extern int        cheatsCheckKeys(u32, u32);
   35.44 +extern int        cheatsNumber;
   35.45 +extern CheatsData cheatsList[100];
   35.46 +
   35.47 +#endif // GBA_CHEATS_H
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/src/gba/GBAGfx.cpp	Sun Mar 04 14:33:52 2012 -0600
    36.3 @@ -0,0 +1,35 @@
    36.4 +#include "../Port.h"
    36.5 +#include "GBAGfx.h"
    36.6 +
    36.7 +int coeff[32] = {
    36.8 +	0,   1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
    36.9 +	16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
   36.10 +};
   36.11 +
   36.12 +// some of the rendering code in gfx.h (such as mode 0 line 1298)
   36.13 +// renders outside the given buffer (past 239) which corrupts other memory,
   36.14 +// so rather than find all places in that code that need to be fixed,
   36.15 +// just give it enough extra scratch space to use
   36.16 +
   36.17 +u32  line0[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.18 +u32  line1[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.19 +u32  line2[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.20 +u32  line3[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.21 +u32  lineOBJ[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.22 +u32  lineOBJWin[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.23 +u32  lineMix[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.24 +bool gfxInWin0[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.25 +bool gfxInWin1[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   36.26 +
   36.27 +int gfxBG2Changed = 0;
   36.28 +int gfxBG3Changed = 0;
   36.29 +
   36.30 +int gfxBG2X       = 0;
   36.31 +int gfxBG2Y       = 0;
   36.32 +int gfxBG2LastX   = 0;
   36.33 +int gfxBG2LastY   = 0;
   36.34 +int gfxBG3X       = 0;
   36.35 +int gfxBG3Y       = 0;
   36.36 +int gfxBG3LastX   = 0;
   36.37 +int gfxBG3LastY   = 0;
   36.38 +int gfxLastVCOUNT = 0;
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/src/gba/GBAGfx.h	Sun Mar 04 14:33:52 2012 -0600
    37.3 @@ -0,0 +1,1791 @@
    37.4 +#ifndef VBA_GBA_GFX_H
    37.5 +#define VBA_GBA_GFX_H
    37.6 +
    37.7 +#if _MSC_VER > 1000
    37.8 +#pragma once
    37.9 +#endif // _MSC_VER > 1000
   37.10 +
   37.11 +#include "../Port.h"
   37.12 +#include "GBA.h"
   37.13 +#include "GBAGlobals.h"
   37.14 +
   37.15 +//#define SPRITE_DEBUG
   37.16 +
   37.17 +void gfxDrawTextScreen(u16, u16, u16, u32 *);
   37.18 +void gfxDrawRotScreen(u16,
   37.19 +                      u16, u16,
   37.20 +                      u16, u16,
   37.21 +                      u16, u16,
   37.22 +                      u16, u16,
   37.23 +                      int&, int&,
   37.24 +                      int,
   37.25 +                      u32 *);
   37.26 +void gfxDrawRotScreen16Bit(u16,
   37.27 +                           u16, u16,
   37.28 +                           u16, u16,
   37.29 +                           u16, u16,
   37.30 +                           u16, u16,
   37.31 +                           int&, int&,
   37.32 +                           int,
   37.33 +                           u32 *);
   37.34 +void gfxDrawRotScreen256(u16,
   37.35 +                         u16, u16,
   37.36 +                         u16, u16,
   37.37 +                         u16, u16,
   37.38 +                         u16, u16,
   37.39 +                         int&, int&,
   37.40 +                         int,
   37.41 +                         u32 *);
   37.42 +void gfxDrawRotScreen16Bit160(u16,
   37.43 +                              u16, u16,
   37.44 +                              u16, u16,
   37.45 +                              u16, u16,
   37.46 +                              u16, u16,
   37.47 +                              int&, int&,
   37.48 +                              int,
   37.49 +                              u32 *);
   37.50 +void gfxDrawSprites(u32 *);
   37.51 +void gfxIncreaseBrightness(u32 *line, int coeff);
   37.52 +void gfxDecreaseBrightness(u32 *line, int coeff);
   37.53 +void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb);
   37.54 +
   37.55 +void mode0RenderLine();
   37.56 +void mode0RenderLineNoWindow();
   37.57 +void mode0RenderLineAll();
   37.58 +
   37.59 +void mode1RenderLine();
   37.60 +void mode1RenderLineNoWindow();
   37.61 +void mode1RenderLineAll();
   37.62 +
   37.63 +void mode2RenderLine();
   37.64 +void mode2RenderLineNoWindow();
   37.65 +void mode2RenderLineAll();
   37.66 +
   37.67 +void mode3RenderLine();
   37.68 +void mode3RenderLineNoWindow();
   37.69 +void mode3RenderLineAll();
   37.70 +
   37.71 +void mode4RenderLine();
   37.72 +void mode4RenderLineNoWindow();
   37.73 +void mode4RenderLineAll();
   37.74 +
   37.75 +void mode5RenderLine();
   37.76 +void mode5RenderLineNoWindow();
   37.77 +void mode5RenderLineAll();
   37.78 +
   37.79 +extern int  coeff[32];
   37.80 +
   37.81 +#define LINE_BUFFER_OVERFLOW_LEEWAY (512-240)
   37.82 +
   37.83 +extern u32  line0[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.84 +extern u32  line1[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.85 +extern u32  line2[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.86 +extern u32  line3[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.87 +extern u32  lineOBJ[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.88 +extern u32  lineOBJWin[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.89 +extern u32  lineMix[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.90 +extern bool gfxInWin0[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.91 +extern bool gfxInWin1[240+LINE_BUFFER_OVERFLOW_LEEWAY];
   37.92 +
   37.93 +extern int gfxBG2Changed;
   37.94 +extern int gfxBG3Changed;
   37.95 +
   37.96 +extern int gfxBG2X;
   37.97 +extern int gfxBG2Y;
   37.98 +extern int gfxBG2LastX;
   37.99 +extern int gfxBG2LastY;
  37.100 +extern int gfxBG3X;
  37.101 +extern int gfxBG3Y;
  37.102 +extern int gfxBG3LastX;
  37.103 +extern int gfxBG3LastY;
  37.104 +extern int gfxLastVCOUNT;
  37.105 +
  37.106 +inline void gfxClearArray(u32 *array)
  37.107 +{
  37.108 +	for (int i = 0; i < 240; i++)
  37.109 +	{
  37.110 +		*array++ = 0x80000000;
  37.111 +	}
  37.112 +}
  37.113 +
  37.114 +inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs,
  37.115 +                              u32 *line)
  37.116 +{
  37.117 +	u16 *palette    = (u16 *)paletteRAM;
  37.118 +	u8 * charBase   = &vram[((control >> 2) & 0x03) * 0x4000];
  37.119 +	u16 *screenBase = (u16 *)&vram[((control >> 8) & 0x1f) * 0x800];
  37.120 +	u32  prio       = ((control & 3)<<25) + 0x1000000;
  37.121 +	int  sizeX      = 256;
  37.122 +	int  sizeY      = 256;
  37.123 +	switch ((control >> 14) & 3)
  37.124 +	{
  37.125 +	case 0:
  37.126 +		break;
  37.127 +	case 1:
  37.128 +		sizeX = 512;
  37.129 +		break;
  37.130 +	case 2:
  37.131 +		sizeY = 512;
  37.132 +		break;
  37.133 +	case 3:
  37.134 +		sizeX = 512;
  37.135 +		sizeY = 512;
  37.136 +		break;
  37.137 +	}
  37.138 +
  37.139 +	int maskX = sizeX-1;
  37.140 +	int maskY = sizeY-1;
  37.141 +
  37.142 +	bool mosaicOn = (control & 0x40) ? true : false;
  37.143 +
  37.144 +	int xxx     = hofs & maskX;
  37.145 +	int yyy     = (vofs + VCOUNT) & maskY;
  37.146 +	int mosaicX = (MOSAIC & 0x000F)+1;
  37.147 +	int mosaicY = ((MOSAIC & 0x00F0)>>4)+1;
  37.148 +
  37.149 +	if (mosaicOn)
  37.150 +	{
  37.151 +		if ((VCOUNT % mosaicY) != 0)
  37.152 +		{
  37.153 +			mosaicY = (VCOUNT / mosaicY) * mosaicY;
  37.154 +			yyy     = (vofs + mosaicY) & maskY;
  37.155 +		}
  37.156 +	}
  37.157 +
  37.158 +	if (yyy > 255 && sizeY > 256)
  37.159 +	{
  37.160 +		yyy        &= 255;
  37.161 +		screenBase += 0x400;
  37.162 +		if (sizeX > 256)
  37.163 +			screenBase += 0x400;
  37.164 +	}
  37.165 +
  37.166 +	int yshift = ((yyy>>3)<<5);
  37.167 +	if ((control) & 0x80)
  37.168 +	{
  37.169 +		u16 *screenSource = screenBase + 0x400 * (xxx>>8) + ((xxx & 255)>>3) + yshift;
  37.170 +		for (int x = 0; x < 240; x++)
  37.171 +		{
  37.172 +			u16 data = READ16LE(screenSource);
  37.173 +
  37.174 +			int tile  = data & 0x3FF;
  37.175 +			int tileX = (xxx & 7);
  37.176 +			int tileY = yyy & 7;
  37.177 +
  37.178 +			if (data & 0x0400)
  37.179 +				tileX = 7 - tileX;
  37.180 +			if (data & 0x0800)
  37.181 +				tileY = 7 - tileY;
  37.182 +
  37.183 +			u8 color = charBase[tile * 64 + tileY * 8 + tileX];
  37.184 +
  37.185 +			line[x] = color ? (READ16LE(&palette[color]) | prio) : 0x80000000;
  37.186 +
  37.187 +			if (data & 0x0400)
  37.188 +			{
  37.189 +				if (tileX == 0)
  37.190 +					screenSource++;
  37.191 +			}
  37.192 +			else if (tileX == 7)
  37.193 +				screenSource++;
  37.194 +			xxx++;
  37.195 +			if (xxx == 256)
  37.196 +			{
  37.197 +				if (sizeX > 256)
  37.198 +					screenSource = screenBase + 0x400 + yshift;
  37.199 +				else
  37.200 +				{
  37.201 +					screenSource = screenBase + yshift;
  37.202 +					xxx = 0;
  37.203 +				}
  37.204 +			}
  37.205 +			else if (xxx >= sizeX)
  37.206 +			{
  37.207 +				xxx = 0;
  37.208 +				screenSource = screenBase + yshift;
  37.209 +			}
  37.210 +		}
  37.211 +	}
  37.212 +	else
  37.213 +	{
  37.214 +		u16 *screenSource = screenBase + 0x400*(xxx>>8)+((xxx&255)>>3) +
  37.215 +		                    yshift;
  37.216 +		for (int x = 0; x < 240; x++)
  37.217 +		{
  37.218 +			u16 data = READ16LE(screenSource);
  37.219 +
  37.220 +			int tile  = data & 0x3FF;
  37.221 +			int tileX = (xxx & 7);
  37.222 +			int tileY = yyy & 7;
  37.223 +
  37.224 +			if (data & 0x0400)
  37.225 +				tileX = 7 - tileX;
  37.226 +			if (data & 0x0800)
  37.227 +				tileY = 7 - tileY;
  37.228 +
  37.229 +			u8 color = charBase[(tile<<5) + (tileY<<2) + (tileX>>1)];
  37.230 +
  37.231 +			if (tileX & 1)
  37.232 +			{
  37.233 +				color = (color >> 4);
  37.234 +			}
  37.235 +			else
  37.236 +			{
  37.237 +				color &= 0x0F;
  37.238 +			}
  37.239 +
  37.240 +			int pal = (READ16LE(screenSource)>>8) & 0xF0;
  37.241 +			line[x] = color ? (READ16LE(&palette[pal + color])|prio) : 0x80000000;
  37.242 +
  37.243 +			if (data & 0x0400)
  37.244 +			{
  37.245 +				if (tileX == 0)
  37.246 +					screenSource++;
  37.247 +			}
  37.248 +			else if (tileX == 7)
  37.249 +				screenSource++;
  37.250 +			xxx++;
  37.251 +			if (xxx == 256)
  37.252 +			{
  37.253 +				if (sizeX > 256)
  37.254 +					screenSource = screenBase + 0x400 + yshift;
  37.255 +				else
  37.256 +				{
  37.257 +					screenSource = screenBase + yshift;
  37.258 +					xxx = 0;
  37.259 +				}
  37.260 +			}
  37.261 +			else if (xxx >= sizeX)
  37.262 +			{
  37.263 +				xxx = 0;
  37.264 +				screenSource = screenBase + yshift;
  37.265 +			}
  37.266 +		}
  37.267 +	}
  37.268 +	if (mosaicOn)
  37.269 +	{
  37.270 +		if (mosaicX > 1)
  37.271 +		{
  37.272 +			int m = 1;
  37.273 +			for (int i = 0; i < 239; i++)
  37.274 +			{
  37.275 +				line[i+1] = line[i];
  37.276 +				m++;
  37.277 +				if (m == mosaicX)
  37.278 +				{
  37.279 +					m = 1;
  37.280 +					i++;
  37.281 +				}
  37.282 +			}
  37.283 +		}
  37.284 +	}
  37.285 +}
  37.286 +
  37.287 +inline void gfxDrawRotScreen(u16 control,
  37.288 +                             u16 x_l, u16 x_h,
  37.289 +                             u16 y_l, u16 y_h,
  37.290 +                             u16 pa,  u16 pb,
  37.291 +                             u16 pc,  u16 pd,
  37.292 +                             int& currentX, int& currentY,
  37.293 +                             int changed,
  37.294 +                             u32 *line)
  37.295 +{
  37.296 +	u16 *palette    = (u16 *)paletteRAM;
  37.297 +	u8 * charBase   = &vram[((control >> 2) & 0x03) * 0x4000];
  37.298 +	u8 * screenBase = (u8 *)&vram[((control >> 8) & 0x1f) * 0x800];
  37.299 +	int  prio       = ((control & 3) << 25) + 0x1000000;
  37.300 +
  37.301 +	int sizeX = 128;
  37.302 +	int sizeY = 128;
  37.303 +	switch ((control >> 14) & 3)
  37.304 +	{
  37.305 +	case 0:
  37.306 +		break;
  37.307 +	case 1:
  37.308 +		sizeX = sizeY = 256;
  37.309 +		break;
  37.310 +	case 2:
  37.311 +		sizeX = sizeY = 512;
  37.312 +		break;
  37.313 +	case 3:
  37.314 +		sizeX = sizeY = 1024;
  37.315 +		break;
  37.316 +	}
  37.317 +
  37.318 +	int dx = pa & 0x7FFF;
  37.319 +	if (pa & 0x8000)
  37.320 +		dx |= 0xFFFF8000;
  37.321 +	int dmx = pb & 0x7FFF;
  37.322 +	if (pb & 0x8000)
  37.323 +		dmx |= 0xFFFF8000;
  37.324 +	int dy = pc & 0x7FFF;
  37.325 +	if (pc & 0x8000)
  37.326 +		dy |= 0xFFFF8000;
  37.327 +	int dmy = pd & 0x7FFFF;
  37.328 +	if (pd & 0x8000)
  37.329 +		dmy |= 0xFFFF8000;
  37.330 +
  37.331 +	if (VCOUNT == 0)
  37.332 +		changed = 3;
  37.333 +
  37.334 +	if (changed & 1)
  37.335 +	{
  37.336 +		currentX = (x_l) | ((x_h & 0x07FF)<<16);
  37.337 +		if (x_h & 0x0800)
  37.338 +			currentX |= 0xF8000000;
  37.339 +	}
  37.340 +	else
  37.341 +	{
  37.342 +		currentX += dmx;
  37.343 +	}
  37.344 +
  37.345 +	if (changed & 2)
  37.346 +	{
  37.347 +		currentY = (y_l) | ((y_h & 0x07FF)<<16);
  37.348 +		if (y_h & 0x0800)
  37.349 +			currentY |= 0xF8000000;
  37.350 +	}
  37.351 +	else
  37.352 +	{
  37.353 +		currentY += dmy;
  37.354 +	}
  37.355 +
  37.356 +	int realX = currentX;
  37.357 +	int realY = currentY;
  37.358 +
  37.359 +	if (control & 0x40)
  37.360 +	{
  37.361 +		int mosaicY = ((MOSAIC & 0xF0)>>4) + 1;
  37.362 +		int y       = (VCOUNT % mosaicY);
  37.363 +		realX -= y*dmx;
  37.364 +		realY -= y*dmy;
  37.365 +	}
  37.366 +
  37.367 +	int xxx = (realX >> 8);
  37.368 +	int yyy = (realY >> 8);
  37.369 +
  37.370 +	if (control & 0x2000)
  37.371 +	{
  37.372 +		xxx %= sizeX;
  37.373 +		yyy %= sizeY;
  37.374 +		if (xxx < 0)
  37.375 +			xxx += sizeX;
  37.376 +		if (yyy < 0)
  37.377 +			yyy += sizeY;
  37.378 +	}
  37.379 +
  37.380 +	if (control & 0x80)
  37.381 +	{
  37.382 +		for (int x = 0; x < 240; x++)
  37.383 +		{
  37.384 +			if (xxx < 0 ||
  37.385 +			    yyy < 0 ||
  37.386 +			    xxx >= sizeX ||
  37.387 +			    yyy >= sizeY)
  37.388 +			{
  37.389 +				line[x] = 0x80000000;
  37.390 +			}
  37.391 +			else
  37.392 +			{
  37.393 +				int tile = screenBase[(xxx>>3) + (yyy>>3)*(sizeX>>3)];
  37.394 +
  37.395 +				int tileX = (xxx & 7);
  37.396 +				int tileY = yyy & 7;
  37.397 +
  37.398 +				u8 color = charBase[(tile<<6) + (tileY<<3) + tileX];
  37.399 +
  37.400 +				line[x] = color ? (READ16LE(&palette[color])|prio) : 0x80000000;
  37.401 +			}
  37.402 +			realX += dx;
  37.403 +			realY += dy;
  37.404 +
  37.405 +			xxx = (realX >> 8);
  37.406 +			yyy = (realY >> 8);
  37.407 +
  37.408 +			if (control & 0x2000)
  37.409 +			{
  37.410 +				xxx %= sizeX;
  37.411 +				yyy %= sizeY;
  37.412 +				if (xxx < 0)
  37.413 +					xxx += sizeX;
  37.414 +				if (yyy < 0)
  37.415 +					yyy += sizeY;
  37.416 +			}
  37.417 +		}
  37.418 +	}
  37.419 +	else
  37.420 +	{
  37.421 +		for (int x = 0; x < 240; x++)
  37.422 +		{
  37.423 +			if (xxx < 0 ||
  37.424 +			    yyy < 0 ||
  37.425 +			    xxx >= sizeX ||
  37.426 +			    yyy >= sizeY)
  37.427 +			{
  37.428 +				line[x] = 0x80000000;
  37.429 +			}
  37.430 +			else
  37.431 +			{
  37.432 +				int tile = screenBase[(xxx>>3) + (yyy>>3)*(sizeX>>3)];
  37.433 +
  37.434 +				int tileX = (xxx & 7);
  37.435 +				int tileY = yyy & 7;
  37.436 +
  37.437 +				u8 color = charBase[(tile<<6) + (tileY<<3) + tileX];
  37.438 +
  37.439 +				line[x] = color ? (READ16LE(&palette[color])|prio) : 0x80000000;
  37.440 +			}
  37.441 +			realX += dx;
  37.442 +			realY += dy;
  37.443 +
  37.444 +			xxx = (realX >> 8);
  37.445 +			yyy = (realY >> 8);
  37.446 +
  37.447 +			if (control & 0x2000)
  37.448 +			{
  37.449 +				xxx %= sizeX;
  37.450 +				yyy %= sizeY;
  37.451 +				if (xxx < 0)
  37.452 +					xxx += sizeX;
  37.453 +				if (yyy < 0)
  37.454 +					yyy += sizeY;
  37.455 +			}
  37.456 +		}
  37.457 +	}
  37.458 +
  37.459 +	if (control & 0x40)
  37.460 +	{
  37.461 +		int mosaicX = (MOSAIC & 0xF) + 1;
  37.462 +		if (mosaicX > 1)
  37.463 +		{
  37.464 +			int m = 1;
  37.465 +			for (int i = 0; i < 239; i++)
  37.466 +			{
  37.467 +				line[i+1] = line[i];
  37.468 +				m++;
  37.469 +				if (m == mosaicX)
  37.470 +				{
  37.471 +					m = 1;
  37.472 +					i++;
  37.473 +				}
  37.474 +			}
  37.475 +		}
  37.476 +	}
  37.477 +}
  37.478 +
  37.479 +inline void gfxDrawRotScreen16Bit(u16 control,
  37.480 +                                  u16 x_l, u16 x_h,
  37.481 +                                  u16 y_l, u16 y_h,
  37.482 +                                  u16 pa,  u16 pb,
  37.483 +                                  u16 pc,  u16 pd,
  37.484 +                                  int& currentX, int& currentY,
  37.485 +                                  int changed,
  37.486 +                                  u32 *line)
  37.487 +{
  37.488 +	u16 *screenBase = (u16 *)&vram[0];
  37.489 +	int  prio       = ((control & 3) << 25) + 0x1000000;
  37.490 +	int  sizeX      = 240;
  37.491 +	int  sizeY      = 160;
  37.492 +
  37.493 +	int startX = (x_l) | ((x_h & 0x07FF)<<16);
  37.494 +	if (x_h & 0x0800)
  37.495 +		startX |= 0xF8000000;
  37.496 +	int startY = (y_l) | ((y_h & 0x07FF)<<16);
  37.497 +	if (y_h & 0x0800)
  37.498 +		startY |= 0xF8000000;
  37.499 +
  37.500 +	int dx = pa & 0x7FFF;
  37.501 +	if (pa & 0x8000)
  37.502 +		dx |= 0xFFFF8000;
  37.503 +	int dmx = pb & 0x7FFF;
  37.504 +	if (pb & 0x8000)
  37.505 +		dmx |= 0xFFFF8000;
  37.506 +	int dy = pc & 0x7FFF;
  37.507 +	if (pc & 0x8000)
  37.508 +		dy |= 0xFFFF8000;
  37.509 +	int dmy = pd & 0x7FFFF;
  37.510 +	if (pd & 0x8000)
  37.511 +		dmy |= 0xFFFF8000;
  37.512 +
  37.513 +	if (VCOUNT == 0)
  37.514 +		changed = 3;
  37.515 +
  37.516 +	if (changed & 1)
  37.517 +	{
  37.518 +		currentX = (x_l) | ((x_h & 0x07FF)<<16);
  37.519 +		if (x_h & 0x0800)
  37.520 +			currentX |= 0xF8000000;
  37.521 +	}
  37.522 +	else
  37.523 +		currentX += dmx;
  37.524 +
  37.525 +	if (changed & 2)
  37.526 +	{
  37.527 +		currentY = (y_l) | ((y_h & 0x07FF)<<16);
  37.528 +		if (y_h & 0x0800)
  37.529 +			currentY |= 0xF8000000;
  37.530 +	}
  37.531 +	else
  37.532 +	{
  37.533 +		currentY += dmy;
  37.534 +	}
  37.535 +
  37.536 +	int realX = currentX;
  37.537 +	int realY = currentY;
  37.538 +
  37.539 +	if (control & 0x40)
  37.540 +	{
  37.541 +		int mosaicY = ((MOSAIC & 0xF0)>>4) + 1;
  37.542 +		int y       = (VCOUNT % mosaicY);
  37.543 +		realX -= y*dmx;
  37.544 +		realY -= y*dmy;
  37.545 +	}
  37.546 +
  37.547 +	int xxx = (realX >> 8);
  37.548 +	int yyy = (realY >> 8);
  37.549 +
  37.550 +	for (int x = 0; x < 240; x++)
  37.551 +	{
  37.552 +		if (xxx < 0 ||
  37.553 +		    yyy < 0 ||
  37.554 +		    xxx >= sizeX ||
  37.555 +		    yyy >= sizeY)
  37.556 +		{
  37.557 +			line[x] = 0x80000000;
  37.558 +		}
  37.559 +		else
  37.560 +		{
  37.561 +			line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio);
  37.562 +		}
  37.563 +		realX += dx;
  37.564 +		realY += dy;
  37.565 +
  37.566 +		xxx = (realX >> 8);
  37.567 +		yyy = (realY >> 8);
  37.568 +	}
  37.569 +
  37.570 +	if (control & 0x40)
  37.571 +	{
  37.572 +		int mosaicX = (MOSAIC & 0xF) + 1;
  37.573 +		if (mosaicX > 1)
  37.574 +		{
  37.575 +			int m = 1;
  37.576 +			for (int i = 0; i < 239; i++)
  37.577 +			{
  37.578 +				line[i+1] = line[i];
  37.579 +				m++;
  37.580 +				if (m == mosaicX)
  37.581 +				{
  37.582 +					m = 1;
  37.583 +					i++;
  37.584 +				}
  37.585 +			}
  37.586 +		}
  37.587 +	}
  37.588 +}
  37.589 +
  37.590 +inline void gfxDrawRotScreen256(u16 control,
  37.591 +                                u16 x_l, u16 x_h,
  37.592 +                                u16 y_l, u16 y_h,
  37.593 +                                u16 pa,  u16 pb,
  37.594 +                                u16 pc,  u16 pd,
  37.595 +                                int &currentX, int& currentY,
  37.596 +                                int changed,
  37.597 +                                u32 *line)
  37.598 +{
  37.599 +	u16 *palette    = (u16 *)paletteRAM;
  37.600 +	u8 * screenBase = (DISPCNT & 0x0010) ? &vram[0xA000] : &vram[0x0000];
  37.601 +	int  prio       = ((control & 3) << 25) + 0x1000000;
  37.602 +	int  sizeX      = 240;
  37.603 +	int  sizeY      = 160;
  37.604 +
  37.605 +	int startX = (x_l) | ((x_h & 0x07FF)<<16);
  37.606 +	if (x_h & 0x0800)
  37.607 +		startX |= 0xF8000000;
  37.608 +	int startY = (y_l) | ((y_h & 0x07FF)<<16);
  37.609 +	if (y_h & 0x0800)
  37.610 +		startY |= 0xF8000000;
  37.611 +
  37.612 +	int dx = pa & 0x7FFF;
  37.613 +	if (pa & 0x8000)
  37.614 +		dx |= 0xFFFF8000;
  37.615 +	int dmx = pb & 0x7FFF;
  37.616 +	if (pb & 0x8000)
  37.617 +		dmx |= 0xFFFF8000;
  37.618 +	int dy = pc & 0x7FFF;
  37.619 +	if (pc & 0x8000)
  37.620 +		dy |= 0xFFFF8000;
  37.621 +	int dmy = pd & 0x7FFFF;
  37.622 +	if (pd & 0x8000)
  37.623 +		dmy |= 0xFFFF8000;
  37.624 +
  37.625 +	if (VCOUNT == 0)
  37.626 +		changed = 3;
  37.627 +
  37.628 +	if (changed & 1)
  37.629 +	{
  37.630 +		currentX = (x_l) | ((x_h & 0x07FF)<<16);
  37.631 +		if (x_h & 0x0800)
  37.632 +			currentX |= 0xF8000000;
  37.633 +	}
  37.634 +	else
  37.635 +	{
  37.636 +		currentX += dmx;
  37.637 +	}
  37.638 +
  37.639 +	if (changed & 2)
  37.640 +	{
  37.641 +		currentY = (y_l) | ((y_h & 0x07FF)<<16);
  37.642 +		if (y_h & 0x0800)
  37.643 +			currentY |= 0xF8000000;
  37.644 +	}
  37.645 +	else
  37.646 +	{
  37.647 +		currentY += dmy;
  37.648 +	}
  37.649 +
  37.650 +	int realX = currentX;
  37.651 +	int realY = currentY;
  37.652 +
  37.653 +	if (control & 0x40)
  37.654 +	{
  37.655 +		int mosaicY = ((MOSAIC & 0xF0)>>4) + 1;
  37.656 +		int y       = (VCOUNT / mosaicY) * mosaicY;
  37.657 +		realX = startX + y*dmx;
  37.658 +		realY = startY + y*dmy;
  37.659 +	}
  37.660 +
  37.661 +	int xxx = (realX >> 8);
  37.662 +	int yyy = (realY >> 8);
  37.663 +
  37.664 +	for (int x = 0; x < 240; x++)
  37.665 +	{
  37.666 +		if (xxx < 0 ||
  37.667 +		    yyy < 0 ||
  37.668 +		    xxx >= sizeX ||
  37.669 +		    yyy >= sizeY)
  37.670 +		{
  37.671 +			line[x] = 0x80000000;
  37.672 +		}
  37.673 +		else
  37.674 +		{
  37.675 +			u8 color = screenBase[yyy * 240 + xxx];
  37.676 +
  37.677 +			line[x] = color ? (READ16LE(&palette[color])|prio) : 0x80000000;
  37.678 +		}
  37.679 +		realX += dx;
  37.680 +		realY += dy;
  37.681 +
  37.682 +		xxx = (realX >> 8);
  37.683 +		yyy = (realY >> 8);
  37.684 +	}
  37.685 +
  37.686 +	if (control & 0x40)
  37.687 +	{
  37.688 +		int mosaicX = (MOSAIC & 0xF) + 1;
  37.689 +		if (mosaicX > 1)
  37.690 +		{
  37.691 +			int m = 1;
  37.692 +			for (int i = 0; i < 239; i++)
  37.693 +			{
  37.694 +				line[i+1] = line[i];
  37.695 +				m++;
  37.696 +				if (m == mosaicX)
  37.697 +				{
  37.698 +					m = 1;
  37.699 +					i++;
  37.700 +				}
  37.701 +			}
  37.702 +		}
  37.703 +	}
  37.704 +}
  37.705 +
  37.706 +inline void gfxDrawRotScreen16Bit160(u16 control,
  37.707 +                                     u16 x_l, u16 x_h,
  37.708 +                                     u16 y_l, u16 y_h,
  37.709 +                                     u16 pa,  u16 pb,
  37.710 +                                     u16 pc,  u16 pd,
  37.711 +                                     int& currentX, int& currentY,
  37.712 +                                     int changed,
  37.713 +                                     u32 *line)
  37.714 +{
  37.715 +	u16 *screenBase = (DISPCNT & 0x0010) ? (u16 *)&vram[0xa000] :
  37.716 +	                  (u16 *)&vram[0];
  37.717 +	int prio  = ((control & 3) << 25) + 0x1000000;
  37.718 +	int sizeX = 160;
  37.719 +	int sizeY = 128;
  37.720 +
  37.721 +	int startX = (x_l) | ((x_h & 0x07FF)<<16);
  37.722 +	if (x_h & 0x0800)
  37.723 +		startX |= 0xF8000000;
  37.724 +	int startY = (y_l) | ((y_h & 0x07FF)<<16);
  37.725 +	if (y_h & 0x0800)
  37.726 +		startY |= 0xF8000000;
  37.727 +
  37.728 +	int dx = pa & 0x7FFF;
  37.729 +	if (pa & 0x8000)
  37.730 +		dx |= 0xFFFF8000;
  37.731 +	int dmx = pb & 0x7FFF;
  37.732 +	if (pb & 0x8000)
  37.733 +		dmx |= 0xFFFF8000;
  37.734 +	int dy = pc & 0x7FFF;
  37.735 +	if (pc & 0x8000)
  37.736 +		dy |= 0xFFFF8000;
  37.737 +	int dmy = pd & 0x7FFFF;
  37.738 +	if (pd & 0x8000)
  37.739 +		dmy |= 0xFFFF8000;
  37.740 +
  37.741 +	if (VCOUNT == 0)
  37.742 +		changed = 3;
  37.743 +
  37.744 +	if (changed & 1)
  37.745 +	{
  37.746 +		currentX = (x_l) | ((x_h & 0x07FF)<<16);
  37.747 +		if (x_h & 0x0800)
  37.748 +			currentX |= 0xF8000000;
  37.749 +	}
  37.750 +	else
  37.751 +	{
  37.752 +		currentX += dmx;
  37.753 +	}
  37.754 +
  37.755 +	if (changed & 2)
  37.756 +	{
  37.757 +		currentY = (y_l) | ((y_h & 0x07FF)<<16);
  37.758 +		if (y_h & 0x0800)
  37.759 +			currentY |= 0xF8000000;
  37.760 +	}
  37.761 +	else
  37.762 +	{
  37.763 +		currentY += dmy;
  37.764 +	}
  37.765 +
  37.766 +	int realX = currentX;
  37.767 +	int realY = currentY;
  37.768 +
  37.769 +	if (control & 0x40)
  37.770 +	{
  37.771 +		int mosaicY = ((MOSAIC & 0xF0)>>4) + 1;
  37.772 +		int y       = (VCOUNT / mosaicY) * mosaicY;
  37.773 +		realX = startX + y*dmx;
  37.774 +		realY = startY + y*dmy;
  37.775 +	}
  37.776 +
  37.777 +	int xxx = (realX >> 8);
  37.778 +	int yyy = (realY >> 8);
  37.779 +
  37.780 +	for (int x = 0; x < 240; x++)
  37.781 +	{
  37.782 +		if (xxx < 0 ||
  37.783 +		    yyy < 0 ||
  37.784 +		    xxx >= sizeX ||
  37.785 +		    yyy >= sizeY)
  37.786 +		{
  37.787 +			line[x] = 0x80000000;
  37.788 +		}
  37.789 +		else
  37.790 +		{
  37.791 +			line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio);
  37.792 +		}
  37.793 +		realX += dx;
  37.794 +		realY += dy;
  37.795 +
  37.796 +		xxx = (realX >> 8);
  37.797 +		yyy = (realY >> 8);
  37.798 +	}
  37.799 +
  37.800 +	if (control & 0x40)
  37.801 +	{
  37.802 +		int mosaicX = (MOSAIC & 0xF) + 1;
  37.803 +		if (mosaicX > 1)
  37.804 +		{
  37.805 +			int m = 1;
  37.806 +			for (int i = 0; i < 239; i++)
  37.807 +			{
  37.808 +				line[i+1] = line[i];
  37.809 +				m++;
  37.810 +				if (m == mosaicX)
  37.811 +				{
  37.812 +					m = 1;
  37.813 +					i++;
  37.814 +				}
  37.815 +			}
  37.816 +		}
  37.817 +	}
  37.818 +}
  37.819 +
  37.820 +inline void gfxDrawSprites(u32 *lineOBJ)
  37.821 +{
  37.822 +	int m = 0;
  37.823 +	gfxClearArray(lineOBJ);
  37.824 +	if (layerEnable & 0x1000)
  37.825 +	{
  37.826 +		u16 *sprites       = (u16 *)oam;
  37.827 +		u16 *spritePalette = &((u16 *)paletteRAM)[256];
  37.828 +		int  mosaicY       = ((MOSAIC & 0xF000)>>12) + 1;
  37.829 +		int  mosaicX       = ((MOSAIC & 0xF00)>>8) + 1;
  37.830 +		for (int x = 0; x < 128; x++)
  37.831 +		{
  37.832 +			u16 a0 = READ16LE(sprites++);
  37.833 +			u16 a1 = READ16LE(sprites++);
  37.834 +			u16 a2 = READ16LE(sprites++);
  37.835 +			sprites++;
  37.836 +
  37.837 +			// ignore OBJ-WIN
  37.838 +			if ((a0 & 0x0c00) == 0x0800)
  37.839 +				continue;
  37.840 +
  37.841 +			int sizeY = 8;
  37.842 +			int sizeX = 8;
  37.843 +
  37.844 +			switch (((a0 >>12) & 0x0c)|(a1>>14))
  37.845 +			{
  37.846 +			case 0:
  37.847 +				break;
  37.848 +			case 1:
  37.849 +				sizeX = sizeY = 16;
  37.850 +				break;
  37.851 +			case 2:
  37.852 +				sizeX = sizeY = 32;
  37.853 +				break;
  37.854 +			case 3:
  37.855 +				sizeX = sizeY = 64;
  37.856 +				break;
  37.857 +			case 4:
  37.858 +				sizeX = 16;
  37.859 +				break;
  37.860 +			case 5:
  37.861 +				sizeX = 32;
  37.862 +				break;
  37.863 +			case 6:
  37.864 +				sizeX = 32;
  37.865 +				sizeY = 16;
  37.866 +				break;
  37.867 +			case 7:
  37.868 +				sizeX = 64;
  37.869 +				sizeY = 32;
  37.870 +				break;
  37.871 +			case 8:
  37.872 +				sizeY = 16;
  37.873 +				break;
  37.874 +			case 9:
  37.875 +				sizeY = 32;
  37.876 +				break;
  37.877 +			case 10:
  37.878 +				sizeX = 16;
  37.879 +				sizeY = 32;
  37.880 +				break;
  37.881 +			case 11:
  37.882 +				sizeX = 32;
  37.883 +				sizeY = 64;
  37.884 +				break;
  37.885 +			default:
  37.886 +				continue;
  37.887 +			}
  37.888 +
  37.889 +#ifdef SPRITE_DEBUG
  37.890 +			int maskX = sizeX-1;
  37.891 +			int maskY = sizeY-1;
  37.892 +#endif
  37.893 +
  37.894 +			int sy = (a0 & 255);
  37.895 +
  37.896 +			if (sy > 160)
  37.897 +				sy -= 256;
  37.898 +
  37.899 +			if (a0 & 0x0100)
  37.900 +			{
  37.901 +				int fieldX = sizeX;
  37.902 +				int fieldY = sizeY;
  37.903 +				if (a0 & 0x0200)
  37.904 +				{
  37.905 +					fieldX <<= 1;
  37.906 +					fieldY <<= 1;
  37.907 +				}
  37.908 +
  37.909 +				int t = VCOUNT - sy;
  37.910 +				if ((t >= 0) && (t < fieldY))
  37.911 +				{
  37.912 +					int sx = (a1 & 0x1FF);
  37.913 +					if ((sx < 240) || (((sx + fieldX) & 511) < 240))
  37.914 +					{
  37.915 +						// int t2 = t - (fieldY >> 1);
  37.916 +						int  rot = (a1 >> 9) & 0x1F;
  37.917 +						u16 *OAM = (u16 *)oam;
  37.918 +						int  dx  = READ16LE(&OAM[3 + (rot << 4)]);
  37.919 +						if (dx & 0x8000)
  37.920 +							dx |= 0xFFFF8000;
  37.921 +						int dmx = READ16LE(&OAM[7 + (rot << 4)]);
  37.922 +						if (dmx & 0x8000)
  37.923 +							dmx |= 0xFFFF8000;
  37.924 +						int dy = READ16LE(&OAM[11 + (rot << 4)]);
  37.925 +						if (dy & 0x8000)
  37.926 +							dy |= 0xFFFF8000;
  37.927 +						int dmy = READ16LE(&OAM[15 + (rot << 4)]);
  37.928 +						if (dmy & 0x8000)
  37.929 +							dmy |= 0xFFFF8000;
  37.930 +
  37.931 +						if (a0 & 0x1000)
  37.932 +						{
  37.933 +							t -= (t % mosaicY);
  37.934 +						}
  37.935 +
  37.936 +						int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx
  37.937 +						            + t * dmx;
  37.938 +						int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy
  37.939 +						            + t * dmy;
  37.940 +
  37.941 +						u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6);
  37.942 +
  37.943 +						if (a0 & 0x2000)
  37.944 +						{
  37.945 +							int c = (a2 & 0x3FF);
  37.946 +							if ((DISPCNT & 7) > 2 && (c < 512))
  37.947 +								continue;
  37.948 +							int inc = 32;
  37.949 +							if (DISPCNT & 0x40)
  37.950 +								inc = sizeX >> 2;
  37.951 +							else
  37.952 +								c &= 0x3FE;
  37.953 +							for (int x = 0; x < fieldX; x++)
  37.954 +							{
  37.955 +								int xxx = realX >> 8;
  37.956 +								int yyy = realY >> 8;
  37.957 +
  37.958 +								if (xxx < 0 || xxx >= sizeX ||
  37.959 +								    yyy < 0 || yyy >= sizeY ||
  37.960 +								    sx >= 240)
  37.961 +									;
  37.962 +								else
  37.963 +								{
  37.964 +									u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5)
  37.965 +									                             + ((yyy & 7)<<3) + ((xxx >> 3)<<6) +
  37.966 +									                             (xxx & 7))&0x7FFF)];
  37.967 +									if ((color == 0) && (((prio >> 25)&3) <
  37.968 +									                     ((lineOBJ[sx]>>25)&3)))
  37.969 +									{
  37.970 +										lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio;
  37.971 +										if ((a0 & 0x1000) && m)
  37.972 +											lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
  37.973 +									}
  37.974 +									else if ((color) && (prio < (lineOBJ[sx]&0xFF000000)))
  37.975 +									{
  37.976 +										lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio;
  37.977 +										if ((a0 & 0x1000) && m)
  37.978 +											lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
  37.979 +									}
  37.980 +
  37.981 +									if (a0 & 0x1000)
  37.982 +									{
  37.983 +										m++;
  37.984 +										if (m == mosaicX)
  37.985 +											m = 0;
  37.986 +									}
  37.987 +#ifdef SPRITE_DEBUG
  37.988 +									if (t == 0 || t == maskY || x == 0 || x == maskX)
  37.989 +										lineOBJ[sx] = 0x001F;
  37.990 +#endif
  37.991 +								}
  37.992 +								sx     = (sx+1)&511;;
  37.993 +								realX += dx;
  37.994 +								realY += dy;
  37.995 +							}
  37.996 +						}
  37.997 +						else
  37.998 +						{
  37.999 +							int c = (a2 & 0x3FF);
 37.1000 +							if ((DISPCNT & 7) > 2 && (c < 512))
 37.1001 +								continue;
 37.1002 +
 37.1003 +							int inc = 32;
 37.1004 +							if (DISPCNT & 0x40)
 37.1005 +								inc = sizeX >> 3;
 37.1006 +							int palette = (a2 >> 8) & 0xF0;
 37.1007 +							for (int x = 0; x < fieldX; x++)
 37.1008 +							{
 37.1009 +								int xxx = realX >> 8;
 37.1010 +								int yyy = realY >> 8;
 37.1011 +								if (xxx < 0 || xxx >= sizeX ||
 37.1012 +								    yyy < 0 || yyy >= sizeY ||
 37.1013 +								    sx >= 240)
 37.1014 +									;
 37.1015 +								else
 37.1016 +								{
 37.1017 +									u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5)
 37.1018 +									                             + ((yyy & 7)<<2) + ((xxx >> 3)<<5) +
 37.1019 +									                             ((xxx & 7)>>1))&0x7FFF)];
 37.1020 +									if (xxx & 1)
 37.1021 +										color >>= 4;
 37.1022 +									else
 37.1023 +										color &= 0x0F;
 37.1024 +
 37.1025 +									if ((color == 0) && (((prio >> 25)&3) <
 37.1026 +									                     ((lineOBJ[sx]>>25)&3)))
 37.1027 +									{
 37.1028 +										lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio;
 37.1029 +										if ((a0 & 0x1000) && m)
 37.1030 +											lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
 37.1031 +									}
 37.1032 +									else if ((color) && (prio < (lineOBJ[sx]&0xFF000000)))
 37.1033 +									{
 37.1034 +										lineOBJ[sx] = READ16LE(&spritePalette[palette+color]) | prio;
 37.1035 +										if ((a0 & 0x1000) && m)
 37.1036 +											lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
 37.1037 +									}
 37.1038 +								}
 37.1039 +								if ((a0 & 0x1000) && m)
 37.1040 +								{
 37.1041 +									m++;
 37.1042 +									if (m == mosaicX)
 37.1043 +										m = 0;
 37.1044 +								}
 37.1045 +
 37.1046 +#ifdef SPRITE_DEBUG
 37.1047 +								if (t == 0 || t == maskY || x == 0 || x == maskX)
 37.1048 +									lineOBJ[sx] = 0x001F;
 37.1049 +#endif
 37.1050 +								sx     = (sx+1)&511;;
 37.1051 +								realX += dx;
 37.1052 +								realY += dy;
 37.1053 +							}
 37.1054 +						}
 37.1055 +					}
 37.1056 +				}
 37.1057 +			}
 37.1058 +			else
 37.1059 +			{
 37.1060 +				int t = VCOUNT - sy;
 37.1061 +				if ((t >= 0) && (t < sizeY))
 37.1062 +				{
 37.1063 +					int sx = (a1 & 0x1FF);
 37.1064 +					if (((sx < 240) || (((sx+sizeX)&511) < 240)) && !(a0 & 0x0200))
 37.1065 +					{
 37.1066 +						if (a0 & 0x2000)
 37.1067 +						{
 37.1068 +							if (a1 & 0x2000)
 37.1069 +								t = sizeY - t - 1;
 37.1070 +							int c = (a2 & 0x3FF);
 37.1071 +							if ((DISPCNT & 7) > 2 && (c < 512))
 37.1072 +								continue;
 37.1073 +
 37.1074 +							int inc = 32;
 37.1075 +							if (DISPCNT & 0x40)
 37.1076 +							{
 37.1077 +								inc = sizeX >> 2;
 37.1078 +							}
 37.1079 +							else
 37.1080 +							{
 37.1081 +								c &= 0x3FE;
 37.1082 +							}
 37.1083 +							int xxx = 0;
 37.1084 +							if (a1 & 0x1000)
 37.1085 +								xxx = sizeX-1;
 37.1086 +
 37.1087 +							if (a0 & 0x1000)
 37.1088 +							{
 37.1089 +								t -= (t % mosaicY);
 37.1090 +							}
 37.1091 +
 37.1092 +							int address = 0x10000 + ((((c+ (t>>3) * inc) << 5)
 37.1093 +							                          + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7)) & 0x7FFF);
 37.1094 +
 37.1095 +							if (a1 & 0x1000)
 37.1096 +								xxx = 7;
 37.1097 +							u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6);
 37.1098 +
 37.1099 +							for (int xx = 0; xx < sizeX; xx++)
 37.1100 +							{
 37.1101 +								if (sx < 240)
 37.1102 +								{
 37.1103 +									u8 color = vram[address];
 37.1104 +									if ((color == 0) && (((prio >> 25)&3) <
 37.1105 +									                     ((lineOBJ[sx]>>25)&3)))
 37.1106 +									{
 37.1107 +										lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio;
 37.1108 +										if ((a0 & 0x1000) && m)
 37.1109 +											lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
 37.1110 +									}
 37.1111 +									else if ((color) && (prio < (lineOBJ[sx]&0xFF000000)))
 37.1112 +									{
 37.1113 +										lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio;
 37.1114 +										if ((a0 & 0x1000) && m)
 37.1115 +											lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
 37.1116 +									}
 37.1117 +
 37.1118 +									if (a0 & 0x1000)
 37.1119 +									{
 37.1120 +										m++;
 37.1121 +										if (m == mosaicX)
 37.1122 +											m = 0;
 37.1123 +									}
 37.1124 +
 37.1125 +#ifdef SPRITE_DEBUG
 37.1126 +									if (t == 0 || t == maskY || xx == 0 || xx == maskX)
 37.1127 +										lineOBJ[sx] = 0x001F;
 37.1128 +#endif
 37.1129 +								}
 37.1130 +
 37.1131 +								sx = (sx+1) & 511;
 37.1132 +								if (a1 & 0x1000)
 37.1133 +								{
 37.1134 +									xxx--;
 37.1135 +									address--;
 37.1136 +									if (xxx == -1)
 37.1137 +									{
 37.1138 +										address -= 56;
 37.1139 +										xxx      = 7;
 37.1140 +									}
 37.1141 +									if (address < 0x10000)
 37.1142 +										address += 0x8000;
 37.1143 +								}
 37.1144 +								else
 37.1145 +								{
 37.1146 +									xxx++;
 37.1147 +									address++;
 37.1148 +									if (xxx == 8)
 37.1149 +									{
 37.1150 +										address += 56;
 37.1151 +										xxx      = 0;
 37.1152 +									}
 37.1153 +									if (address > 0x17fff)
 37.1154 +										address -= 0x8000;
 37.1155 +								}
 37.1156 +							}
 37.1157 +						}
 37.1158 +						else
 37.1159 +						{
 37.1160 +							if (a1 & 0x2000)
 37.1161 +								t = sizeY - t - 1;
 37.1162 +							int c = (a2 & 0x3FF);
 37.1163 +							if ((DISPCNT & 7) > 2 && (c < 512))
 37.1164 +								continue;
 37.1165 +
 37.1166 +							int inc = 32;
 37.1167 +							if (DISPCNT & 0x40)
 37.1168 +							{
 37.1169 +								inc = sizeX >> 3;
 37.1170 +							}
 37.1171 +							int xxx = 0;
 37.1172 +							if (a1 & 0x1000)
 37.1173 +								xxx = sizeX - 1;
 37.1174 +
 37.1175 +							if (a0 & 0x1000)
 37.1176 +							{
 37.1177 +								t -= (t % mosaicY);
 37.1178 +							}
 37.1179 +
 37.1180 +							int address = 0x10000 + ((((c + (t>>3) * inc)<<5)
 37.1181 +							                          + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7FFF);
 37.1182 +							u32 prio    = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6);
 37.1183 +							int palette = (a2 >> 8) & 0xF0;
 37.1184 +							if (a1 & 0x1000)
 37.1185 +							{
 37.1186 +								xxx = 7;
 37.1187 +								for (int xx = sizeX - 1; xx >= 0; xx--)
 37.1188 +								{
 37.1189 +									if (sx < 240)
 37.1190 +									{
 37.1191 +										u8 color = vram[address];
 37.1192 +										if (xx & 1)
 37.1193 +										{
 37.1194 +											color = (color >> 4);
 37.1195 +										}
 37.1196 +										else
 37.1197 +											color &= 0x0F;
 37.1198 +
 37.1199 +										if ((color == 0) && (((prio >> 25)&3) <
 37.1200 +										                     ((lineOBJ[sx]>>25)&3)))
 37.1201 +										{
 37.1202 +											lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio;
 37.1203 +											if ((a0 & 0x1000) && m)
 37.1204 +												lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
 37.1205 +										}
 37.1206 +										else if ((color) && (prio < (lineOBJ[sx]&0xFF000000)))
 37.1207 +										{
 37.1208 +											lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio;
 37.1209 +											if ((a0 & 0x1000) && m)
 37.1210 +												lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
 37.1211 +										}
 37.1212 +									}
 37.1213 +									if (a0 & 0x1000)
 37.1214 +									{
 37.1215 +										m++;
 37.1216 +										if (m == mosaicX)
 37.1217 +											m = 0;
 37.1218 +									}
 37.1219 +#ifdef SPRITE_DEBUG
 37.1220 +									if (t == 0 || t == maskY || xx == 0 || xx == maskX)
 37.1221 +										lineOBJ[sx] = 0x001F;
 37.1222 +#endif
 37.1223 +									sx = (sx+1) & 511;
 37.1224 +									xxx--;
 37.1225 +									if (!(xx & 1))
 37.1226 +										address--;
 37.1227 +									if (xxx == -1)
 37.1228 +									{
 37.1229 +										xxx      = 7;
 37.1230 +										address -= 28;
 37.1231 +									}
 37.1232 +									if (address < 0x10000)
 37.1233 +										address += 0x8000;
 37.1234 +								}
 37.1235 +							}
 37.1236 +							else
 37.1237 +							{
 37.1238 +								for (int xx = 0; xx < sizeX; xx++)
 37.1239 +								{
 37.1240 +									if (sx < 240)
 37.1241 +									{
 37.1242 +										u8 color = vram[address];
 37.1243 +										if (xx & 1)
 37.1244 +										{
 37.1245 +											color = (color >> 4);
 37.1246 +										}
 37.1247 +										else
 37.1248 +											color &= 0x0F;
 37.1249 +
 37.1250 +										if ((color == 0) && (((prio >> 25)&3) <
 37.1251 +										                     ((lineOBJ[sx]>>25)&3)))
 37.1252 +										{
 37.1253 +											lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio;
 37.1254 +											if ((a0 & 0x1000) && m)
 37.1255 +												lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
 37.1256 +										}
 37.1257 +										else if ((color) && (prio < (lineOBJ[sx]&0xFF000000)))
 37.1258 +										{
 37.1259 +											lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio;
 37.1260 +											if ((a0 & 0x1000) && m)
 37.1261 +												lineOBJ[sx] = (lineOBJ[sx-1] & 0xF9FFFFFF) | prio;
 37.1262 +										}
 37.1263 +									}
 37.1264 +									if (a0 & 0x1000)
 37.1265 +									{
 37.1266 +										m++;
 37.1267 +										if (m == mosaicX)
 37.1268 +											m = 0;
 37.1269 +									}
 37.1270 +#ifdef SPRITE_DEBUG
 37.1271 +									if (t == 0 || t == maskY || xx == 0 || xx == maskX)
 37.1272 +										lineOBJ[sx] = 0x001F;
 37.1273 +#endif
 37.1274 +									sx = (sx+1) & 511;
 37.1275 +									xxx++;
 37.1276 +									if (xx & 1)
 37.1277 +										address++;
 37.1278 +									if (xxx == 8)
 37.1279 +									{
 37.1280 +										address += 28;
 37.1281 +										xxx      = 0;
 37.1282 +									}
 37.1283 +									if (address > 0x17fff)
 37.1284 +										address -= 0x8000;
 37.1285 +								}
 37.1286 +							}
 37.1287 +						}
 37.1288 +					}
 37.1289 +				}
 37.1290 +			}
 37.1291 +		}
 37.1292 +	}
 37.1293 +}
 37.1294 +
 37.1295 +inline void gfxDrawOBJWin(u32 *lineOBJWin)
 37.1296 +{
 37.1297 +	gfxClearArray(lineOBJWin);
 37.1298 +	if (layerEnable & 0x8000)
 37.1299 +	{
 37.1300 +		u16 *sprites = (u16 *)oam;
 37.1301 +		// u16 *spritePalette = &((u16 *)paletteRAM)[256];
 37.1302 +		for (int x = 0; x < 128; x++)
 37.1303 +		{
 37.1304 +			u16 a0 = READ16LE(sprites++);
 37.1305 +			u16 a1 = READ16LE(sprites++);
 37.1306 +			u16 a2 = READ16LE(sprites++);
 37.1307 +			sprites++;
 37.1308 +
 37.1309 +			// ignore non OBJ-WIN
 37.1310 +			if ((a0 & 0x0c00) != 0x0800)
 37.1311 +				continue;
 37.1312 +
 37.1313 +			int sizeY = 8;
 37.1314 +			int sizeX = 8;
 37.1315 +
 37.1316 +			switch (((a0 >>12) & 0x0c)|(a1>>14))
 37.1317 +			{
 37.1318 +			case 0:
 37.1319 +				break;
 37.1320 +			case 1:
 37.1321 +				sizeX = sizeY = 16;
 37.1322 +				break;
 37.1323 +			case 2:
 37.1324 +				sizeX = sizeY = 32;
 37.1325 +				break;
 37.1326 +			case 3:
 37.1327 +				sizeX = sizeY = 64;
 37.1328 +				break;
 37.1329 +			case 4:
 37.1330 +				sizeX = 16;
 37.1331 +				break;
 37.1332 +			case 5:
 37.1333 +				sizeX = 32;
 37.1334 +				break;
 37.1335 +			case 6:
 37.1336 +				sizeX = 32;
 37.1337 +				sizeY = 16;
 37.1338 +				break;
 37.1339 +			case 7:
 37.1340 +				sizeX = 64;
 37.1341 +				sizeY = 32;
 37.1342 +				break;
 37.1343 +			case 8:
 37.1344 +				sizeY = 16;
 37.1345 +				break;
 37.1346 +			case 9:
 37.1347 +				sizeY = 32;
 37.1348 +				break;
 37.1349 +			case 10:
 37.1350 +				sizeX = 16;
 37.1351 +				sizeY = 32;
 37.1352 +				break;
 37.1353 +			case 11:
 37.1354 +				sizeX = 32;
 37.1355 +				sizeY = 64;
 37.1356 +				break;
 37.1357 +			default:
 37.1358 +				continue;
 37.1359 +			}
 37.1360 +
 37.1361 +			int sy = (a0 & 255);
 37.1362 +
 37.1363 +			if (sy > 160)
 37.1364 +				sy -= 256;
 37.1365 +
 37.1366 +			if (a0 & 0x0100)
 37.1367 +			{
 37.1368 +				int fieldX = sizeX;
 37.1369 +				int fieldY = sizeY;
 37.1370 +				if (a0 & 0x0200)
 37.1371 +				{
 37.1372 +					fieldX <<= 1;
 37.1373 +					fieldY <<= 1;
 37.1374 +				}
 37.1375 +
 37.1376 +				int t = VCOUNT - sy;
 37.1377 +				if ((t >= 0) && (t < fieldY))
 37.1378 +				{
 37.1379 +					int sx = (a1 & 0x1FF);
 37.1380 +					if ((sx < 240) || (((sx + fieldX) & 511) < 240))
 37.1381 +					{
 37.1382 +						// int t2 = t - (fieldY >> 1);
 37.1383 +						int  rot = (a1 >> 9) & 0x1F;
 37.1384 +						u16 *OAM = (u16 *)oam;
 37.1385 +						int  dx  = READ16LE(&OAM[3 + (rot << 4)]);
 37.1386 +						if (dx & 0x8000)
 37.1387 +							dx |= 0xFFFF8000;
 37.1388 +						int dmx = READ16LE(&OAM[7 + (rot << 4)]);
 37.1389 +						if (dmx & 0x8000)
 37.1390 +							dmx |= 0xFFFF8000;
 37.1391 +						int dy = READ16LE(&OAM[11 + (rot << 4)]);
 37.1392 +						if (dy & 0x8000)
 37.1393 +							dy |= 0xFFFF8000;
 37.1394 +						int dmy = READ16LE(&OAM[15 + (rot << 4)]);
 37.1395 +						if (dmy & 0x8000)
 37.1396 +							dmy |= 0xFFFF8000;
 37.1397 +
 37.1398 +						int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx
 37.1399 +						            + t * dmx;
 37.1400 +						int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy
 37.1401 +						            + t * dmy;
 37.1402 +
 37.1403 +						// u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6);
 37.1404 +
 37.1405 +						if (a0 & 0x2000)
 37.1406 +						{
 37.1407 +							int c = (a2 & 0x3FF);
 37.1408 +							if ((DISPCNT & 7) > 2 && (c < 512))
 37.1409 +								continue;
 37.1410 +							int inc = 32;
 37.1411 +							if (DISPCNT & 0x40)
 37.1412 +								inc = sizeX >> 2;
 37.1413 +							else
 37.1414 +								c &= 0x3FE;
 37.1415 +							for (int x = 0; x < fieldX; x++)
 37.1416 +							{
 37.1417 +								int xxx = realX >> 8;
 37.1418 +								int yyy = realY >> 8;
 37.1419 +
 37.1420 +								if (xxx < 0 || xxx >= sizeX ||
 37.1421 +								    yyy < 0 || yyy >= sizeY)
 37.1422 +								{}
 37.1423 +								else
 37.1424 +								{
 37.1425 +									u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5)
 37.1426 +									                             + ((yyy & 7)<<3) + ((xxx >> 3)<<6) +
 37.1427 +									                             (xxx & 7))&0x7fff)];
 37.1428 +									if (color)
 37.1429 +									{
 37.1430 +										lineOBJWin[sx] = 1;
 37.1431 +									}
 37.1432 +								}
 37.1433 +								sx     = (sx+1)&511;;
 37.1434 +								realX += dx;
 37.1435 +								realY += dy;
 37.1436 +							}
 37.1437 +						}
 37.1438 +						else
 37.1439 +						{
 37.1440 +							int c = (a2 & 0x3FF);
 37.1441 +							if ((DISPCNT & 7) > 2 && (c < 512))
 37.1442 +								continue;
 37.1443 +
 37.1444 +							int inc = 32;
 37.1445 +							if (DISPCNT & 0x40)
 37.1446 +								inc = sizeX >> 3;
 37.1447 +							// int palette = (a2 >> 8) & 0xF0;
 37.1448 +							for (int x = 0; x < fieldX; x++)
 37.1449 +							{
 37.1450 +								int xxx = realX >> 8;
 37.1451 +								int yyy = realY >> 8;
 37.1452 +
 37.1453 +								//              if(x == 0 || x == (sizeX-1) ||
 37.1454 +								//                 t == 0 || t == (sizeY-1)) {
 37.1455 +								//                lineOBJ[sx] = 0x001F | prio;
 37.1456 +								//              } else {
 37.1457 +								if (xxx < 0 || xxx >= sizeX ||
 37.1458 +								    yyy < 0 || yyy >= sizeY)
 37.1459 +								{}
 37.1460 +								else
 37.1461 +								{
 37.1462 +									u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5)
 37.1463 +									                             + ((yyy & 7)<<2) + ((xxx >> 3)<<5) +
 37.1464 +									                             ((xxx & 7)>>1))&0x7fff)];
 37.1465 +									if (xxx & 1)
 37.1466 +										color >>= 4;
 37.1467 +									else
 37.1468 +										color &= 0x0F;
 37.1469 +
 37.1470 +									if (color)
 37.1471 +									{
 37.1472 +										lineOBJWin[sx] = 1;
 37.1473 +									}
 37.1474 +								}
 37.1475 +								//            }
 37.1476 +								sx     = (sx+1)&511;;
 37.1477 +								realX += dx;
 37.1478 +								realY += dy;
 37.1479 +							}
 37.1480 +						}
 37.1481 +					}
 37.1482 +				}
 37.1483 +			}
 37.1484 +			else
 37.1485 +			{
 37.1486 +				int t = VCOUNT - sy;
 37.1487 +				if ((t >= 0) && (t < sizeY))
 37.1488 +				{
 37.1489 +					int sx = (a1 & 0x1FF);
 37.1490 +					if (((sx < 240) || (((sx+sizeX)&511) < 240)) && !(a0 & 0x0200))
 37.1491 +					{
 37.1492 +						if (a0 & 0x2000)
 37.1493 +						{
 37.1494 +							if (a1 & 0x2000)
 37.1495 +								t = sizeY - t - 1;
 37.1496 +							int c = (a2 & 0x3FF);
 37.1497 +							if ((DISPCNT & 7) > 2 && (c < 512))
 37.1498 +								continue;
 37.1499 +
 37.1500 +							int inc = 32;
 37.1501 +							if (DISPCNT & 0x40)
 37.1502 +							{
 37.1503 +								inc = sizeX >> 2;
 37.1504 +							}
 37.1505 +							else
 37.1506 +							{
 37.1507 +								c &= 0x3FE;
 37.1508 +							}
 37.1509 +							int xxx = 0;
 37.1510 +							if (a1 & 0x1000)
 37.1511 +								xxx = sizeX-1;
 37.1512 +							int address = 0x10000 + ((((c+ (t>>3) * inc) << 5)
 37.1513 +							                          + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7))&0x7fff);
 37.1514 +							if (a1 & 0x1000)
 37.1515 +								xxx = 7;
 37.1516 +							// u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6);
 37.1517 +							for (int xx = 0; xx < sizeX; xx++)
 37.1518 +							{
 37.1519 +								if (sx < 240)
 37.1520 +								{
 37.1521 +									u8 color = vram[address];
 37.1522 +									if (color)
 37.1523 +									{
 37.1524 +										lineOBJWin[sx] = 1;
 37.1525 +									}
 37.1526 +								}
 37.1527 +
 37.1528 +								sx = (sx+1) & 511;
 37.1529 +								if (a1 & 0x1000)
 37.1530 +								{
 37.1531 +									xxx--;
 37.1532 +									address--;
 37.1533 +									if (xxx == -1)
 37.1534 +									{
 37.1535 +										address -= 56;
 37.1536 +										xxx      = 7;
 37.1537 +									}
 37.1538 +									if (address < 0x10000)
 37.1539 +										address += 0x8000;
 37.1540 +								}
 37.1541 +								else
 37.1542 +								{
 37.1543 +									xxx++;
 37.1544 +									address++;
 37.1545 +									if (xxx == 8)
 37.1546 +									{
 37.1547 +										address += 56;
 37.1548 +										xxx      = 0;
 37.1549 +									}
 37.1550 +									if (address > 0x17fff)
 37.1551 +										address -= 0x8000;
 37.1552 +								}
 37.1553 +							}
 37.1554 +						}
 37.1555 +						else
 37.1556 +						{
 37.1557 +							if (a1 & 0x2000)
 37.1558 +								t = sizeY - t - 1;
 37.1559 +							int c = (a2 & 0x3FF);
 37.1560 +							if ((DISPCNT & 7) > 2 && (c < 512))
 37.1561 +								continue;
 37.1562 +
 37.1563 +							int inc = 32;
 37.1564 +							if (DISPCNT & 0x40)
 37.1565 +							{
 37.1566 +								inc = sizeX >> 3;
 37.1567 +							}
 37.1568 +							int xxx = 0;
 37.1569 +							if (a1 & 0x1000)
 37.1570 +								xxx = sizeX - 1;
 37.1571 +							int address = 0x10000 + ((((c + (t>>3) * inc)<<5)
 37.1572 +							                          + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7fff);
 37.1573 +							// u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6);
 37.1574 +							// int palette = (a2 >> 8) & 0xF0;
 37.1575 +							if (a1 & 0x1000)
 37.1576 +							{
 37.1577 +								xxx = 7;
 37.1578 +								for (int xx = sizeX - 1; xx >= 0; xx--)
 37.1579 +								{
 37.1580 +									if (sx < 240)
 37.1581 +									{
 37.1582 +										u8 color = vram[address];
 37.1583 +										if (xx & 1)
 37.1584 +										{
 37.1585 +											color = (color >> 4);
 37.1586 +										}
 37.1587 +										else
 37.1588 +											color &= 0x0F;
 37.1589 +
 37.1590 +										if (color)
 37.1591 +										{
 37.1592 +											lineOBJWin[sx] = 1;
 37.1593 +										}
 37.1594 +									}
 37.1595 +									sx = (sx+1) & 511;
 37.1596 +									xxx--;
 37.1597 +									if (!(xx & 1))
 37.1598 +										address--;
 37.1599 +									if (xxx == -1)
 37.1600 +									{
 37.1601 +										xxx      = 7;
 37.1602 +										address -= 28;
 37.1603 +									}
 37.1604 +									if (address < 0x10000)
 37.1605 +										address += 0x8000;
 37.1606 +								}
 37.1607 +							}
 37.1608 +							else
 37.1609 +							{
 37.1610 +								for (int xx = 0; xx < sizeX; xx++)
 37.1611 +								{
 37.1612 +									if (sx < 240)
 37.1613 +									{
 37.1614 +										u8 color = vram[address];
 37.1615 +										if (xx & 1)
 37.1616 +										{
 37.1617 +											color = (color >> 4);
 37.1618 +										}
 37.1619 +										else
 37.1620 +											color &= 0x0F;
 37.1621 +
 37.1622 +										if (color)
 37.1623 +										{
 37.1624 +											lineOBJWin[sx] = 1;
 37.1625 +										}
 37.1626 +									}
 37.1627 +									sx = (sx+1) & 511;
 37.1628 +									xxx++;
 37.1629 +									if (xx & 1)
 37.1630 +										address++;
 37.1631 +									if (xxx == 8)
 37.1632 +									{
 37.1633 +										address += 28;
 37.1634 +										xxx      = 0;
 37.1635 +									}
 37.1636 +									if (address > 0x17fff)
 37.1637 +										address -= 0x8000;
 37.1638 +								}
 37.1639 +							}
 37.1640 +						}
 37.1641 +					}
 37.1642 +				}
 37.1643 +			}
 37.1644 +		}
 37.1645 +	}
 37.1646 +}
 37.1647 +
 37.1648 +inline u32 gfxIncreaseBrightness(u32 color, int coeff)
 37.1649 +{
 37.1650 +	int r = (color & 0x1F);
 37.1651 +	int g = ((color >> 5) & 0x1F);
 37.1652 +	int b = ((color >> 10) & 0x1F);
 37.1653 +
 37.1654 +	r = r + (((31 - r) * coeff) >> 4);
 37.1655 +	g = g + (((31 - g) * coeff) >> 4);
 37.1656 +	b = b + (((31 - b) * coeff) >> 4);
 37.1657 +	if (r > 31)
 37.1658 +		r = 31;
 37.1659 +	if (g > 31)
 37.1660 +		g = 31;
 37.1661 +	if (b > 31)
 37.1662 +		b = 31;
 37.1663 +	color = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r;
 37.1664 +	return color;
 37.1665 +}
 37.1666 +
 37.1667 +inline void gfxIncreaseBrightness(u32 *line, int coeff)
 37.1668 +{
 37.1669 +	for (int x = 0; x < 240; x++)
 37.1670 +	{
 37.1671 +		u32 color = *line;
 37.1672 +		int r     = (color & 0x1F);
 37.1673 +		int g     = ((color >> 5) & 0x1F);
 37.1674 +		int b     = ((color >> 10) & 0x1F);
 37.1675 +
 37.1676 +		r = r + (((31 - r) * coeff) >> 4);
 37.1677 +		g = g + (((31 - g) * coeff) >> 4);
 37.1678 +		b = b + (((31 - b) * coeff) >> 4);
 37.1679 +		if (r > 31)
 37.1680 +			r = 31;
 37.1681 +		if (g > 31)
 37.1682 +			g = 31;
 37.1683 +		if (b > 31)
 37.1684 +			b = 31;
 37.1685 +		*line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r;
 37.1686 +	}
 37.1687 +}
 37.1688 +
 37.1689 +inline u32 gfxDecreaseBrightness(u32 color, int coeff)
 37.1690 +{
 37.1691 +	int r = (color & 0x1F);
 37.1692 +	int g = ((color >> 5) & 0x1F);
 37.1693 +	int b = ((color >> 10) & 0x1F);
 37.1694 +
 37.1695 +	r = r - ((r * coeff) >> 4);
 37.1696 +	g = g - ((g * coeff) >> 4);
 37.1697 +	b = b - ((b * coeff) >> 4);
 37.1698 +	if (r < 0)
 37.1699 +		r = 0;
 37.1700 +	if (g < 0)
 37.1701 +		g = 0;
 37.1702 +	if (b < 0)
 37.1703 +		b = 0;
 37.1704 +	color = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r;
 37.1705 +
 37.1706 +	return color;
 37.1707 +}
 37.1708 +
 37.1709 +inline void gfxDecreaseBrightness(u32 *line, int coeff)
 37.1710 +{
 37.1711 +	for (int x = 0; x < 240; x++)
 37.1712 +	{
 37.1713 +		u32 color = *line;
 37.1714 +		int r     = (color & 0x1F);
 37.1715 +		int g     = ((color >> 5) & 0x1F);
 37.1716 +		int b     = ((color >> 10) & 0x1F);
 37.1717 +
 37.1718 +		r = r - ((r * coeff) >> 4);
 37.1719 +		g = g - ((g * coeff) >> 4);
 37.1720 +		b = b - ((b * coeff) >> 4);
 37.1721 +		if (r < 0)
 37.1722 +			r = 0;
 37.1723 +		if (g < 0)
 37.1724 +			g = 0;
 37.1725 +		if (b < 0)
 37.1726 +			b = 0;
 37.1727 +		*line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r;
 37.1728 +	}
 37.1729 +}
 37.1730 +
 37.1731 +inline u32 gfxAlphaBlend(u32 color, u32 color2, int ca, int cb)
 37.1732 +{
 37.1733 +	if (color < 0x80000000)
 37.1734 +	{
 37.1735 +		int r  = (color & 0x1F);
 37.1736 +		int g  = ((color >> 5) & 0x1F);
 37.1737 +		int b  = ((color >> 10) & 0x1F);
 37.1738 +		int r0 = (color2 & 0x1F);
 37.1739 +		int g0 = ((color2 >> 5) & 0x1F);
 37.1740 +		int b0 = ((color2 >> 10) & 0x1F);
 37.1741 +
 37.1742 +		r = ((r * ca) >> 4) + ((r0 * cb) >> 4);
 37.1743 +		g = ((g * ca) >> 4) + ((g0 * cb) >> 4);
 37.1744 +		b = ((b * ca) >> 4) + ((b0 * cb) >> 4);
 37.1745 +
 37.1746 +		if (r > 31)
 37.1747 +			r = 31;
 37.1748 +		if (g > 31)
 37.1749 +			g = 31;
 37.1750 +		if (b > 31)
 37.1751 +			b = 31;
 37.1752 +
 37.1753 +		return (color & 0xFFFF0000) | (b << 10) | (g << 5) | r;
 37.1754 +	}
 37.1755 +	return color;
 37.1756 +}
 37.1757 +
 37.1758 +inline void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb)
 37.1759 +{
 37.1760 +	for (int x = 0; x < 240; x++)
 37.1761 +	{
 37.1762 +		u32 color = *ta;
 37.1763 +		if (color < 0x80000000)
 37.1764 +		{
 37.1765 +			int r      = (color & 0x1F);
 37.1766 +			int g      = ((color >> 5) & 0x1F);
 37.1767 +			int b      = ((color >> 10) & 0x1F);
 37.1768 +			u32 color2 = (*tb++);
 37.1769 +			int r0     = (color2 & 0x1F);
 37.1770 +			int g0     = ((color2 >> 5) & 0x1F);
 37.1771 +			int b0     = ((color2 >> 10) & 0x1F);
 37.1772 +
 37.1773 +			r = ((r * ca) >> 4) + ((r0 * cb) >> 4);
 37.1774 +			g = ((g * ca) >> 4) + ((g0 * cb) >> 4);
 37.1775 +			b = ((b * ca) >> 4) + ((b0 * cb) >> 4);
 37.1776 +
 37.1777 +			if (r > 31)
 37.1778 +				r = 31;
 37.1779 +			if (g > 31)
 37.1780 +				g = 31;
 37.1781 +			if (b > 31)
 37.1782 +				b = 31;
 37.1783 +
 37.1784 +			*ta++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r;
 37.1785 +		}
 37.1786 +		else
 37.1787 +		{
 37.1788 +			ta++;
 37.1789 +			tb++;
 37.1790 +		}
 37.1791 +	}
 37.1792 +}
 37.1793 +
 37.1794 +#endif // VBA_GBA_GFX_H
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/src/gba/GBAGlobals.cpp	Sun Mar 04 14:33:52 2012 -0600
    38.3 @@ -0,0 +1,123 @@
    38.4 +#include "GBAGlobals.h"
    38.5 +
    38.6 +reg_pair  reg[45];
    38.7 +memoryMap map[256];
    38.8 +bool8	  ioReadable[0x400];
    38.9 +bool8	  N_FLAG			   = 0;
   38.10 +bool8	  C_FLAG			   = 0;
   38.11 +bool8	  Z_FLAG			   = 0;
   38.12 +bool8	  V_FLAG			   = 0;
   38.13 +bool8	  armState			   = true;
   38.14 +bool8	  armIrqEnable		   = true;
   38.15 +u32		  armNextPC			   = 0x00000000;
   38.16 +int32	  armMode			   = 0x1f;
   38.17 +u32		  stop				   = 0x08000568;
   38.18 +int32	  saveType			   = 0;
   38.19 +bool8	  useBios			   = false;
   38.20 +bool8	  skipBios			   = false;
   38.21 +int32	  frameSkip			   = 1;
   38.22 +u32		  extButtons		   = 0;
   38.23 +bool8	  capturePrevious	   = false;
   38.24 +int32	  captureNumber		   = 0;
   38.25 +bool8	  speedup			   = false;
   38.26 +bool8	  synchronize		   = true;
   38.27 +bool8	  cpuDisableSfx		   = false;
   38.28 +bool8	  cpuIsMultiBoot	   = false;
   38.29 +bool8	  parseDebug		   = true;
   38.30 +int32	  layerSettings		   = 0xff00;
   38.31 +int32	  layerEnable		   = 0xff00;
   38.32 +bool8	  speedHack			   = false;
   38.33 +bool8	  memLagEnabled		   = false;
   38.34 +bool8	  memLagTempEnabled	   = false;
   38.35 +bool8	  useOldFrameTiming	   = false;
   38.36 +int32	  cpuSaveType		   = 0;
   38.37 +bool8	  cpuEnhancedDetection = true;
   38.38 +bool8	  cheatsEnabled		   = true;
   38.39 +
   38.40 +u8 *bios		= NULL;
   38.41 +u8 *rom			= NULL;
   38.42 +u8 *internalRAM = NULL;
   38.43 +u8 *workRAM		= NULL;
   38.44 +u8 *paletteRAM	= NULL;
   38.45 +u8 *vram		= NULL;
   38.46 +u8 *pix			= NULL;
   38.47 +u8 *oam			= NULL;
   38.48 +u8 *ioMem		= NULL;
   38.49 +
   38.50 +u16 DISPCNT	 = 0x0080;
   38.51 +u16 DISPSTAT = 0x0000;
   38.52 +u16 VCOUNT	 = 0x0000;
   38.53 +u16 BG0CNT	 = 0x0000;
   38.54 +u16 BG1CNT	 = 0x0000;
   38.55 +u16 BG2CNT	 = 0x0000;
   38.56 +u16 BG3CNT	 = 0x0000;
   38.57 +u16 BG0HOFS	 = 0x0000;
   38.58 +u16 BG0VOFS	 = 0x0000;
   38.59 +u16 BG1HOFS	 = 0x0000;
   38.60 +u16 BG1VOFS	 = 0x0000;
   38.61 +u16 BG2HOFS	 = 0x0000;
   38.62 +u16 BG2VOFS	 = 0x0000;
   38.63 +u16 BG3HOFS	 = 0x0000;
   38.64 +u16 BG3VOFS	 = 0x0000;
   38.65 +u16 BG2PA	 = 0x0100;
   38.66 +u16 BG2PB	 = 0x0000;
   38.67 +u16 BG2PC	 = 0x0000;
   38.68 +u16 BG2PD	 = 0x0100;
   38.69 +u16 BG2X_L	 = 0x0000;
   38.70 +u16 BG2X_H	 = 0x0000;
   38.71 +u16 BG2Y_L	 = 0x0000;
   38.72 +u16 BG2Y_H	 = 0x0000;
   38.73 +u16 BG3PA	 = 0x0100;
   38.74 +u16 BG3PB	 = 0x0000;
   38.75 +u16 BG3PC	 = 0x0000;
   38.76 +u16 BG3PD	 = 0x0100;
   38.77 +u16 BG3X_L	 = 0x0000;
   38.78 +u16 BG3X_H	 = 0x0000;
   38.79 +u16 BG3Y_L	 = 0x0000;
   38.80 +u16 BG3Y_H	 = 0x0000;
   38.81 +u16 WIN0H	 = 0x0000;
   38.82 +u16 WIN1H	 = 0x0000;
   38.83 +u16 WIN0V	 = 0x0000;
   38.84 +u16 WIN1V	 = 0x0000;
   38.85 +u16 WININ	 = 0x0000;
   38.86 +u16 WINOUT	 = 0x0000;
   38.87 +u16 MOSAIC	 = 0x0000;
   38.88 +u16 BLDMOD	 = 0x0000;
   38.89 +u16 COLEV	 = 0x0000;
   38.90 +u16 COLY	 = 0x0000;
   38.91 +u16 DM0SAD_L = 0x0000;
   38.92 +u16 DM0SAD_H = 0x0000;
   38.93 +u16 DM0DAD_L = 0x0000;
   38.94 +u16 DM0DAD_H = 0x0000;
   38.95 +u16 DM0CNT_L = 0x0000;
   38.96 +u16 DM0CNT_H = 0x0000;
   38.97 +u16 DM1SAD_L = 0x0000;
   38.98 +u16 DM1SAD_H = 0x0000;
   38.99 +u16 DM1DAD_L = 0x0000;
  38.100 +u16 DM1DAD_H = 0x0000;
  38.101 +u16 DM1CNT_L = 0x0000;
  38.102 +u16 DM1CNT_H = 0x0000;
  38.103 +u16 DM2SAD_L = 0x0000;
  38.104 +u16 DM2SAD_H = 0x0000;
  38.105 +u16 DM2DAD_L = 0x0000;
  38.106 +u16 DM2DAD_H = 0x0000;
  38.107 +u16 DM2CNT_L = 0x0000;
  38.108 +u16 DM2CNT_H = 0x0000;
  38.109 +u16 DM3SAD_L = 0x0000;
  38.110 +u16 DM3SAD_H = 0x0000;
  38.111 +u16 DM3DAD_L = 0x0000;
  38.112 +u16 DM3DAD_H = 0x0000;
  38.113 +u16 DM3CNT_L = 0x0000;
  38.114 +u16 DM3CNT_H = 0x0000;
  38.115 +u16 TM0D	 = 0x0000;
  38.116 +u16 TM0CNT	 = 0x0000;
  38.117 +u16 TM1D	 = 0x0000;
  38.118 +u16 TM1CNT	 = 0x0000;
  38.119 +u16 TM2D	 = 0x0000;
  38.120 +u16 TM2CNT	 = 0x0000;
  38.121 +u16 TM3D	 = 0x0000;
  38.122 +u16 TM3CNT	 = 0x0000;
  38.123 +u16 P1		 = 0xFFFF;
  38.124 +u16 IE		 = 0x0000;
  38.125 +u16 IF		 = 0x0000;
  38.126 +u16 IME		 = 0x0000;
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/src/gba/GBAGlobals.h	Sun Mar 04 14:33:52 2012 -0600
    39.3 @@ -0,0 +1,208 @@
    39.4 +#ifndef VBA_GBA_GLOBALS_H
    39.5 +#define VBA_GBA_GLOBALS_H
    39.6 +
    39.7 +#if _MSC_VER > 1000
    39.8 +#pragma once
    39.9 +#endif // _MSC_VER > 1000
   39.10 +
   39.11 +#include "../Port.h"
   39.12 +
   39.13 +#define VERBOSE_SWI                  1
   39.14 +#define VERBOSE_UNALIGNED_MEMORY     2
   39.15 +#define VERBOSE_ILLEGAL_WRITE        4
   39.16 +#define VERBOSE_ILLEGAL_READ         8
   39.17 +#define VERBOSE_DMA0                16
   39.18 +#define VERBOSE_DMA1                32
   39.19 +#define VERBOSE_DMA2                64
   39.20 +#define VERBOSE_DMA3               128
   39.21 +#define VERBOSE_UNDEFINED          256
   39.22 +#define VERBOSE_AGBPRINT           512
   39.23 +
   39.24 +// moved from armdis.cpp
   39.25 +#define debuggerReadMemory(addr) \
   39.26 +    READ32LE(&map[(addr) >> 24].address[(addr) & map[(addr) >> 24].mask])
   39.27 +
   39.28 +#define debuggerReadHalfWord(addr) \
   39.29 +    READ16LE(&map[(addr) >> 24].address[(addr) & map[(addr) >> 24].mask])
   39.30 +
   39.31 +#define debuggerReadByte(addr) \
   39.32 +    READ8LE(&map[(addr) >> 24].address[(addr) & map[(addr) >> 24].mask])
   39.33 +
   39.34 +#define debuggerWriteMemory(addr, value) \
   39.35 +    WRITE32LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]), (value))
   39.36 +
   39.37 +#define debuggerWriteHalfWord(addr, value) \
   39.38 +    WRITE16LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]), (value))
   39.39 +
   39.40 +#define debuggerWriteByte(addr, value) \
   39.41 +    WRITE8LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]), (value))
   39.42 +
   39.43 +// moved from GBA.h
   39.44 +typedef struct
   39.45 +{
   39.46 +	u8 *address;
   39.47 +	u32 mask;
   39.48 +} memoryMap;
   39.49 +
   39.50 +#ifndef NO_GBA_MAP
   39.51 +extern memoryMap map[256];
   39.52 +#endif
   39.53 +
   39.54 +// moved from GBA.h
   39.55 +typedef union
   39.56 +{
   39.57 +	struct
   39.58 +	{
   39.59 +#ifdef WORDS_BIGENDIAN
   39.60 +		u8 B3;
   39.61 +		u8 B2;
   39.62 +		u8 B1;
   39.63 +		u8 B0;
   39.64 +#else
   39.65 +		u8 B0;
   39.66 +		u8 B1;
   39.67 +		u8 B2;
   39.68 +		u8 B3;
   39.69 +#endif
   39.70 +	} B;
   39.71 +	struct
   39.72 +	{
   39.73 +#ifdef WORDS_BIGENDIAN
   39.74 +		u16 W1;
   39.75 +		u16 W0;
   39.76 +#else
   39.77 +		u16 W0;
   39.78 +		u16 W1;
   39.79 +#endif
   39.80 +	} W;
   39.81 +#ifdef WORDS_BIGENDIAN
   39.82 +	volatile u32 I;
   39.83 +#else
   39.84 +	u32 I;
   39.85 +#endif
   39.86 +} reg_pair;
   39.87 +
   39.88 +extern reg_pair reg[45];
   39.89 +extern u8		biosProtected[4];
   39.90 +extern bool8	ioReadable[0x400];
   39.91 +extern bool8	N_FLAG;
   39.92 +extern bool8	C_FLAG;
   39.93 +extern bool8	Z_FLAG;
   39.94 +extern bool8	V_FLAG;
   39.95 +extern bool8	armState;
   39.96 +extern bool8	armIrqEnable;
   39.97 +extern u32		armNextPC;
   39.98 +extern int32	armMode;
   39.99 +extern u32		stop;
  39.100 +extern int32	saveType;
  39.101 +extern bool8	useBios;
  39.102 +extern bool8	skipBios;
  39.103 +extern int32	frameSkip;
  39.104 +extern u32		extButtons;
  39.105 +extern bool8	capturePrevious;
  39.106 +extern int32	captureNumber;
  39.107 +extern bool8	speedup;
  39.108 +extern bool8	synchronize;
  39.109 +extern bool8	cpuDisableSfx;
  39.110 +extern bool8	cpuIsMultiBoot;
  39.111 +extern bool8	parseDebug;
  39.112 +extern int32	layerSettings;
  39.113 +extern int32	layerEnable;
  39.114 +extern bool8	speedHack;
  39.115 +extern bool8	memLagEnabled, memLagTempEnabled;
  39.116 +extern bool8	useOldFrameTiming;
  39.117 +extern int32	cpuSaveType;
  39.118 +extern bool8	cpuEnhancedDetection;
  39.119 +extern bool8	cheatsEnabled;
  39.120 +
  39.121 +extern int emulating;
  39.122 +
  39.123 +extern u8 *bios;
  39.124 +extern u8 *rom;
  39.125 +extern u8 *internalRAM;
  39.126 +extern u8 *workRAM;
  39.127 +extern u8 *paletteRAM;
  39.128 +extern u8 *vram;
  39.129 +extern u8 *pix;
  39.130 +extern u8 *oam;
  39.131 +extern u8 *ioMem;
  39.132 +
  39.133 +extern u16 DISPCNT;
  39.134 +extern u16 DISPSTAT;
  39.135 +extern u16 VCOUNT;
  39.136 +extern u16 BG0CNT;
  39.137 +extern u16 BG1CNT;
  39.138 +extern u16 BG2CNT;
  39.139 +extern u16 BG3CNT;
  39.140 +extern u16 BG0HOFS;
  39.141 +extern u16 BG0VOFS;
  39.142 +extern u16 BG1HOFS;
  39.143 +extern u16 BG1VOFS;
  39.144 +extern u16 BG2HOFS;
  39.145 +extern u16 BG2VOFS;
  39.146 +extern u16 BG3HOFS;
  39.147 +extern u16 BG3VOFS;
  39.148 +extern u16 BG2PA;
  39.149 +extern u16 BG2PB;
  39.150 +extern u16 BG2PC;
  39.151 +extern u16 BG2PD;
  39.152 +extern u16 BG2X_L;
  39.153 +extern u16 BG2X_H;
  39.154 +extern u16 BG2Y_L;
  39.155 +extern u16 BG2Y_H;
  39.156 +extern u16 BG3PA;
  39.157 +extern u16 BG3PB;
  39.158 +extern u16 BG3PC;
  39.159 +extern u16 BG3PD;
  39.160 +extern u16 BG3X_L;
  39.161 +extern u16 BG3X_H;
  39.162 +extern u16 BG3Y_L;
  39.163 +extern u16 BG3Y_H;
  39.164 +extern u16 WIN0H;
  39.165 +extern u16 WIN1H;
  39.166 +extern u16 WIN0V;
  39.167 +extern u16 WIN1V;
  39.168 +extern u16 WININ;
  39.169 +extern u16 WINOUT;
  39.170 +extern u16 MOSAIC;
  39.171 +extern u16 BLDMOD;
  39.172 +extern u16 COLEV;
  39.173 +extern u16 COLY;
  39.174 +extern u16 DM0SAD_L;
  39.175 +extern u16 DM0SAD_H;
  39.176 +extern u16 DM0DAD_L;
  39.177 +extern u16 DM0DAD_H;
  39.178 +extern u16 DM0CNT_L;
  39.179 +extern u16 DM0CNT_H;
  39.180 +extern u16 DM1SAD_L;
  39.181 +extern u16 DM1SAD_H;
  39.182 +extern u16 DM1DAD_L;
  39.183 +extern u16 DM1DAD_H;
  39.184 +extern u16 DM1CNT_L;
  39.185 +extern u16 DM1CNT_H;
  39.186 +extern u16 DM2SAD_L;
  39.187 +extern u16 DM2SAD_H;
  39.188 +extern u16 DM2DAD_L;
  39.189 +extern u16 DM2DAD_H;
  39.190 +extern u16 DM2CNT_L;
  39.191 +extern u16 DM2CNT_H;
  39.192 +extern u16 DM3SAD_L;
  39.193 +extern u16 DM3SAD_H;
  39.194 +extern u16 DM3DAD_L;
  39.195 +extern u16 DM3DAD_H;
  39.196 +extern u16 DM3CNT_L;
  39.197 +extern u16 DM3CNT_H;
  39.198 +extern u16 TM0D;
  39.199 +extern u16 TM0CNT;
  39.200 +extern u16 TM1D;
  39.201 +extern u16 TM1CNT;
  39.202 +extern u16 TM2D;
  39.203 +extern u16 TM2CNT;
  39.204 +extern u16 TM3D;
  39.205 +extern u16 TM3CNT;
  39.206 +extern u16 P1;
  39.207 +extern u16 IE;
  39.208 +extern u16 IF;
  39.209 +extern u16 IME;
  39.210 +
  39.211 +#endif // VBA_GBA_GLOBALS_H
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/src/gba/GBASound.cpp	Sun Mar 04 14:33:52 2012 -0600
    40.3 @@ -0,0 +1,1542 @@
    40.4 +#if (defined(WIN32) && !defined(SDL))
    40.5 +#   include "../win32/stdafx.h"
    40.6 +#   include "../win32/VBA.h"
    40.7 +#endif
    40.8 +
    40.9 +#include <cstring>
   40.10 +#include <cassert>
   40.11 +
   40.12 +#include "GBASound.h"
   40.13 +#include "../common/System.h" // SDL build needs this
   40.14 +#include "../common/Util.h"
   40.15 +#include "GBA.h"
   40.16 +#include "GBAGlobals.h"
   40.17 +
   40.18 +#ifndef countof
   40.19 +#define countof(a)  (sizeof(a) / sizeof(a[0]))
   40.20 +#endif
   40.21 +
   40.22 +soundtick_t USE_TICKS_AS = 380; // (16777216.0/44100.0); // FIXME: (16777216.0/280896.0)(fps) vs 60.0fps?
   40.23 +
   40.24 +#define SOUND_MAGIC   0x60000000
   40.25 +#define SOUND_MAGIC_2 0x30000000
   40.26 +#define NOISE_MAGIC (2097152.0 / 44100.0)
   40.27 +
   40.28 +extern bool8 stopState;
   40.29 +
   40.30 +u8 soundWavePattern[4][32] = {
   40.31 +	{ 0x01, 0x01, 0x01, 0x01,
   40.32 +	  0xff, 0xff, 0xff, 0xff,
   40.33 +	  0xff, 0xff, 0xff, 0xff,
   40.34 +	  0xff, 0xff, 0xff, 0xff,
   40.35 +	  0xff, 0xff, 0xff, 0xff,
   40.36 +	  0xff, 0xff, 0xff, 0xff,
   40.37 +	  0xff, 0xff, 0xff, 0xff,
   40.38 +	  0xff, 0xff, 0xff, 0xff },
   40.39 +	{ 0x01, 0x01, 0x01, 0x01,
   40.40 +	  0x01, 0x01, 0x01, 0x01,
   40.41 +	  0xff, 0xff, 0xff, 0xff,
   40.42 +	  0xff, 0xff, 0xff, 0xff,
   40.43 +	  0xff, 0xff, 0xff, 0xff,
   40.44 +	  0xff, 0xff, 0xff, 0xff,
   40.45 +	  0xff, 0xff, 0xff, 0xff,
   40.46 +	  0xff, 0xff, 0xff, 0xff },
   40.47 +	{ 0x01, 0x01, 0x01, 0x01,
   40.48 +	  0x01, 0x01, 0x01, 0x01,
   40.49 +	  0x01, 0x01, 0x01, 0x01,
   40.50 +	  0x01, 0x01, 0x01, 0x01,
   40.51 +	  0xff, 0xff, 0xff, 0xff,
   40.52 +	  0xff, 0xff, 0xff, 0xff,
   40.53 +	  0xff, 0xff, 0xff, 0xff,
   40.54 +	  0xff, 0xff, 0xff, 0xff },
   40.55 +	{ 0x01, 0x01, 0x01, 0x01,
   40.56 +	  0x01, 0x01, 0x01, 0x01,
   40.57 +	  0x01, 0x01, 0x01, 0x01,
   40.58 +	  0x01, 0x01, 0x01, 0x01,
   40.59 +	  0x01, 0x01, 0x01, 0x01,
   40.60 +	  0x01, 0x01, 0x01, 0x01,
   40.61 +	  0xff, 0xff, 0xff, 0xff,
   40.62 +	  0xff, 0xff, 0xff, 0xff }
   40.63 +};
   40.64 +
   40.65 +int32 soundFreqRatio[8] = {
   40.66 +	1048576, // 0
   40.67 +	524288, // 1
   40.68 +	262144, // 2
   40.69 +	174763, // 3
   40.70 +	131072, // 4
   40.71 +	104858, // 5
   40.72 +	87381, // 6
   40.73 +	74898  // 7
   40.74 +};
   40.75 +
   40.76 +int32 soundShiftClock[16] = {
   40.77 +	2,   // 0
   40.78 +	4,   // 1
   40.79 +	8,   // 2
   40.80 +	16,  // 3
   40.81 +	32,  // 4
   40.82 +	64,  // 5
   40.83 +	128, // 6
   40.84 +	256, // 7
   40.85 +	512, // 8
   40.86 +	1024, // 9
   40.87 +	2048, // 10
   40.88 +	4096, // 11
   40.89 +	8192, // 12
   40.90 +	16384, // 13
   40.91 +	1,   // 14
   40.92 +	1    // 15
   40.93 +};
   40.94 +
   40.95 +int32 soundVolume = 0;
   40.96 +
   40.97 +u8	soundBuffer[6][735];
   40.98 +u16 soundFinalWave[1470];
   40.99 +u16 soundFrameSound[735 * 30 * 2]; // for avi logging
  40.100 +
  40.101 +u32			soundBufferLen		= 1470;
  40.102 +u32			soundBufferTotalLen = 14700;
  40.103 +int32		soundQuality		= 2;
  40.104 +int32		soundPaused			= 1;
  40.105 +int32		soundPlay			= 0;
  40.106 +soundtick_t soundTicks			= soundQuality * USE_TICKS_AS;
  40.107 +soundtick_t SOUND_CLOCK_TICKS	= soundQuality * USE_TICKS_AS;
  40.108 +u32			soundNextPosition	= 0;
  40.109 +
  40.110 +int32 soundLevel1 = 0;
  40.111 +int32 soundLevel2 = 0;
  40.112 +int32 soundBalance = 0;
  40.113 +int32 soundMasterOn = 0;
  40.114 +u32	  soundIndex = 0;
  40.115 +u32	  soundBufferIndex		 = 0;
  40.116 +int32 soundFrameSoundWritten = 0;
  40.117 +int32 soundDebug			 = 0;
  40.118 +bool8 soundOffFlag			 = false;
  40.119 +
  40.120 +int32 sound1On = 0;
  40.121 +int32 sound1ATL = 0;
  40.122 +int32 sound1Skip = 0;
  40.123 +int32 sound1Index = 0;
  40.124 +int32 sound1Continue = 0;
  40.125 +int32 sound1EnvelopeVolume	  = 0;
  40.126 +int32 sound1EnvelopeATL		  = 0;
  40.127 +int32 sound1EnvelopeUpDown	  = 0;
  40.128 +int32 sound1EnvelopeATLReload = 0;
  40.129 +int32 sound1SweepATL		  = 0;
  40.130 +int32 sound1SweepATLReload	  = 0;
  40.131 +int32 sound1SweepSteps		  = 0;
  40.132 +int32 sound1SweepUpDown		  = 0;
  40.133 +int32 sound1SweepStep		  = 0;
  40.134 +u8 *  sound1Wave			  = soundWavePattern[2];
  40.135 +
  40.136 +int32 sound2On = 0;
  40.137 +int32 sound2ATL = 0;
  40.138 +int32 sound2Skip = 0;
  40.139 +int32 sound2Index = 0;
  40.140 +int32 sound2Continue = 0;
  40.141 +int32 sound2EnvelopeVolume	  = 0;
  40.142 +int32 sound2EnvelopeATL		  = 0;
  40.143 +int32 sound2EnvelopeUpDown	  = 0;
  40.144 +int32 sound2EnvelopeATLReload = 0;
  40.145 +u8 *  sound2Wave			  = soundWavePattern[2];
  40.146 +
  40.147 +int32 sound3On = 0;
  40.148 +int32 sound3ATL			= 0;
  40.149 +int32 sound3Skip		= 0;
  40.150 +int32 sound3Index		= 0;
  40.151 +int32 sound3Continue	= 0;
  40.152 +int32 sound3OutputLevel = 0;
  40.153 +int32 sound3Last		= 0;
  40.154 +u8	  sound3WaveRam[0x20];
  40.155 +int32 sound3Bank		 = 0;
  40.156 +int32 sound3DataSize	 = 0;
  40.157 +int32 sound3ForcedOutput = 0;
  40.158 +
  40.159 +int32 sound4On = 0;
  40.160 +int32 sound4Clock = 0;
  40.161 +int32 sound4ATL = 0;
  40.162 +int32 sound4Skip = 0;
  40.163 +int32 sound4Index = 0;
  40.164 +int32 sound4ShiftRight		  = 0x7f;
  40.165 +int32 sound4ShiftSkip		  = 0;
  40.166 +int32 sound4ShiftIndex		  = 0;
  40.167 +int32 sound4NSteps			  = 0;
  40.168 +int32 sound4CountDown		  = 0;
  40.169 +int32 sound4Continue		  = 0;
  40.170 +int32 sound4EnvelopeVolume	  = 0;
  40.171 +int32 sound4EnvelopeATL		  = 0;
  40.172 +int32 sound4EnvelopeUpDown	  = 0;
  40.173 +int32 sound4EnvelopeATLReload = 0;
  40.174 +
  40.175 +int32 soundControl = 0;
  40.176 +
  40.177 +int32 soundDSFifoAIndex		 = 0;
  40.178 +int32 soundDSFifoACount		 = 0;
  40.179 +int32 soundDSFifoAWriteIndex = 0;
  40.180 +bool8 soundDSAEnabled		 = false;
  40.181 +int32 soundDSATimer = 0;
  40.182 +u8	  soundDSFifoA[32];
  40.183 +u8	  soundDSAValue = 0;
  40.184 +
  40.185 +int32 soundDSFifoBIndex		 = 0;
  40.186 +int32 soundDSFifoBCount		 = 0;
  40.187 +int32 soundDSFifoBWriteIndex = 0;
  40.188 +bool8 soundDSBEnabled		 = false;
  40.189 +int32 soundDSBTimer = 0;
  40.190 +u8	  soundDSFifoB[32];
  40.191 +u8	  soundDSBValue = 0;
  40.192 +
  40.193 +int32 soundEnableFlag = 0x3ff;
  40.194 +int32 soundMutedFlag  = 0;
  40.195 +
  40.196 +s16	  soundFilter[4000];
  40.197 +s16	  soundRight[5] = { 0, 0, 0, 0, 0 };
  40.198 +s16	  soundLeft[5] = { 0, 0, 0, 0, 0 };
  40.199 +int32 soundEchoIndex = 0;
  40.200 +bool8 soundEcho		 = false;
  40.201 +bool8 soundLowPass	 = false;
  40.202 +bool8 soundReverse	 = false;
  40.203 +
  40.204 +static int32  soundTicks_int32;
  40.205 +static int32  SOUND_CLOCK_TICKS_int32;
  40.206 +static int32  soundDSBValue_int32;
  40.207 +variable_desc soundSaveStruct[] = {
  40.208 +	{ &soundPaused,				sizeof(int32)					  },
  40.209 +	{ &soundPlay,				sizeof(int32)					  },
  40.210 +	{ &soundTicks_int32,		sizeof(int32)					  },
  40.211 +	{ &SOUND_CLOCK_TICKS_int32, sizeof(int32)					  },
  40.212 +	{ &soundLevel1,				sizeof(int32)					  },
  40.213 +	{ &soundLevel2,				sizeof(int32)					  },
  40.214 +	{ &soundBalance,			sizeof(int32)					  },
  40.215 +	{ &soundMasterOn,			sizeof(int32)					  },
  40.216 +	{ &soundIndex,				sizeof(int32)					  },
  40.217 +	{ &sound1On,				sizeof(int32)					  },
  40.218 +	{ &sound1ATL,				sizeof(int32)					  },
  40.219 +	{ &sound1Skip,				sizeof(int32)					  },
  40.220 +	{ &sound1Index,				sizeof(int32)					  },
  40.221 +	{ &sound1Continue,			sizeof(int32)					  },
  40.222 +	{ &sound1EnvelopeVolume,	sizeof(int32)					  },
  40.223 +	{ &sound1EnvelopeATL,		sizeof(int32)					  },
  40.224 +	{ &sound1EnvelopeATLReload, sizeof(int32)					  },
  40.225 +	{ &sound1EnvelopeUpDown,	sizeof(int32)					  },
  40.226 +	{ &sound1SweepATL,			sizeof(int32)					  },
  40.227 +	{ &sound1SweepATLReload,	sizeof(int32)					  },
  40.228 +	{ &sound1SweepSteps,		sizeof(int32)					  },
  40.229 +	{ &sound1SweepUpDown,		sizeof(int32)					  },
  40.230 +	{ &sound1SweepStep,			sizeof(int32)					  },
  40.231 +	{ &sound2On,				sizeof(int32)					  },
  40.232 +	{ &sound2ATL,				sizeof(int32)					  },
  40.233 +	{ &sound2Skip,				sizeof(int32)					  },
  40.234 +	{ &sound2Index,				sizeof(int32)					  },
  40.235 +	{ &sound2Continue,			sizeof(int32)					  },
  40.236 +	{ &sound2EnvelopeVolume,	sizeof(int32)					  },
  40.237 +	{ &sound2EnvelopeATL,		sizeof(int32)					  },
  40.238 +	{ &sound2EnvelopeATLReload, sizeof(int32)					  },
  40.239 +	{ &sound2EnvelopeUpDown,	sizeof(int32)					  },
  40.240 +	{ &sound3On,				sizeof(int32)					  },
  40.241 +	{ &sound3ATL,				sizeof(int32)					  },
  40.242 +	{ &sound3Skip,				sizeof(int32)					  },
  40.243 +	{ &sound3Index,				sizeof(int32)					  },
  40.244 +	{ &sound3Continue,			sizeof(int32)					  },
  40.245 +	{ &sound3OutputLevel,		sizeof(int32)					  },
  40.246 +	{ &sound4On,				sizeof(int32)					  },
  40.247 +	{ &sound4ATL,				sizeof(int32)					  },
  40.248 +	{ &sound4Skip,				sizeof(int32)					  },
  40.249 +	{ &sound4Index,				sizeof(int32)					  },
  40.250 +	{ &sound4Clock,				sizeof(int32)					  },
  40.251 +	{ &sound4ShiftRight,		sizeof(int32)					  },
  40.252 +	{ &sound4ShiftSkip,			sizeof(int32)					  },
  40.253 +	{ &sound4ShiftIndex,		sizeof(int32)					  },
  40.254 +	{ &sound4NSteps,			sizeof(int32)					  },
  40.255 +	{ &sound4CountDown,			sizeof(int32)					  },
  40.256 +	{ &sound4Continue,			sizeof(int32)					  },
  40.257 +	{ &sound4EnvelopeVolume,	sizeof(int32)					  },
  40.258 +	{ &sound4EnvelopeATL,		sizeof(int32)					  },
  40.259 +	{ &sound4EnvelopeATLReload, sizeof(int32)					  },
  40.260 +	{ &sound4EnvelopeUpDown,	sizeof(int32)					  },
  40.261 +	{ &soundEnableFlag,			sizeof(int32)					  },
  40.262 +	{ &soundControl,			sizeof(int32)					  },
  40.263 +	{ &soundDSFifoAIndex,		sizeof(int32)					  },
  40.264 +	{ &soundDSFifoACount,		sizeof(int32)					  },
  40.265 +	{ &soundDSFifoAWriteIndex,	sizeof(int32)					  },
  40.266 +	{ &soundDSAEnabled,			sizeof(bool8)					  },
  40.267 +	{ &soundDSATimer,			sizeof(int32)					  },
  40.268 +	{ &soundDSFifoA[0],			32								  },
  40.269 +	{ &soundDSAValue,			sizeof(u8)						  },
  40.270 +	{ &soundDSFifoBIndex,		sizeof(int32)					  },
  40.271 +	{ &soundDSFifoBCount,		sizeof(int32)					  },
  40.272 +	{ &soundDSFifoBWriteIndex,	sizeof(int32)					  },
  40.273 +	{ &soundDSBEnabled,			sizeof(int32)					  },
  40.274 +	{ &soundDSBTimer,			sizeof(int32)					  },
  40.275 +	{ &soundDSFifoB[0],			32								  },
  40.276 +	{ &soundDSBValue_int32,		sizeof(int32)					  }, // save as int32 because of a mistake of the past.
  40.277 +	{ &soundBuffer[0][0],		6 * 735							  },
  40.278 +	{ &soundFinalWave[0],		2 * 735							  },
  40.279 +	{ NULL,						0								  }
  40.280 +};
  40.281 +
  40.282 +variable_desc soundSaveStructV2[] = {
  40.283 +	{ &sound3WaveRam[0],   0x20							},
  40.284 +	{ &sound3Bank,		   sizeof(int32)				},
  40.285 +	{ &sound3DataSize,	   sizeof(int32)				},
  40.286 +	{ &sound3ForcedOutput, sizeof(int32)				},
  40.287 +	{ NULL,				   0							}
  40.288 +};
  40.289 +
  40.290 +//variable_desc soundSaveStructV3[] = {
  40.291 +//  { &soundTicks, sizeof(soundtick_t) },
  40.292 +//  { &SOUND_CLOCK_TICKS, sizeof(soundtick_t) },
  40.293 +//  { &USE_TICKS_AS, sizeof(soundtick_t) },
  40.294 +//  { NULL, 0 }
  40.295 +//};
  40.296 +
  40.297 +void soundEvent(u32 address, u8 data)
  40.298 +{
  40.299 +	int freq = 0;
  40.300 +
  40.301 +	switch (address)
  40.302 +	{
  40.303 +	case NR10:
  40.304 +		data &= 0x7f;
  40.305 +		sound1SweepATL	  = sound1SweepATLReload = 344 * ((data >> 4) & 7);
  40.306 +		sound1SweepSteps  = data & 7;
  40.307 +		sound1SweepUpDown = data & 0x08;
  40.308 +		sound1SweepStep	  = 0;
  40.309 +		ioMem[address]	  = data;
  40.310 +		break;
  40.311 +	case NR11:
  40.312 +		sound1Wave	   = soundWavePattern[data >> 6];
  40.313 +		sound1ATL	   = 172 * (64 - (data & 0x3f));
  40.314 +		ioMem[address] = data;
  40.315 +		break;
  40.316 +	case NR12:
  40.317 +		sound1EnvelopeUpDown	= data & 0x08;
  40.318 +		sound1EnvelopeATLReload = 689 * (data & 7);
  40.319 +		if ((data & 0xF8) == 0)
  40.320 +			sound1EnvelopeVolume = 0;
  40.321 +		ioMem[address] = data;
  40.322 +		break;
  40.323 +	case NR13:
  40.324 +		freq	  = (((int)(ioMem[NR14] & 7)) << 8) | data;
  40.325 +		sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f));
  40.326 +		freq	  = 2048 - freq;
  40.327 +		if (freq)
  40.328 +		{
  40.329 +			sound1Skip = SOUND_MAGIC / freq;
  40.330 +		}
  40.331 +		else
  40.332 +			sound1Skip = 0;
  40.333 +		ioMem[address] = data;
  40.334 +		break;
  40.335 +	case NR14:
  40.336 +		data &= 0xC7;
  40.337 +		freq = (((int)(data & 7) << 8) | ioMem[NR13]);
  40.338 +		freq = 2048 - freq;
  40.339 +		sound1ATL	   = 172 * (64 - (ioMem[NR11] & 0x3f));
  40.340 +		sound1Continue = data & 0x40;
  40.341 +		if (freq)
  40.342 +		{
  40.343 +			sound1Skip = SOUND_MAGIC / freq;
  40.344 +		}
  40.345 +		else
  40.346 +			sound1Skip = 0;
  40.347 +		if (data & 0x80)
  40.348 +		{
  40.349 +			ioMem[NR52] |= 1;
  40.350 +			sound1EnvelopeVolume = ioMem[NR12] >> 4;
  40.351 +			sound1EnvelopeUpDown = ioMem[NR12] & 0x08;
  40.352 +			sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f));
  40.353 +			sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (ioMem[NR12] & 7);
  40.354 +			sound1SweepATL			= sound1SweepATLReload = 344 * ((ioMem[NR10] >> 4) & 7);
  40.355 +			sound1SweepSteps		= ioMem[NR10] & 7;
  40.356 +			sound1SweepUpDown		= ioMem[NR10] & 0x08;
  40.357 +			sound1SweepStep			= 0;
  40.358 +
  40.359 +			sound1Index = 0;
  40.360 +			sound1On	= 1;
  40.361 +		}
  40.362 +		ioMem[address] = data;
  40.363 +		break;
  40.364 +	case NR21:
  40.365 +		sound2Wave	   = soundWavePattern[data >> 6];
  40.366 +		sound2ATL	   = 172 * (64 - (data & 0x3f));
  40.367 +		ioMem[address] = data;
  40.368 +		break;
  40.369 +	case NR22:
  40.370 +		sound2EnvelopeUpDown	= data & 0x08;
  40.371 +		sound2EnvelopeATLReload = 689 * (data & 7);
  40.372 +		if ((data & 0xF8) == 0)
  40.373 +			sound2EnvelopeVolume = 0;
  40.374 +		ioMem[address] = data;
  40.375 +		break;
  40.376 +	case NR23:
  40.377 +		freq	  = (((int)(ioMem[NR24] & 7)) << 8) | data;
  40.378 +		sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f));
  40.379 +		freq	  = 2048 - freq;
  40.380 +		if (freq)
  40.381 +		{
  40.382 +			sound2Skip = SOUND_MAGIC / freq;
  40.383 +		}
  40.384 +		else
  40.385 +			sound2Skip = 0;
  40.386 +		ioMem[address] = data;
  40.387 +		break;
  40.388 +	case NR24:
  40.389 +		data &= 0xC7;
  40.390 +		freq = (((int)(data & 7) << 8) | ioMem[NR23]);
  40.391 +		freq = 2048 - freq;
  40.392 +		sound2ATL	   = 172 * (64 - (ioMem[NR21] & 0x3f));
  40.393 +		sound2Continue = data & 0x40;
  40.394 +		if (freq)
  40.395 +		{
  40.396 +			sound2Skip = SOUND_MAGIC / freq;
  40.397 +		}
  40.398 +		else
  40.399 +			sound2Skip = 0;
  40.400 +		if (data & 0x80)
  40.401 +		{
  40.402 +			ioMem[NR52] |= 2;
  40.403 +			sound2EnvelopeVolume = ioMem[NR22] >> 4;
  40.404 +			sound2EnvelopeUpDown = ioMem[NR22] & 0x08;
  40.405 +			sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f));
  40.406 +			sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (ioMem[NR22] & 7);
  40.407 +
  40.408 +			sound2Index = 0;
  40.409 +			sound2On	= 1;
  40.410 +		}
  40.411 +		ioMem[address] = data;
  40.412 +		break;
  40.413 +	case NR30:
  40.414 +		data &= 0xe0;
  40.415 +		if (!(data & 0x80))
  40.416 +		{
  40.417 +			ioMem[NR52] &= 0xfb;
  40.418 +			sound3On	 = 0;
  40.419 +		}
  40.420 +		if (((data >> 6) & 1) != sound3Bank)
  40.421 +			memcpy(&ioMem[0x90], &sound3WaveRam[(((data >> 6) & 1) * 0x10) ^ 0x10],
  40.422 +			       0x10);
  40.423 +		sound3Bank	   = (data >> 6) & 1;
  40.424 +		sound3DataSize = (data >> 5) & 1;
  40.425 +		ioMem[address] = data;
  40.426 +		break;
  40.427 +	case NR31:
  40.428 +		sound3ATL	   = 172 * (256 - data);
  40.429 +		ioMem[address] = data;
  40.430 +		break;
  40.431 +	case NR32:
  40.432 +		data &= 0xe0;
  40.433 +		sound3OutputLevel  = (data >> 5) & 3;
  40.434 +		sound3ForcedOutput = (data >> 7) & 1;
  40.435 +		ioMem[address]	   = data;
  40.436 +		break;
  40.437 +	case NR33:
  40.438 +		freq = 2048 - (((int)(ioMem[NR34] & 7) << 8) | data);
  40.439 +		if (freq)
  40.440 +		{
  40.441 +			sound3Skip = SOUND_MAGIC_2 / freq;
  40.442 +		}
  40.443 +		else
  40.444 +			sound3Skip = 0;
  40.445 +		ioMem[address] = data;
  40.446 +		break;
  40.447 +	case NR34:
  40.448 +		data &= 0xc7;
  40.449 +		freq  = 2048 - (((data & 7) << 8) | (int)ioMem[NR33]);
  40.450 +		if (freq)
  40.451 +		{
  40.452 +			sound3Skip = SOUND_MAGIC_2 / freq;
  40.453 +		}
  40.454 +		else
  40.455 +		{
  40.456 +			sound3Skip = 0;
  40.457 +		}
  40.458 +		sound3Continue = data & 0x40;
  40.459 +		if ((data & 0x80) && (ioMem[NR30] & 0x80))
  40.460 +		{
  40.461 +			ioMem[NR52] |= 4;
  40.462 +			sound3ATL	 = 172 * (256 - ioMem[NR31]);
  40.463 +			sound3Index	 = 0;
  40.464 +			sound3On	 = 1;
  40.465 +		}
  40.466 +		ioMem[address] = data;
  40.467 +		break;
  40.468 +	case NR41:
  40.469 +		data &= 0x3f;
  40.470 +		sound4ATL	   = 172 * (64 - (data & 0x3f));
  40.471 +		ioMem[address] = data;
  40.472 +		break;
  40.473 +	case NR42:
  40.474 +		sound4EnvelopeUpDown	= data & 0x08;
  40.475 +		sound4EnvelopeATLReload = 689 * (data & 7);
  40.476 +		if ((data & 0xF8) == 0)
  40.477 +			sound4EnvelopeVolume = 0;
  40.478 +		ioMem[address] = data;
  40.479 +		break;
  40.480 +	case NR43:
  40.481 +		freq		 = soundFreqRatio[data & 7];
  40.482 +		sound4NSteps = data & 0x08;
  40.483 +
  40.484 +		sound4Skip = freq * NOISE_MAGIC;
  40.485 +
  40.486 +		sound4Clock = data >> 4;
  40.487 +
  40.488 +		freq = freq / soundShiftClock[sound4Clock];
  40.489 +
  40.490 +		sound4ShiftSkip = freq * NOISE_MAGIC;
  40.491 +		ioMem[address]	= data;
  40.492 +		break;
  40.493 +	case NR44:
  40.494 +		data &= 0xc0;
  40.495 +		sound4Continue = data & 0x40;
  40.496 +		if (data & 0x80)
  40.497 +		{
  40.498 +			ioMem[NR52] |= 8;
  40.499 +			sound4EnvelopeVolume = ioMem[NR42] >> 4;
  40.500 +			sound4EnvelopeUpDown = ioMem[NR42] & 0x08;
  40.501 +			sound4ATL = 172 * (64 - (ioMem[NR41] & 0x3f));
  40.502 +			sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (ioMem[NR42] & 7);
  40.503 +
  40.504 +			sound4On = 1;
  40.505 +
  40.506 +			sound4Index		 = 0;
  40.507 +			sound4ShiftIndex = 0;
  40.508 +
  40.509 +			freq = soundFreqRatio[ioMem[NR43] & 7];
  40.510 +
  40.511 +			sound4Skip = freq * NOISE_MAGIC;
  40.512 +
  40.513 +			sound4NSteps = ioMem[NR43] & 0x08;
  40.514 +
  40.515 +			freq = freq / soundShiftClock[ioMem[NR43] >> 4];
  40.516 +
  40.517 +			sound4ShiftSkip = freq * NOISE_MAGIC;
  40.518 +			if (sound4NSteps)
  40.519 +				sound4ShiftRight = 0x7f;
  40.520 +			else
  40.521 +				sound4ShiftRight = 0x7fff;
  40.522 +		}
  40.523 +		ioMem[address] = data;
  40.524 +		break;
  40.525 +	case NR50:
  40.526 +		data &= 0x77;
  40.527 +		soundLevel1	   = data & 7;
  40.528 +		soundLevel2	   = (data >> 4) & 7;
  40.529 +		ioMem[address] = data;
  40.530 +		break;
  40.531 +	case NR51:
  40.532 +		soundBalance   = (data & soundEnableFlag);
  40.533 +		ioMem[address] = data;
  40.534 +		break;
  40.535 +	case NR52:
  40.536 +		data &= 0x80;
  40.537 +		data |= ioMem[NR52] & 15;
  40.538 +		soundMasterOn = data & 0x80;
  40.539 +		if (!(data & 0x80))
  40.540 +		{
  40.541 +			sound1On = 0;
  40.542 +			sound2On = 0;
  40.543 +			sound3On = 0;
  40.544 +			sound4On = 0;
  40.545 +		}
  40.546 +		ioMem[address] = data;
  40.547 +		break;
  40.548 +	case 0x90:
  40.549 +	case 0x91:
  40.550 +	case 0x92:
  40.551 +	case 0x93:
  40.552 +	case 0x94:
  40.553 +	case 0x95:
  40.554 +	case 0x96:
  40.555 +	case 0x97:
  40.556 +	case 0x98:
  40.557 +	case 0x99:
  40.558 +	case 0x9a:
  40.559 +	case 0x9b:
  40.560 +	case 0x9c:
  40.561 +	case 0x9d:
  40.562 +	case 0x9e:
  40.563 +	case 0x9f:
  40.564 +		sound3WaveRam[(sound3Bank * 0x10) ^ 0x10 + (address & 15)] = data;
  40.565 +		break;
  40.566 +	}
  40.567 +}
  40.568 +
  40.569 +void soundEvent(u32 address, u16 data)
  40.570 +{
  40.571 +	switch (address)
  40.572 +	{
  40.573 +	case SGCNT0_H:
  40.574 +		data		&= 0xFF0F;
  40.575 +		soundControl = data & 0x770F;;
  40.576 +		if (data & 0x0800)
  40.577 +		{
  40.578 +			soundDSFifoAWriteIndex = 0;
  40.579 +			soundDSFifoAIndex	   = 0;
  40.580 +			soundDSFifoACount	   = 0;
  40.581 +			soundDSAValue = 0;
  40.582 +			memset(soundDSFifoA, 0, 32);
  40.583 +		}
  40.584 +		soundDSAEnabled = (data & 0x0300) ? true : false;
  40.585 +		soundDSATimer	= (data & 0x0400) ? 1 : 0;
  40.586 +		if (data & 0x8000)
  40.587 +		{
  40.588 +			soundDSFifoBWriteIndex = 0;
  40.589 +			soundDSFifoBIndex	   = 0;
  40.590 +			soundDSFifoBCount	   = 0;
  40.591 +			soundDSBValue = 0;
  40.592 +			memset(soundDSFifoB, 0, 32);
  40.593 +		}
  40.594 +		soundDSBEnabled = (data & 0x3000) ? true : false;
  40.595 +		soundDSBTimer	= (data & 0x4000) ? 1 : 0;
  40.596 +		*((u16 *)&ioMem[address]) = data;
  40.597 +		break;
  40.598 +	case FIFOA_L:
  40.599 +	case FIFOA_H:
  40.600 +		soundDSFifoA[soundDSFifoAWriteIndex++] = data & 0xFF;
  40.601 +		soundDSFifoA[soundDSFifoAWriteIndex++] = data >> 8;
  40.602 +		soundDSFifoACount		 += 2;
  40.603 +		soundDSFifoAWriteIndex	 &= 31;
  40.604 +		*((u16 *)&ioMem[address]) = data;
  40.605 +		break;
  40.606 +	case FIFOB_L:
  40.607 +	case FIFOB_H:
  40.608 +		soundDSFifoB[soundDSFifoBWriteIndex++] = data & 0xFF;
  40.609 +		soundDSFifoB[soundDSFifoBWriteIndex++] = data >> 8;
  40.610 +		soundDSFifoBCount		 += 2;
  40.611 +		soundDSFifoBWriteIndex	 &= 31;
  40.612 +		*((u16 *)&ioMem[address]) = data;
  40.613 +		break;
  40.614 +	case 0x88:
  40.615 +		data &= 0xC3FF;
  40.616 +		*((u16 *)&ioMem[address]) = data;
  40.617 +		break;
  40.618 +	case 0x90:
  40.619 +	case 0x92:
  40.620 +	case 0x94:
  40.621 +	case 0x96:
  40.622 +	case 0x98:
  40.623 +	case 0x9a:
  40.624 +	case 0x9c:
  40.625 +	case 0x9e:
  40.626 +		*((u16 *)&sound3WaveRam[(sound3Bank * 0x10) ^ 0x10 + (address & 14)]) = data;
  40.627 +		*((u16 *)&ioMem[address]) = data;
  40.628 +		break;
  40.629 +	}
  40.630 +}
  40.631 +
  40.632 +void soundChannel1()
  40.633 +{
  40.634 +	int vol = sound1EnvelopeVolume;
  40.635 +
  40.636 +	int freq  = 0;
  40.637 +	int value = 0;
  40.638 +
  40.639 +	if (sound1On && (sound1ATL || !sound1Continue))
  40.640 +	{
  40.641 +		sound1Index += soundQuality * sound1Skip;
  40.642 +		sound1Index &= 0x1fffffff;
  40.643 +
  40.644 +		value = ((s8)sound1Wave[sound1Index >> 24]) * vol;
  40.645 +	}
  40.646 +
  40.647 +	soundBuffer[0][soundIndex] = value;
  40.648 +
  40.649 +	if (sound1On)
  40.650 +	{
  40.651 +		if (sound1ATL)
  40.652 +		{
  40.653 +			sound1ATL -= soundQuality;
  40.654 +
  40.655 +			if (sound1ATL <= 0 && sound1Continue)
  40.656 +			{
  40.657 +				ioMem[NR52] &= 0xfe;
  40.658 +				sound1On	 = 0;
  40.659 +			}
  40.660 +		}
  40.661 +
  40.662 +		if (sound1EnvelopeATL)
  40.663 +		{
  40.664 +			sound1EnvelopeATL -= soundQuality;
  40.665 +
  40.666 +			if (sound1EnvelopeATL <= 0)
  40.667 +			{
  40.668 +				if (sound1EnvelopeUpDown)
  40.669 +				{
  40.670 +					if (sound1EnvelopeVolume < 15)
  40.671 +						sound1EnvelopeVolume++;
  40.672 +				}
  40.673 +				else
  40.674 +				{
  40.675 +					if (sound1EnvelopeVolume)
  40.676 +						sound1EnvelopeVolume--;
  40.677 +				}
  40.678 +
  40.679 +				sound1EnvelopeATL += sound1EnvelopeATLReload;
  40.680 +			}
  40.681 +		}
  40.682 +
  40.683 +		if (sound1SweepATL)
  40.684 +		{
  40.685 +			sound1SweepATL -= soundQuality;
  40.686 +
  40.687 +			if (sound1SweepATL <= 0)
  40.688 +			{
  40.689 +				freq = (((int)(ioMem[NR14] & 7) << 8) | ioMem[NR13]);
  40.690 +
  40.691 +				int updown = 1;
  40.692 +
  40.693 +				if (sound1SweepUpDown)
  40.694 +					updown = -1;
  40.695 +
  40.696 +				int newfreq = 0;
  40.697 +				if (sound1SweepSteps)
  40.698 +				{
  40.699 +					newfreq = freq + updown * freq / (1 << sound1SweepSteps);
  40.700 +					if (newfreq == freq)
  40.701 +						newfreq = 0;
  40.702 +				}
  40.703 +				else
  40.704 +					newfreq = freq;
  40.705 +
  40.706 +				if (newfreq < 0)
  40.707 +				{
  40.708 +					sound1SweepATL += sound1SweepATLReload;
  40.709 +				}
  40.710 +				else if (newfreq > 2047)
  40.711 +				{
  40.712 +					sound1SweepATL = 0;
  40.713 +					sound1On	   = 0;
  40.714 +					ioMem[NR52]	  &= 0xfe;
  40.715 +				}
  40.716 +				else
  40.717 +				{
  40.718 +					sound1SweepATL += sound1SweepATLReload;
  40.719 +					sound1Skip		= SOUND_MAGIC / (2048 - newfreq);
  40.720 +
  40.721 +					ioMem[NR13] = newfreq & 0xff;
  40.722 +					ioMem[NR14] = (ioMem[NR14] & 0xf8) | ((newfreq >> 8) & 7);
  40.723 +				}
  40.724 +			}
  40.725 +		}
  40.726 +	}
  40.727 +}
  40.728 +
  40.729 +void soundChannel2()
  40.730 +{
  40.731 +	//  int freq = 0;
  40.732 +	int vol = sound2EnvelopeVolume;
  40.733 +
  40.734 +	int value = 0;
  40.735 +
  40.736 +	if (sound2On && (sound2ATL || !sound2Continue))
  40.737 +	{
  40.738 +		sound2Index += soundQuality * sound2Skip;
  40.739 +		sound2Index &= 0x1fffffff;
  40.740 +
  40.741 +		value = ((s8)sound2Wave[sound2Index >> 24]) * vol;
  40.742 +	}
  40.743 +
  40.744 +	soundBuffer[1][soundIndex] = value;
  40.745 +
  40.746 +	if (sound2On)
  40.747 +	{
  40.748 +		if (sound2ATL)
  40.749 +		{
  40.750 +			sound2ATL -= soundQuality;
  40.751 +
  40.752 +			if (sound2ATL <= 0 && sound2Continue)
  40.753 +			{
  40.754 +				ioMem[NR52] &= 0xfd;
  40.755 +				sound2On	 = 0;
  40.756 +			}
  40.757 +		}
  40.758 +
  40.759 +		if (sound2EnvelopeATL)
  40.760 +		{
  40.761 +			sound2EnvelopeATL -= soundQuality;
  40.762 +
  40.763 +			if (sound2EnvelopeATL <= 0)
  40.764 +			{
  40.765 +				if (sound2EnvelopeUpDown)
  40.766 +				{
  40.767 +					if (sound2EnvelopeVolume < 15)
  40.768 +						sound2EnvelopeVolume++;
  40.769 +				}
  40.770 +				else
  40.771 +				{
  40.772 +					if (sound2EnvelopeVolume)
  40.773 +						sound2EnvelopeVolume--;
  40.774 +				}
  40.775 +				sound2EnvelopeATL += sound2EnvelopeATLReload;
  40.776 +			}
  40.777 +		}
  40.778 +	}
  40.779 +}
  40.780 +
  40.781 +void soundChannel3()
  40.782 +{
  40.783 +	int value = sound3Last;
  40.784 +
  40.785 +	if (sound3On && (sound3ATL || !sound3Continue))
  40.786 +	{
  40.787 +		sound3Index += soundQuality * sound3Skip;
  40.788 +		if (sound3DataSize)
  40.789 +		{
  40.790 +			sound3Index &= 0x3fffffff;
  40.791 +			value		 = sound3WaveRam[sound3Index >> 25];
  40.792 +		}
  40.793 +		else
  40.794 +		{
  40.795 +			sound3Index &= 0x1fffffff;
  40.796 +			value		 = sound3WaveRam[sound3Bank * 0x10 + (sound3Index >> 25)];
  40.797 +		}
  40.798 +
  40.799 +		if ((sound3Index & 0x01000000))
  40.800 +		{
  40.801 +			value &= 0x0f;
  40.802 +		}
  40.803 +		else
  40.804 +		{
  40.805 +			value >>= 4;
  40.806 +		}
  40.807 +
  40.808 +		value -= 8;
  40.809 +		value *= 2;
  40.810 +
  40.811 +		if (sound3ForcedOutput)
  40.812 +		{
  40.813 +			value = ((value >> 1) + value) >> 1;
  40.814 +		}
  40.815 +		else
  40.816 +		{
  40.817 +			switch (sound3OutputLevel)
  40.818 +			{
  40.819 +			case 0:
  40.820 +				value = 0;
  40.821 +				break;
  40.822 +			case 1:
  40.823 +				break;
  40.824 +			case 2:
  40.825 +				value = (value >> 1);
  40.826 +				break;
  40.827 +			case 3:
  40.828 +				value = (value >> 2);
  40.829 +				break;
  40.830 +			}
  40.831 +		}
  40.832 +		//value += 1;
  40.833 +		sound3Last = value;
  40.834 +	}
  40.835 +
  40.836 +	soundBuffer[2][soundIndex] = value;
  40.837 +
  40.838 +	if (sound3On)
  40.839 +	{
  40.840 +		if (sound3ATL)
  40.841 +		{
  40.842 +			sound3ATL -= soundQuality;
  40.843 +
  40.844 +			if (sound3ATL <= 0 && sound3Continue)
  40.845 +			{
  40.846 +				ioMem[NR52] &= 0xfb;
  40.847 +				sound3On	 = 0;
  40.848 +			}
  40.849 +		}
  40.850 +	}
  40.851 +}
  40.852 +
  40.853 +void soundChannel4()
  40.854 +{
  40.855 +	int vol = sound4EnvelopeVolume;
  40.856 +
  40.857 +	int value = 0;
  40.858 +
  40.859 +	if (sound4Clock <= 0x0c)
  40.860 +	{
  40.861 +		if (sound4On && (sound4ATL || !sound4Continue))
  40.862 +		{
  40.863 +	  #define NOISE_ONE_SAMP_SCALE  0x200000
  40.864 +
  40.865 +			sound4Index		 += soundQuality * sound4Skip;
  40.866 +			sound4ShiftIndex += soundQuality * sound4ShiftSkip;
  40.867 +
  40.868 +			if (sound4NSteps)
  40.869 +			{
  40.870 +				while (sound4ShiftIndex >= NOISE_ONE_SAMP_SCALE)
  40.871 +				{
  40.872 +					sound4ShiftRight = (((sound4ShiftRight << 6) ^
  40.873 +					                     (sound4ShiftRight << 5)) & 0x40) |
  40.874 +					                   (sound4ShiftRight >> 1);
  40.875 +					sound4ShiftIndex -= NOISE_ONE_SAMP_SCALE;
  40.876 +				}
  40.877 +			}
  40.878 +			else
  40.879 +			{
  40.880 +				while (sound4ShiftIndex >= NOISE_ONE_SAMP_SCALE)
  40.881 +				{
  40.882 +					sound4ShiftRight = (((sound4ShiftRight << 14) ^
  40.883 +					                     (sound4ShiftRight << 13)) & 0x4000) |
  40.884 +					                   (sound4ShiftRight >> 1);
  40.885 +
  40.886 +					sound4ShiftIndex -= NOISE_ONE_SAMP_SCALE;
  40.887 +				}
  40.888 +			}
  40.889 +
  40.890 +			sound4Index		 %= NOISE_ONE_SAMP_SCALE;
  40.891 +			sound4ShiftIndex %= NOISE_ONE_SAMP_SCALE;
  40.892 +
  40.893 +			value = ((sound4ShiftRight & 1) * 2 - 1) * vol;
  40.894 +		}
  40.895 +		else
  40.896 +		{
  40.897 +			value = 0;
  40.898 +		}
  40.899 +	}
  40.900 +
  40.901 +	soundBuffer[3][soundIndex] = value;
  40.902 +
  40.903 +	if (sound4On)
  40.904 +	{
  40.905 +		if (sound4ATL)
  40.906 +		{
  40.907 +			sound4ATL -= soundQuality;
  40.908 +
  40.909 +			if (sound4ATL <= 0 && sound4Continue)
  40.910 +			{
  40.911 +				ioMem[NR52] &= 0xfd;
  40.912 +				sound4On	 = 0;
  40.913 +			}
  40.914 +		}
  40.915 +
  40.916 +		if (sound4EnvelopeATL)
  40.917 +		{
  40.918 +			sound4EnvelopeATL -= soundQuality;
  40.919 +
  40.920 +			if (sound4EnvelopeATL <= 0)
  40.921 +			{
  40.922 +				if (sound4EnvelopeUpDown)
  40.923 +				{
  40.924 +					if (sound4EnvelopeVolume < 15)
  40.925 +						sound4EnvelopeVolume++;
  40.926 +				}
  40.927 +				else
  40.928 +				{
  40.929 +					if (sound4EnvelopeVolume)
  40.930 +						sound4EnvelopeVolume--;
  40.931 +				}
  40.932 +				sound4EnvelopeATL += sound4EnvelopeATLReload;
  40.933 +			}
  40.934 +		}
  40.935 +	}
  40.936 +}
  40.937 +
  40.938 +void soundDirectSoundA()
  40.939 +{
  40.940 +	soundBuffer[4][soundIndex] = soundDSAValue;
  40.941 +}
  40.942 +
  40.943 +void soundDirectSoundATimer()
  40.944 +{
  40.945 +	if (soundDSAEnabled)
  40.946 +	{
  40.947 +		if (soundDSFifoACount <= 16)
  40.948 +		{
  40.949 +			CPUCheckDMA(3, 2);
  40.950 +			if (soundDSFifoACount <= 16)
  40.951 +			{
  40.952 +				soundEvent(FIFOA_L, (u16)0);
  40.953 +				soundEvent(FIFOA_H, (u16)0);
  40.954 +				soundEvent(FIFOA_L, (u16)0);
  40.955 +				soundEvent(FIFOA_H, (u16)0);
  40.956 +				soundEvent(FIFOA_L, (u16)0);
  40.957 +				soundEvent(FIFOA_H, (u16)0);
  40.958 +				soundEvent(FIFOA_L, (u16)0);
  40.959 +				soundEvent(FIFOA_H, (u16)0);
  40.960 +			}
  40.961 +		}
  40.962 +
  40.963 +		soundDSAValue	  = (soundDSFifoA[soundDSFifoAIndex]);
  40.964 +		soundDSFifoAIndex = (++soundDSFifoAIndex) & 31;
  40.965 +		soundDSFifoACount--;
  40.966 +	}
  40.967 +	else
  40.968 +		soundDSAValue = 0;
  40.969 +}
  40.970 +
  40.971 +void soundDirectSoundB()
  40.972 +{
  40.973 +	soundBuffer[5][soundIndex] = soundDSBValue;
  40.974 +}
  40.975 +
  40.976 +void soundDirectSoundBTimer()
  40.977 +{
  40.978 +	if (soundDSBEnabled)
  40.979 +	{
  40.980 +		if (soundDSFifoBCount <= 16)
  40.981 +		{
  40.982 +			CPUCheckDMA(3, 4);
  40.983 +			if (soundDSFifoBCount <= 16)
  40.984 +			{
  40.985 +				soundEvent(FIFOB_L, (u16)0);
  40.986 +				soundEvent(FIFOB_H, (u16)0);
  40.987 +				soundEvent(FIFOB_L, (u16)0);
  40.988 +				soundEvent(FIFOB_H, (u16)0);
  40.989 +				soundEvent(FIFOB_L, (u16)0);
  40.990 +				soundEvent(FIFOB_H, (u16)0);
  40.991 +				soundEvent(FIFOB_L, (u16)0);
  40.992 +				soundEvent(FIFOB_H, (u16)0);
  40.993 +			}
  40.994 +		}
  40.995 +
  40.996 +		soundDSBValue	  = (soundDSFifoB[soundDSFifoBIndex]);
  40.997 +		soundDSFifoBIndex = (++soundDSFifoBIndex) & 31;
  40.998 +		soundDSFifoBCount--;
  40.999 +	}
 40.1000 +	else
 40.1001 +	{
 40.1002 +		soundDSBValue = 0;
 40.1003 +	}
 40.1004 +}
 40.1005 +
 40.1006 +void soundTimerOverflow(int timer)
 40.1007 +{
 40.1008 +	if (soundDSAEnabled && (soundDSATimer == timer))
 40.1009 +	{
 40.1010 +		soundDirectSoundATimer();
 40.1011 +	}
 40.1012 +	if (soundDSBEnabled && (soundDSBTimer == timer))
 40.1013 +	{
 40.1014 +		soundDirectSoundBTimer();
 40.1015 +	}
 40.1016 +}
 40.1017 +
 40.1018 +void soundMix()
 40.1019 +{
 40.1020 +	int res		 = 0;
 40.1021 +	int cgbRes	 = 0;
 40.1022 +	int ratio	 = ioMem[0x82] & 3;
 40.1023 +	int dsaRatio = ioMem[0x82] & 4;
 40.1024 +	int dsbRatio = ioMem[0x82] & 8;
 40.1025 +
 40.1026 +	if (ioMem)
 40.1027 +		soundBalance = (ioMem[NR51] & soundEnableFlag & ~soundMutedFlag);
 40.1028 +
 40.1029 +	if (soundBalance & 16)
 40.1030 +	{
 40.1031 +		cgbRes = ((s8)soundBuffer[0][soundIndex]);
 40.1032 +	}
 40.1033 +	if (soundBalance & 32)
 40.1034 +	{
 40.1035 +		cgbRes += ((s8)soundBuffer[1][soundIndex]);
 40.1036 +	}
 40.1037 +	if (soundBalance & 64)
 40.1038 +	{
 40.1039 +		cgbRes += ((s8)soundBuffer[2][soundIndex]);
 40.1040 +	}
 40.1041 +	if (soundBalance & 128)
 40.1042 +	{
 40.1043 +		cgbRes += ((s8)soundBuffer[3][soundIndex]);
 40.1044 +	}
 40.1045 +
 40.1046 +	if ((soundControl & 0x0200) && (soundEnableFlag & 0x100))
 40.1047 +	{
 40.1048 +		if (!dsaRatio)
 40.1049 +			res = ((s8)soundBuffer[4][soundIndex]) >> 1;
 40.1050 +		else
 40.1051 +			res = ((s8)soundBuffer[4][soundIndex]);
 40.1052 +	}
 40.1053 +
 40.1054 +	if ((soundControl & 0x2000) && (soundEnableFlag & 0x200))
 40.1055 +	{
 40.1056 +		if (!dsbRatio)
 40.1057 +			res += ((s8)soundBuffer[5][soundIndex]) >> 1;
 40.1058 +		else
 40.1059 +			res += ((s8)soundBuffer[5][soundIndex]);
 40.1060 +	}
 40.1061 +
 40.1062 +	res	   = (res * 170);
 40.1063 +	cgbRes = (cgbRes * 52 * soundLevel1);
 40.1064 +
 40.1065 +	switch (ratio)
 40.1066 +	{
 40.1067 +	case 0:
 40.1068 +	case 3: // prohibited, but 25%
 40.1069 +		cgbRes >>= 2;
 40.1070 +		break;
 40.1071 +	case 1:
 40.1072 +		cgbRes >>= 1;
 40.1073 +		break;
 40.1074 +	case 2:
 40.1075 +		break;
 40.1076 +	}
 40.1077 +
 40.1078 +	res += cgbRes;
 40.1079 +
 40.1080 +	if (soundEcho)
 40.1081 +	{
 40.1082 +		res *= 2;
 40.1083 +		res += soundFilter[soundEchoIndex];
 40.1084 +		res /= 2;
 40.1085 +		soundFilter[soundEchoIndex++] = res;
 40.1086 +	}
 40.1087 +
 40.1088 +	if (soundLowPass)
 40.1089 +	{
 40.1090 +		soundLeft[4] = soundLeft[3];
 40.1091 +		soundLeft[3] = soundLeft[2];
 40.1092 +		soundLeft[2] = soundLeft[1];
 40.1093 +		soundLeft[1] = soundLeft[0];
 40.1094 +		soundLeft[0] = res;
 40.1095 +		res = (soundLeft[4] + 2 * soundLeft[3] + 8 * soundLeft[2] + 2 * soundLeft[1] +
 40.1096 +		       soundLeft[0]) / 14;
 40.1097 +	}
 40.1098 +
 40.1099 +	bool noSpecialEffects = false;
 40.1100 +#if (defined(WIN32) && !defined(SDL))
 40.1101 +	if (theApp.soundRecording || theApp.aviRecording || theApp.nvAudioLog)
 40.1102 +		noSpecialEffects = true;
 40.1103 +#endif
 40.1104 +
 40.1105 +	if (!noSpecialEffects)
 40.1106 +	{
 40.1107 +		switch (soundVolume)
 40.1108 +		{
 40.1109 +		case 0:
 40.1110 +		case 1:
 40.1111 +		case 2:
 40.1112 +		case 3:
 40.1113 +			res *= (soundVolume + 1);
 40.1114 +			break;
 40.1115 +		case 4:
 40.1116 +			res >>= 2;
 40.1117 +			break;
 40.1118 +		case 5:
 40.1119 +			res >>= 1;
 40.1120 +			break;
 40.1121 +		}
 40.1122 +	}
 40.1123 +
 40.1124 +	if (res > 32767)
 40.1125 +		res = 32767;
 40.1126 +	if (res < -32768)
 40.1127 +		res = -32768;
 40.1128 +
 40.1129 +	if (soundReverse && !noSpecialEffects)
 40.1130 +	{
 40.1131 +		soundFinalWave[++soundBufferIndex] = res;
 40.1132 +		if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound))
 40.1133 +			/*assert(false)*/;
 40.1134 +		else
 40.1135 +			soundFrameSound[++soundFrameSoundWritten] = res;
 40.1136 +	}
 40.1137 +	else
 40.1138 +	{
 40.1139 +		soundFinalWave[soundBufferIndex++] = res;
 40.1140 +		if (soundFrameSoundWritten >= countof(soundFrameSound))
 40.1141 +			/*assert(false)*/;
 40.1142 +		else
 40.1143 +			soundFrameSound[soundFrameSoundWritten++] = res;
 40.1144 +	}
 40.1145 +
 40.1146 +	res	   = 0;
 40.1147 +	cgbRes = 0;
 40.1148 +
 40.1149 +	if (soundBalance & 1)
 40.1150 +	{
 40.1151 +		cgbRes = ((s8)soundBuffer[0][soundIndex]);
 40.1152 +	}
 40.1153 +	if (soundBalance & 2)
 40.1154 +	{
 40.1155 +		cgbRes += ((s8)soundBuffer[1][soundIndex]);
 40.1156 +	}
 40.1157 +	if (soundBalance & 4)
 40.1158 +	{
 40.1159 +		cgbRes += ((s8)soundBuffer[2][soundIndex]);
 40.1160 +	}
 40.1161 +	if (soundBalance & 8)
 40.1162 +	{
 40.1163 +		cgbRes += ((s8)soundBuffer[3][soundIndex]);
 40.1164 +	}
 40.1165 +
 40.1166 +	if ((soundControl & 0x0100) && (soundEnableFlag & 0x100))
 40.1167 +	{
 40.1168 +		if (!dsaRatio)
 40.1169 +			res = ((s8)soundBuffer[4][soundIndex]) >> 1;
 40.1170 +		else
 40.1171 +			res = ((s8)soundBuffer[4][soundIndex]);
 40.1172 +	}
 40.1173 +
 40.1174 +	if ((soundControl & 0x1000) && (soundEnableFlag & 0x200))
 40.1175 +	{
 40.1176 +		if (!dsbRatio)
 40.1177 +			res += ((s8)soundBuffer[5][soundIndex]) >> 1;
 40.1178 +		else
 40.1179 +			res += ((s8)soundBuffer[5][soundIndex]);
 40.1180 +	}
 40.1181 +
 40.1182 +	res	   = (res * 170);
 40.1183 +	cgbRes = (cgbRes * 52 * soundLevel1);
 40.1184 +
 40.1185 +	switch (ratio)
 40.1186 +	{
 40.1187 +	case 0:
 40.1188 +	case 3: // prohibited, but 25%
 40.1189 +		cgbRes >>= 2;
 40.1190 +		break;
 40.1191 +	case 1:
 40.1192 +		cgbRes >>= 1;
 40.1193 +		break;
 40.1194 +	case 2:
 40.1195 +		break;
 40.1196 +	}
 40.1197 +
 40.1198 +	res += cgbRes;
 40.1199 +
 40.1200 +	if (soundEcho)
 40.1201 +	{
 40.1202 +		res *= 2;
 40.1203 +		res += soundFilter[soundEchoIndex];
 40.1204 +		res /= 2;
 40.1205 +		soundFilter[soundEchoIndex++] = res;
 40.1206 +
 40.1207 +		if (soundEchoIndex >= 4000)
 40.1208 +			soundEchoIndex = 0;
 40.1209 +	}
 40.1210 +
 40.1211 +	if (soundLowPass)
 40.1212 +	{
 40.1213 +		soundRight[4] = soundRight[3];
 40.1214 +		soundRight[3] = soundRight[2];
 40.1215 +		soundRight[2] = soundRight[1];
 40.1216 +		soundRight[1] = soundRight[0];
 40.1217 +		soundRight[0] = res;
 40.1218 +		res = (soundRight[4] + 2 * soundRight[3] + 8 * soundRight[2] + 2 * soundRight[1] +
 40.1219 +		       soundRight[0]) / 14;
 40.1220 +	}
 40.1221 +
 40.1222 +	if (!noSpecialEffects)
 40.1223 +	{
 40.1224 +		switch (soundVolume)
 40.1225 +		{
 40.1226 +		case 0:
 40.1227 +		case 1:
 40.1228 +		case 2:
 40.1229 +		case 3:
 40.1230 +			res *= (soundVolume + 1);
 40.1231 +			break;
 40.1232 +		case 4:
 40.1233 +			res >>= 2;
 40.1234 +			break;
 40.1235 +		case 5:
 40.1236 +			res >>= 1;
 40.1237 +			break;
 40.1238 +		}
 40.1239 +	}
 40.1240 +
 40.1241 +	if (res > 32767)
 40.1242 +		res = 32767;
 40.1243 +	if (res < -32768)
 40.1244 +		res = -32768;
 40.1245 +
 40.1246 +	if (soundReverse && !noSpecialEffects)
 40.1247 +	{
 40.1248 +		soundFinalWave[-1 + soundBufferIndex++]		   = res;
 40.1249 +		if ((soundFrameSoundWritten) >= countof(soundFrameSound))
 40.1250 +			/*assert(false)*/;
 40.1251 +		else
 40.1252 +			soundFrameSound[-1 + soundFrameSoundWritten++] = res;
 40.1253 +	}
 40.1254 +	else
 40.1255 +	{
 40.1256 +		soundFinalWave[soundBufferIndex++]			  = res;
 40.1257 +		if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound))
 40.1258 +			/*assert(false)*/;
 40.1259 +		else
 40.1260 +			soundFrameSound[soundFrameSoundWritten++] = res;
 40.1261 +	}
 40.1262 +}
 40.1263 +
 40.1264 +void soundTick()
 40.1265 +{
 40.1266 +	if (systemSoundOn)
 40.1267 +	{
 40.1268 +		if (soundMasterOn && !stopState)
 40.1269 +		{
 40.1270 +			soundChannel1();
 40.1271 +			soundChannel2();
 40.1272 +			soundChannel3();
 40.1273 +			soundChannel4();
 40.1274 +			soundDirectSoundA();
 40.1275 +			soundDirectSoundB();
 40.1276 +			soundMix();
 40.1277 +		}
 40.1278 +		else
 40.1279 +		{
 40.1280 +			soundFinalWave[soundBufferIndex++] = 0;
 40.1281 +			soundFinalWave[soundBufferIndex++] = 0;
 40.1282 +			if ((soundFrameSoundWritten + 1) >= countof(soundFrameSound))
 40.1283 +				/*assert(false)*/;
 40.1284 +			else
 40.1285 +			{
 40.1286 +				soundFrameSound[soundFrameSoundWritten++] = 0;
 40.1287 +				soundFrameSound[soundFrameSoundWritten++] = 0;
 40.1288 +			}
 40.1289 +		}
 40.1290 +
 40.1291 +		soundIndex++;
 40.1292 +
 40.1293 +		if (2 * soundBufferIndex >= soundBufferLen)
 40.1294 +		{
 40.1295 +			if (systemSoundOn)
 40.1296 +			{
 40.1297 +				if (soundPaused)
 40.1298 +				{
 40.1299 +					soundResume();
 40.1300 +				}
 40.1301 +
 40.1302 +				systemSoundWriteToBuffer();
 40.1303 +			}
 40.1304 +			soundIndex		 = 0;
 40.1305 +			soundBufferIndex = 0;
 40.1306 +		}
 40.1307 +	}
 40.1308 +}
 40.1309 +
 40.1310 +void soundShutdown()
 40.1311 +{
 40.1312 +	systemSoundShutdown();
 40.1313 +}
 40.1314 +
 40.1315 +void soundPause()
 40.1316 +{
 40.1317 +	systemSoundPause();
 40.1318 +}
 40.1319 +
 40.1320 +void soundResume()
 40.1321 +{
 40.1322 +	systemSoundResume();
 40.1323 +}
 40.1324 +
 40.1325 +void soundEnableChannels(int channels)
 40.1326 +{
 40.1327 +	int c = (channels & 0x0f) << 4;
 40.1328 +	soundEnableFlag |= ((channels & 0x30f) | c);
 40.1329 +}
 40.1330 +
 40.1331 +void soundDisableChannels(int channels)
 40.1332 +{
 40.1333 +	int c = (channels & 0x0f) << 4;
 40.1334 +	soundEnableFlag &= ~((channels & 0x30f) | c);
 40.1335 +}
 40.1336 +
 40.1337 +int soundGetEnabledChannels()
 40.1338 +{
 40.1339 +	return (soundEnableFlag & 0x30f);
 40.1340 +}
 40.1341 +
 40.1342 +#if 0
 40.1343 +// unused
 40.1344 +void soundMuteChannels(int channels)
 40.1345 +{
 40.1346 +	soundMutedFlag |= channels & 0x30f;
 40.1347 +}
 40.1348 +
 40.1349 +void soundUnmuteChannels(int channels)
 40.1350 +{
 40.1351 +	soundMutedFlag &= ~(channels & 0x30f);
 40.1352 +}
 40.1353 +
 40.1354 +int soundGetMutedChannels()
 40.1355 +{
 40.1356 +	return (soundMutedFlag & 0x30f);
 40.1357 +}
 40.1358 +#endif
 40.1359 +
 40.1360 +void soundReset()
 40.1361 +{
 40.1362 +	systemSoundReset();
 40.1363 +
 40.1364 +	soundPaused		  = 1;
 40.1365 +	soundPlay		  = 0;
 40.1366 +	SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS;
 40.1367 +	soundTicks		  = SOUND_CLOCK_TICKS;
 40.1368 +	soundNextPosition = 0;
 40.1369 +	soundMasterOn	  = 1;
 40.1370 +	soundIndex		  = 0;
 40.1371 +	soundBufferIndex  = 0;
 40.1372 +	soundLevel1		  = 7;
 40.1373 +	soundLevel2		  = 7;
 40.1374 +
 40.1375 +	sound1On = 0;
 40.1376 +	sound1ATL = 0;
 40.1377 +	sound1Skip = 0;
 40.1378 +	sound1Index = 0;
 40.1379 +	sound1Continue = 0;
 40.1380 +	sound1EnvelopeVolume	= 0;
 40.1381 +	sound1EnvelopeATL		= 0;
 40.1382 +	sound1EnvelopeUpDown	= 0;
 40.1383 +	sound1EnvelopeATLReload = 0;
 40.1384 +	sound1SweepATL			= 0;
 40.1385 +	sound1SweepATLReload	= 0;
 40.1386 +	sound1SweepSteps		= 0;
 40.1387 +	sound1SweepUpDown		= 0;
 40.1388 +	sound1SweepStep			= 0;
 40.1389 +	sound1Wave				= soundWavePattern[2];
 40.1390 +
 40.1391 +	sound2On = 0;
 40.1392 +	sound2ATL = 0;
 40.1393 +	sound2Skip = 0;
 40.1394 +	sound2Index = 0;
 40.1395 +	sound2Continue = 0;
 40.1396 +	sound2EnvelopeVolume	= 0;
 40.1397 +	sound2EnvelopeATL		= 0;
 40.1398 +	sound2EnvelopeUpDown	= 0;
 40.1399 +	sound2EnvelopeATLReload = 0;
 40.1400 +	sound2Wave				= soundWavePattern[2];
 40.1401 +
 40.1402 +	sound3On = 0;
 40.1403 +	sound3ATL = 0;
 40.1404 +	sound3Skip		   = 0;
 40.1405 +	sound3Index		   = 0;
 40.1406 +	sound3Continue	   = 0;
 40.1407 +	sound3OutputLevel  = 0;
 40.1408 +	sound3Last		   = 0;
 40.1409 +	sound3Bank		   = 0;
 40.1410 +	sound3DataSize	   = 0;
 40.1411 +	sound3ForcedOutput = 0;
 40.1412 +
 40.1413 +	sound4On = 0;
 40.1414 +	sound4Clock = 0;
 40.1415 +	sound4ATL = 0;
 40.1416 +	sound4Skip = 0;
 40.1417 +	sound4Index = 0;
 40.1418 +	sound4ShiftRight		= 0x7f;
 40.1419 +	sound4NSteps			= 0;
 40.1420 +	sound4CountDown			= 0;
 40.1421 +	sound4Continue			= 0;
 40.1422 +	sound4EnvelopeVolume	= 0;
 40.1423 +	sound4EnvelopeATL		= 0;
 40.1424 +	sound4EnvelopeUpDown	= 0;
 40.1425 +	sound4EnvelopeATLReload = 0;
 40.1426 +
 40.1427 +	sound1On = 0;
 40.1428 +	sound2On = 0;
 40.1429 +	sound3On = 0;
 40.1430 +	sound4On = 0;
 40.1431 +
 40.1432 +	int addr = 0x90;
 40.1433 +
 40.1434 +	while (addr < 0xA0)
 40.1435 +	{
 40.1436 +		ioMem[addr++] = 0x00;
 40.1437 +		ioMem[addr++] = 0xff;
 40.1438 +	}
 40.1439 +
 40.1440 +	addr = 0;
 40.1441 +	while (addr < 0x20)
 40.1442 +	{
 40.1443 +		sound3WaveRam[addr++] = 0x00;
 40.1444 +		sound3WaveRam[addr++] = 0xff;
 40.1445 +	}
 40.1446 +
 40.1447 +	memset(soundFinalWave, 0, soundBufferLen);
 40.1448 +
 40.1449 +	memset(soundFilter, 0, sizeof(soundFilter));
 40.1450 +	soundEchoIndex = 0;
 40.1451 +}
 40.1452 +
 40.1453 +bool soundInit()
 40.1454 +{
 40.1455 +	if (systemSoundInit())
 40.1456 +	{
 40.1457 +		memset(soundBuffer[0], 0, 735 * 2);
 40.1458 +		memset(soundBuffer[1], 0, 735 * 2);
 40.1459 +		memset(soundBuffer[2], 0, 735 * 2);
 40.1460 +		memset(soundBuffer[3], 0, 735 * 2);
 40.1461 +
 40.1462 +		memset(soundFinalWave, 0, soundBufferLen);
 40.1463 +
 40.1464 +		soundPaused = 1;
 40.1465 +		return true;
 40.1466 +	}
 40.1467 +	return false;
 40.1468 +}
 40.1469 +
 40.1470 +void soundSetQuality(int quality)
 40.1471 +{
 40.1472 +	if (soundQuality != quality && systemSoundCanChangeQuality())
 40.1473 +	{
 40.1474 +		if (!soundOffFlag)
 40.1475 +			soundShutdown();
 40.1476 +		soundQuality	  = quality;
 40.1477 +		soundNextPosition = 0;
 40.1478 +		if (!soundOffFlag)
 40.1479 +			soundInit();
 40.1480 +		SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality;
 40.1481 +		soundIndex		  = 0;
 40.1482 +		soundBufferIndex  = 0;
 40.1483 +	}
 40.1484 +	else if (soundQuality != quality)
 40.1485 +	{
 40.1486 +		soundNextPosition = 0;
 40.1487 +		SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality;
 40.1488 +		soundIndex		  = 0;
 40.1489 +		soundBufferIndex  = 0;
 40.1490 +	}
 40.1491 +}
 40.1492 +
 40.1493 +void soundSaveGame(gzFile gzFile)
 40.1494 +{
 40.1495 +	soundTicks_int32		= (int32) soundTicks;
 40.1496 +	SOUND_CLOCK_TICKS_int32 = (int32) SOUND_CLOCK_TICKS;
 40.1497 +	soundDSBValue_int32		= (int32) soundDSBValue;
 40.1498 +
 40.1499 +	utilWriteData(gzFile, soundSaveStruct);
 40.1500 +	utilWriteData(gzFile, soundSaveStructV2);
 40.1501 +
 40.1502 +	utilGzWrite(gzFile, &soundQuality, sizeof(int32));
 40.1503 +	//utilWriteData(gzFile, soundSaveStructV3);
 40.1504 +}
 40.1505 +
 40.1506 +void soundReadGame(gzFile gzFile, int version)
 40.1507 +{
 40.1508 +	int32 oldSoundPaused = soundPaused;
 40.1509 +	int32 oldSoundEnableFlag = soundEnableFlag;
 40.1510 +	utilReadData(gzFile, soundSaveStruct);
 40.1511 +	soundPaused = oldSoundPaused;
 40.1512 +	soundEnableFlag = oldSoundEnableFlag;
 40.1513 +
 40.1514 +	if (version >= SAVE_GAME_VERSION_3)
 40.1515 +	{
 40.1516 +		utilReadData(gzFile, soundSaveStructV2);
 40.1517 +	}
 40.1518 +	else
 40.1519 +	{
 40.1520 +		sound3Bank		   = (ioMem[NR30] >> 6) & 1;
 40.1521 +		sound3DataSize	   = (ioMem[NR30] >> 5) & 1;
 40.1522 +		sound3ForcedOutput = (ioMem[NR32] >> 7) & 1;
 40.1523 +		// nothing better to do here...
 40.1524 +		memcpy(&sound3WaveRam[0x00], &ioMem[0x90], 0x10);
 40.1525 +		memcpy(&sound3WaveRam[0x10], &ioMem[0x90], 0x10);
 40.1526 +	}
 40.1527 +	soundBufferIndex = soundIndex * 2;
 40.1528 +
 40.1529 +	int quality = 1;
 40.1530 +	utilGzRead(gzFile, &quality, sizeof(int32));
 40.1531 +	soundSetQuality(quality);
 40.1532 +
 40.1533 +	sound1Wave = soundWavePattern[ioMem[NR11] >> 6];
 40.1534 +	sound2Wave = soundWavePattern[ioMem[NR21] >> 6];
 40.1535 +
 40.1536 +	//if(version >= SAVE_GAME_VERSION_14) {
 40.1537 +	//  utilReadData(gzFile, soundSaveStructV3);
 40.1538 +	//}
 40.1539 +	//else {
 40.1540 +	soundTicks		  = (soundtick_t) soundTicks_int32;
 40.1541 +	SOUND_CLOCK_TICKS = (soundtick_t) SOUND_CLOCK_TICKS_int32;
 40.1542 +	//}
 40.1543 +	soundDSBValue = (u8) (soundDSBValue_int32 & 0xff);
 40.1544 +}
 40.1545 +
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/src/gba/GBASound.h	Sun Mar 04 14:33:52 2012 -0600
    41.3 @@ -0,0 +1,73 @@
    41.4 +#ifndef VBA_GBA_SOUND_H
    41.5 +#define VBA_GBA_SOUND_H
    41.6 +
    41.7 +#if _MSC_VER > 1000
    41.8 +#pragma once
    41.9 +#endif // _MSC_VER > 1000
   41.10 +
   41.11 +#include "zlib.h"
   41.12 +#include "../Port.h"
   41.13 +
   41.14 +#define NR10 0x60
   41.15 +#define NR11 0x62
   41.16 +#define NR12 0x63
   41.17 +#define NR13 0x64
   41.18 +#define NR14 0x65
   41.19 +#define NR21 0x68
   41.20 +#define NR22 0x69
   41.21 +#define NR23 0x6c
   41.22 +#define NR24 0x6d
   41.23 +#define NR30 0x70
   41.24 +#define NR31 0x72
   41.25 +#define NR32 0x73
   41.26 +#define NR33 0x74
   41.27 +#define NR34 0x75
   41.28 +#define NR41 0x78
   41.29 +#define NR42 0x79
   41.30 +#define NR43 0x7c
   41.31 +#define NR44 0x7d
   41.32 +#define NR50 0x80
   41.33 +#define NR51 0x81
   41.34 +#define NR52 0x84
   41.35 +#define SGCNT0_H 0x82
   41.36 +#define FIFOA_L 0xa0
   41.37 +#define FIFOA_H 0xa2
   41.38 +#define FIFOB_L 0xa4
   41.39 +#define FIFOB_H 0xa6
   41.40 +
   41.41 +extern void soundTick();
   41.42 +extern void soundShutdown();
   41.43 +extern bool soundInit();
   41.44 +extern void soundPause();
   41.45 +extern void soundResume();
   41.46 +extern void soundEnableChannels(int);
   41.47 +extern void soundDisableChannels(int);
   41.48 +extern int  soundGetEnabledChannels();
   41.49 +extern void soundReset();
   41.50 +extern void soundSaveGame(gzFile);
   41.51 +extern void soundReadGame(gzFile, int);
   41.52 +extern void soundEvent(u32, u8);
   41.53 +extern void soundEvent(u32, u16);
   41.54 +extern void soundTimerOverflow(int);
   41.55 +extern void soundSetQuality(int);
   41.56 +
   41.57 +typedef int32 soundtick_t;
   41.58 +
   41.59 +extern soundtick_t SOUND_CLOCK_TICKS;
   41.60 +extern soundtick_t soundTicks;
   41.61 +extern int32       soundPaused;
   41.62 +extern bool8       soundOffFlag;
   41.63 +extern int32       soundQuality;
   41.64 +extern u32         soundBufferLen;
   41.65 +extern u32         soundBufferTotalLen;
   41.66 +extern u32         soundNextPosition;
   41.67 +extern u16         soundFinalWave[1470];
   41.68 +extern u16         soundFrameSound[735*30*2];
   41.69 +extern int32       soundFrameSoundWritten;
   41.70 +extern int32       soundVolume;
   41.71 +
   41.72 +extern bool8 soundEcho;
   41.73 +extern bool8 soundLowPass;
   41.74 +extern bool8 soundReverse;
   41.75 +
   41.76 +#endif // VBA_GBA_SOUND_H
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/src/gba/GBAinline.h	Sun Mar 04 14:33:52 2012 -0600
    42.3 @@ -0,0 +1,490 @@
    42.4 +#ifndef VBA_GBAINLINE_H
    42.5 +#define VBA_GBAINLINE_H
    42.6 +
    42.7 +#if _MSC_VER > 1000
    42.8 +#pragma once
    42.9 +#endif // _MSC_VER > 1000
   42.10 +
   42.11 +#include "../Port.h"
   42.12 +#include "../common/System.h"
   42.13 +#include "../common/vbalua.h"
   42.14 +#include "GBAGlobals.h"
   42.15 +#include "EEprom.h"
   42.16 +#include "Flash.h"
   42.17 +#include "RTC.h"
   42.18 +
   42.19 +extern bool8 cpuSramEnabled;
   42.20 +extern bool8 cpuFlashEnabled;
   42.21 +extern bool8 cpuEEPROMEnabled;
   42.22 +extern bool8 cpuEEPROMSensorEnabled;
   42.23 +
   42.24 +#define CPUReadByteQuick(addr) \
   42.25 +    map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
   42.26 +
   42.27 +#define CPUReadHalfWordQuick(addr) \
   42.28 +    READ16LE(((u16 *)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
   42.29 +
   42.30 +#define CPUReadMemoryQuick(addr) \
   42.31 +    READ32LE(((u32 *)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
   42.32 +
   42.33 +//inline u32 CPUReadMemoryQuick(u32 addr)
   42.34 +//{
   42.35 +//	u32 addrShift = (addr)>>24;
   42.36 +//	u32 rt = (addr) & map[addrShift].mask;
   42.37 +//	return READ32LE(((u32*)&map[addrShift].address[rt]));
   42.38 +//}
   42.39 +
   42.40 +inline u32 CPUReadMemory(u32 address)
   42.41 +{
   42.42 +#ifdef GBA_LOGGING
   42.43 +	if (address & 3)
   42.44 +	{
   42.45 +		if (systemVerbose & VERBOSE_UNALIGNED_MEMORY)
   42.46 +		{
   42.47 +			log("Unaligned word read: %08x at %08x\n", address, armMode ?
   42.48 +			    armNextPC - 4 : armNextPC - 2);
   42.49 +		}
   42.50 +	}
   42.51 +#endif
   42.52 +
   42.53 +	u32 value;
   42.54 +	switch (address >> 24)
   42.55 +	{
   42.56 +	case 0:
   42.57 +		if (reg[15].I >> 24)
   42.58 +		{
   42.59 +			if (address < 0x4000)
   42.60 +			{
   42.61 +#ifdef GBA_LOGGING
   42.62 +				if (systemVerbose & VERBOSE_ILLEGAL_READ)
   42.63 +				{
   42.64 +					log("Illegal word read: %08x at %08x\n", address, armMode ?
   42.65 +					    armNextPC - 4 : armNextPC - 2);
   42.66 +				}
   42.67 +#endif
   42.68 +
   42.69 +				value = READ32LE(((u32 *)&biosProtected));
   42.70 +			}
   42.71 +			else
   42.72 +				goto unreadable;
   42.73 +		}
   42.74 +		else
   42.75 +			value = READ32LE(((u32 *)&bios[address & 0x3FFC]));
   42.76 +		break;
   42.77 +	case 2:
   42.78 +		value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC]));
   42.79 +		break;
   42.80 +	case 3:
   42.81 +		value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC]));
   42.82 +		break;
   42.83 +	case 4:
   42.84 +		if ((address < 0x4000400) && ioReadable[address & 0x3fc])
   42.85 +		{
   42.86 +			if (ioReadable[(address & 0x3fc) + 2])
   42.87 +			{
   42.88 +				if (address >= 0x400012d && address <= 0x4000131)
   42.89 +					GBASystemCounters.lagged = false;
   42.90 +				value = READ32LE(((u32 *)&ioMem[address & 0x3fC]));
   42.91 +			}
   42.92 +			else
   42.93 +			{
   42.94 +				if (address >= 0x400012f && address <= 0x4000131)
   42.95 +					GBASystemCounters.lagged = false;
   42.96 +				value = READ16LE(((u16 *)&ioMem[address & 0x3fc]));
   42.97 +			}
   42.98 +		}
   42.99 +		else
  42.100 +			goto unreadable;
  42.101 +		break;
  42.102 +	case 5:
  42.103 +		value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC]));
  42.104 +		break;
  42.105 +	case 6:
  42.106 +		value = READ32LE(((u32 *)&vram[address & 0x1fffc]));
  42.107 +		break;
  42.108 +	case 7:
  42.109 +		value = READ32LE(((u32 *)&oam[address & 0x3FC]));
  42.110 +		break;
  42.111 +	case 8:
  42.112 +	case 9:
  42.113 +	case 10:
  42.114 +	case 11:
  42.115 +	case 12:
  42.116 +		value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
  42.117 +		break;
  42.118 +	case 13:
  42.119 +		if (cpuEEPROMEnabled)
  42.120 +			// no need to swap this
  42.121 +			return eepromRead(address);
  42.122 +		goto unreadable;
  42.123 +	case 14:
  42.124 +		if (cpuFlashEnabled | cpuSramEnabled)
  42.125 +			// no need to swap this
  42.126 +			return flashRead(address);
  42.127 +	// default
  42.128 +	default:
  42.129 +unreadable:
  42.130 +#ifdef GBA_LOGGING
  42.131 +		if (systemVerbose & VERBOSE_ILLEGAL_READ)
  42.132 +		{
  42.133 +			log("Illegal word read: %08x at %08x\n", address, armMode ?
  42.134 +			    armNextPC - 4 : armNextPC - 2);
  42.135 +		}
  42.136 +#endif
  42.137 +
  42.138 +		//    if(ioMem[0x205] & 0x40) {
  42.139 +		if (armState)
  42.140 +		{
  42.141 +			value = CPUReadMemoryQuick(reg[15].I);
  42.142 +		}
  42.143 +		else
  42.144 +		{
  42.145 +			value = CPUReadHalfWordQuick(reg[15].I) |
  42.146 +			        CPUReadHalfWordQuick(reg[15].I) << 16;
  42.147 +		}
  42.148 +		//  } else {
  42.149 +		//      value = *((u32 *)&bios[address & 0x3ffc]);
  42.150 +		//    }
  42.151 +		//        return 0xFFFFFFFF;
  42.152 +	}
  42.153 +
  42.154 +	if (address & 3)
  42.155 +	{
  42.156 +#ifdef C_CORE
  42.157 +		int shift = (address & 3) << 3;
  42.158 +		value = (value >> shift) | (value << (32 - shift));
  42.159 +#else
  42.160 +#ifdef __GNUC__
  42.161 +		asm ("and $3, %%ecx;"
  42.162 +		     "shl $3 ,%%ecx;"
  42.163 +		     "ror %%cl, %0"
  42.164 +			 : "=r" (value)
  42.165 +			 : "r" (value), "c" (address));
  42.166 +#else
  42.167 +		__asm {
  42.168 +			mov ecx, address;
  42.169 +			and ecx, 3;
  42.170 +			shl ecx, 3;
  42.171 +			ror [dword ptr value], cl;
  42.172 +		}
  42.173 +#endif
  42.174 +#endif
  42.175 +	}
  42.176 +	return value;
  42.177 +}
  42.178 +
  42.179 +extern u32 myROM[];
  42.180 +
  42.181 +inline u32 CPUReadHalfWord(u32 address)
  42.182 +{
  42.183 +#ifdef GBA_LOGGING
  42.184 +	if (address & 1)
  42.185 +	{
  42.186 +		if (systemVerbose & VERBOSE_UNALIGNED_MEMORY)
  42.187 +		{
  42.188 +			log("Unaligned halfword read: %08x at %08x\n", address, armMode ?
  42.189 +			    armNextPC - 4 : armNextPC - 2);
  42.190 +		}
  42.191 +	}
  42.192 +#endif
  42.193 +
  42.194 +	u32 value;
  42.195 +
  42.196 +	switch (address >> 24)
  42.197 +	{
  42.198 +	case 0:
  42.199 +		if (reg[15].I >> 24)
  42.200 +		{
  42.201 +			if (address < 0x4000)
  42.202 +			{
  42.203 +#ifdef GBA_LOGGING
  42.204 +				if (systemVerbose & VERBOSE_ILLEGAL_READ)
  42.205 +				{
  42.206 +					log("Illegal halfword read: %08x at %08x\n", address, armMode ?
  42.207 +					    armNextPC - 4 : armNextPC - 2);
  42.208 +				}
  42.209 +#endif
  42.210 +				value = READ16LE(((u16 *)&biosProtected[address&2]));
  42.211 +			}
  42.212 +			else
  42.213 +				goto unreadable;
  42.214 +		}
  42.215 +		else
  42.216 +			value = READ16LE(((u16 *)&bios[address & 0x3FFE]));
  42.217 +		break;
  42.218 +	case 2:
  42.219 +		value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE]));
  42.220 +		break;
  42.221 +	case 3:
  42.222 +		value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe]));
  42.223 +		break;
  42.224 +	case 4:
  42.225 +		if ((address < 0x4000400) && ioReadable[address & 0x3fe])
  42.226 +		{
  42.227 +			if (address >= 0x400012f && address <= 0x4000131)
  42.228 +				GBASystemCounters.lagged = false;
  42.229 +			value =  READ16LE(((u16 *)&ioMem[address & 0x3fe]));
  42.230 +		}
  42.231 +		else
  42.232 +			goto unreadable;
  42.233 +		break;
  42.234 +	case 5:
  42.235 +		value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe]));
  42.236 +		break;
  42.237 +	case 6:
  42.238 +		value = READ16LE(((u16 *)&vram[address & 0x1fffe]));
  42.239 +		break;
  42.240 +	case 7:
  42.241 +		value = READ16LE(((u16 *)&oam[address & 0x3fe]));
  42.242 +		break;
  42.243 +	case 8:
  42.244 +	case 9:
  42.245 +	case 10:
  42.246 +	case 11:
  42.247 +	case 12:
  42.248 +		if (address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
  42.249 +			value = rtcRead(address);
  42.250 +		else
  42.251 +			value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
  42.252 +		break;
  42.253 +	case 13:
  42.254 +		if (cpuEEPROMEnabled)
  42.255 +			// no need to swap this
  42.256 +			return eepromRead(address);
  42.257 +		goto unreadable;
  42.258 +	case 14:
  42.259 +		if (cpuFlashEnabled | cpuSramEnabled)
  42.260 +			// no need to swap this
  42.261 +			return flashRead(address);
  42.262 +	// default
  42.263 +	default:
  42.264 +unreadable:
  42.265 +#ifdef GBA_LOGGING
  42.266 +		if (systemVerbose & VERBOSE_ILLEGAL_READ)
  42.267 +		{
  42.268 +			log("Illegal halfword read: %08x at %08x\n", address, armMode ?
  42.269 +			    armNextPC - 4 : armNextPC - 2);
  42.270 +		}
  42.271 +#endif
  42.272 +		extern bool8 cpuDmaHack;
  42.273 +		extern u32   cpuDmaLast;
  42.274 +		extern int32 cpuDmaCount;
  42.275 +		if (cpuDmaHack && cpuDmaCount)
  42.276 +		{
  42.277 +			value = (u16)cpuDmaLast;
  42.278 +		}
  42.279 +		else
  42.280 +		{
  42.281 +			if (armState)
  42.282 +			{
  42.283 +				value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
  42.284 +			}
  42.285 +			else
  42.286 +			{
  42.287 +				value = CPUReadHalfWordQuick(reg[15].I);
  42.288 +			}
  42.289 +		}
  42.290 +		//    return value;
  42.291 +		//    if(address & 1)
  42.292 +		//      value = (value >> 8) | ((value & 0xFF) << 24);
  42.293 +		//    return 0xFFFF;
  42.294 +		break;
  42.295 +	}
  42.296 +
  42.297 +	if (address & 1)
  42.298 +	{
  42.299 +		value = (value >> 8) | (value << 24);
  42.300 +	}
  42.301 +
  42.302 +	return value;
  42.303 +}
  42.304 +
  42.305 +inline u16 CPUReadHalfWordSigned(u32 address)
  42.306 +{
  42.307 +	u16 value = CPUReadHalfWord(address);
  42.308 +	if ((address & 1))
  42.309 +		value = (s8)value;
  42.310 +	return value;
  42.311 +}
  42.312 +
  42.313 +inline u8 CPUReadByte(u32 address)
  42.314 +{
  42.315 +	switch (address >> 24)
  42.316 +	{
  42.317 +	case 0:
  42.318 +		if (reg[15].I >> 24)
  42.319 +		{
  42.320 +			if (address < 0x4000)
  42.321 +			{
  42.322 +#ifdef GBA_LOGGING
  42.323 +				if (systemVerbose & VERBOSE_ILLEGAL_READ)
  42.324 +				{
  42.325 +					log("Illegal byte read: %08x at %08x\n", address, armMode ?
  42.326 +					    armNextPC - 4 : armNextPC - 2);
  42.327 +				}
  42.328 +#endif
  42.329 +				return biosProtected[address & 3];
  42.330 +			}
  42.331 +			else
  42.332 +				goto unreadable;
  42.333 +		}
  42.334 +		return bios[address & 0x3FFF];
  42.335 +	case 2:
  42.336 +		return workRAM[address & 0x3FFFF];
  42.337 +	case 3:
  42.338 +		return internalRAM[address & 0x7fff];
  42.339 +	case 4:
  42.340 +		if ((address < 0x4000400) && ioReadable[address & 0x3ff])
  42.341 +		{
  42.342 +			if (address == 0x4000130 || address == 0x4000131)
  42.343 +				GBASystemCounters.lagged = false;
  42.344 +			return ioMem[address & 0x3ff];
  42.345 +		}
  42.346 +		else
  42.347 +			goto unreadable;
  42.348 +	case 5:
  42.349 +		return paletteRAM[address & 0x3ff];
  42.350 +	case 6:
  42.351 +		return vram[address & 0x1ffff];
  42.352 +	case 7:
  42.353 +		return oam[address & 0x3ff];
  42.354 +	case 8:
  42.355 +	case 9:
  42.356 +	case 10:
  42.357 +	case 11:
  42.358 +	case 12:
  42.359 +		return rom[address & 0x1FFFFFF];
  42.360 +	case 13:
  42.361 +		if (cpuEEPROMEnabled)
  42.362 +			return eepromRead(address);
  42.363 +		goto unreadable;
  42.364 +	case 14:
  42.365 +		if (cpuSramEnabled | cpuFlashEnabled)
  42.366 +			return flashRead(address);
  42.367 +		if (cpuEEPROMSensorEnabled)
  42.368 +		{
  42.369 +			switch (address & 0x00008f00)
  42.370 +			{
  42.371 +			case 0x8200:
  42.372 +				return systemGetSensorX() & 255;
  42.373 +			case 0x8300:
  42.374 +				return (systemGetSensorX() >> 8)|0x80;
  42.375 +			case 0x8400:
  42.376 +				return systemGetSensorY() & 255;
  42.377 +			case 0x8500:
  42.378 +				return systemGetSensorY() >> 8;
  42.379 +			}
  42.380 +		}
  42.381 +	// default
  42.382 +	default:
  42.383 +unreadable:
  42.384 +#ifdef GBA_LOGGING
  42.385 +		if (systemVerbose & VERBOSE_ILLEGAL_READ)
  42.386 +		{
  42.387 +			log("Illegal byte read: %08x at %08x\n", address, armMode ?
  42.388 +			    armNextPC - 4 : armNextPC - 2);
  42.389 +		}
  42.390 +#endif
  42.391 +
  42.392 +		if (armState)
  42.393 +		{
  42.394 +			return CPUReadByteQuick(reg[15].I+(address & 3));
  42.395 +		}
  42.396 +		else
  42.397 +		{
  42.398 +			return CPUReadByteQuick(reg[15].I+(address & 1));
  42.399 +		}
  42.400 +		//    return 0xFF;
  42.401 +		break;
  42.402 +	}
  42.403 +}
  42.404 +
  42.405 +inline void CPUWriteMemoryWrapped(u32 address, u32 value)
  42.406 +{
  42.407 +#ifdef GBA_LOGGING
  42.408 +	if (address & 3)
  42.409 +	{
  42.410 +		if (systemVerbose & VERBOSE_UNALIGNED_MEMORY)
  42.411 +		{
  42.412 +			log("Unaliagned word write: %08x to %08x from %08x\n",
  42.413 +			    value,
  42.414 +			    address,
  42.415 +			    armMode ? armNextPC - 4 : armNextPC - 2);
  42.416 +		}
  42.417 +	}
  42.418 +#endif
  42.419 +
  42.420 +	switch (address >> 24)
  42.421 +	{
  42.422 +	case 0x02:
  42.423 +#ifdef SDL
  42.424 +		if (*((u32 *)&freezeWorkRAM[address & 0x3FFFC]))
  42.425 +			cheatsWriteMemory((u32 *)&workRAM[address & 0x3FFFC],
  42.426 +			                  value,
  42.427 +			                  *((u32 *)&freezeWorkRAM[address & 0x3FFFC]));
  42.428 +		else
  42.429 +#endif
  42.430 +		WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value);
  42.431 +		break;
  42.432 +	case 0x03:
  42.433 +#ifdef SDL
  42.434 +		if (*((u32 *)&freezeInternalRAM[address & 0x7ffc]))
  42.435 +			cheatsWriteMemory((u32 *)&internalRAM[address & 0x7FFC],
  42.436 +			                  value,
  42.437 +			                  *((u32 *)&freezeInternalRAM[address & 0x7ffc]));
  42.438 +		else
  42.439 +#endif
  42.440 +		WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value);
  42.441 +		break;
  42.442 +	case 0x04:
  42.443 +		CPUUpdateRegister((address & 0x3FC), value & 0xFFFF);
  42.444 +		CPUUpdateRegister((address & 0x3FC) + 2, (value >> 16));
  42.445 +		break;
  42.446 +	case 0x05:
  42.447 +		WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
  42.448 +		break;
  42.449 +	case 0x06:
  42.450 +		if (address & 0x10000)
  42.451 +			WRITE32LE(((u32 *)&vram[address & 0x17ffc]), value);
  42.452 +		else
  42.453 +			WRITE32LE(((u32 *)&vram[address & 0x1fffc]), value);
  42.454 +		break;
  42.455 +	case 0x07:
  42.456 +		WRITE32LE(((u32 *)&oam[address & 0x3fc]), value);
  42.457 +		break;
  42.458 +	case 0x0D:
  42.459 +		if (cpuEEPROMEnabled)
  42.460 +		{
  42.461 +			eepromWrite(address, value);
  42.462 +			break;
  42.463 +		}
  42.464 +		goto unwritable;
  42.465 +	case 0x0E:
  42.466 +		if (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)
  42.467 +		{
  42.468 +			(*cpuSaveGameFunc)(address, (u8)value);
  42.469 +			break;
  42.470 +		}
  42.471 +	// default
  42.472 +	default:
  42.473 +unwritable:
  42.474 +#ifdef GBA_LOGGING
  42.475 +		if (systemVerbose & VERBOSE_ILLEGAL_WRITE)
  42.476 +		{
  42.477 +			log("Illegal word write: %08x to %08x from %08x\n",
  42.478 +			    value,
  42.479 +			    address,
  42.480 +			    armMode ? armNextPC - 4 : armNextPC - 2);
  42.481 +		}
  42.482 +#endif
  42.483 +		break;
  42.484 +	}
  42.485 +}
  42.486 +
  42.487 +inline void CPUWriteMemory(u32 address, u32 value)
  42.488 +{
  42.489 +	CPUWriteMemoryWrapped(address, value);
  42.490 +	CallRegisteredLuaMemHook(address, 4, value, LUAMEMHOOK_WRITE);
  42.491 +}
  42.492 +
  42.493 +#endif // VBA_GBAINLINE_H
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/src/gba/Makefile.am	Sun Mar 04 14:33:52 2012 -0600
    43.3 @@ -0,0 +1,48 @@
    43.4 +noinst_LIBRARIES = libgba.a
    43.5 +
    43.6 +libgba_a_SOURCES = \
    43.7 +	agbprint.h	\
    43.8 +	armdis.h	\
    43.9 +	arm-new.h	\
   43.10 +	bios.h		\
   43.11 +	EEprom.h	\
   43.12 +	elf.h		\
   43.13 +	Flash.h		\
   43.14 +	GBACheats.h	\
   43.15 +	GBAGfx.h	\
   43.16 +	GBAGlobals.h	\
   43.17 +	GBA.h		\
   43.18 +	GBAinline.h	\
   43.19 +	GBASound.h	\
   43.20 +	RTC.h		\
   43.21 +	Sram.h		\
   43.22 +	thumb.h		\
   43.23 +			\
   43.24 +	agbprint.cpp	\
   43.25 +	armdis.cpp	\
   43.26 +	bios.cpp	\
   43.27 +	EEprom.cpp	\
   43.28 +	elf.cpp		\
   43.29 +	Flash.cpp	\
   43.30 +	GBACheats.cpp	\
   43.31 +	GBA.cpp		\
   43.32 +	GBAGfx.cpp	\
   43.33 +	GBAGlobals.cpp	\
   43.34 +	GBASound.cpp	\
   43.35 +	Mode0.cpp	\
   43.36 +	Mode1.cpp	\
   43.37 +	Mode2.cpp	\
   43.38 +	Mode3.cpp	\
   43.39 +	Mode4.cpp	\
   43.40 +	Mode5.cpp	\
   43.41 +	remote.cpp	\
   43.42 +	RTC.cpp		\
   43.43 +	Sram.cpp	
   43.44 +
   43.45 +
   43.46 +AM_CPPFLAGS = \
   43.47 +	-I$(top_srcdir)/src		\
   43.48 +	-DSDL				\
   43.49 +	-DSYSCONFDIR=\"$(sysconfdir)\"
   43.50 +
   43.51 +AM_CXXFLAGS = -fno-exceptions @SDL_CFLAGS@
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/src/gba/Mode0.cpp	Sun Mar 04 14:33:52 2012 -0600
    44.3 @@ -0,0 +1,633 @@
    44.4 +#include "GBAGfx.h"
    44.5 +#include "GBAGlobals.h"
    44.6 +
    44.7 +void mode0RenderLine()
    44.8 +{
    44.9 +	u16 *palette = (u16 *)paletteRAM;
   44.10 +
   44.11 +	if (DISPCNT & 0x80)
   44.12 +	{
   44.13 +		for (int x = 0; x < 240; x++)
   44.14 +		{
   44.15 +			lineMix[x] = 0x7fff;
   44.16 +		}
   44.17 +		return;
   44.18 +	}
   44.19 +
   44.20 +	if (layerEnable & 0x0100)
   44.21 +	{
   44.22 +		gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
   44.23 +	}
   44.24 +
   44.25 +	if (layerEnable & 0x0200)
   44.26 +	{
   44.27 +		gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
   44.28 +	}
   44.29 +
   44.30 +	if (layerEnable & 0x0400)
   44.31 +	{
   44.32 +		gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2);
   44.33 +	}
   44.34 +
   44.35 +	if (layerEnable & 0x0800)
   44.36 +	{
   44.37 +		gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3);
   44.38 +	}
   44.39 +
   44.40 +	gfxDrawSprites(lineOBJ);
   44.41 +
   44.42 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
   44.43 +
   44.44 +	for (int x = 0; x < 240; x++)
   44.45 +	{
   44.46 +		u32 color = backdrop;
   44.47 +		u8  top   = 0x20;
   44.48 +
   44.49 +		if (line0[x] < color)
   44.50 +		{
   44.51 +			color = line0[x];
   44.52 +			top   = 0x01;
   44.53 +		}
   44.54 +
   44.55 +		if ((u8)(line1[x]>>24) < (u8)(color >> 24))
   44.56 +		{
   44.57 +			color = line1[x];
   44.58 +			top   = 0x02;
   44.59 +		}
   44.60 +
   44.61 +		if ((u8)(line2[x]>>24) < (u8)(color >> 24))
   44.62 +		{
   44.63 +			color = line2[x];
   44.64 +			top   = 0x04;
   44.65 +		}
   44.66 +
   44.67 +		if ((u8)(line3[x]>>24) < (u8)(color >> 24))
   44.68 +		{
   44.69 +			color = line3[x];
   44.70 +			top   = 0x08;
   44.71 +		}
   44.72 +
   44.73 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))
   44.74 +		{
   44.75 +			color = lineOBJ[x];
   44.76 +			top   = 0x10;
   44.77 +		}
   44.78 +
   44.79 +		if ((top & 0x10) && (color & 0x00010000))
   44.80 +		{
   44.81 +			// semi-transparent OBJ
   44.82 +			u32 back = backdrop;
   44.83 +			u8  top2 = 0x20;
   44.84 +
   44.85 +			if ((u8)(line0[x]>>24) < (u8)(back >> 24))
   44.86 +			{
   44.87 +				back = line0[x];
   44.88 +				top2 = 0x01;
   44.89 +			}
   44.90 +
   44.91 +			if ((u8)(line1[x]>>24) < (u8)(back >> 24))
   44.92 +			{
   44.93 +				back = line1[x];
   44.94 +				top2 = 0x02;
   44.95 +			}
   44.96 +
   44.97 +			if ((u8)(line2[x]>>24) < (u8)(back >> 24))
   44.98 +			{
   44.99 +				back = line2[x];
  44.100 +				top2 = 0x04;
  44.101 +			}
  44.102 +
  44.103 +			if ((u8)(line3[x]>>24) < (u8)(back >> 24))
  44.104 +			{
  44.105 +				back = line3[x];
  44.106 +				top2 = 0x08;
  44.107 +			}
  44.108 +
  44.109 +			if (top2 & (BLDMOD>>8))
  44.110 +				color = gfxAlphaBlend(color, back,
  44.111 +				                      coeff[COLEV & 0x1F],
  44.112 +				                      coeff[(COLEV >> 8) & 0x1F]);
  44.113 +			else
  44.114 +			{
  44.115 +				switch ((BLDMOD >> 6) & 3)
  44.116 +				{
  44.117 +				case 2:
  44.118 +					if (BLDMOD & top)
  44.119 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  44.120 +					break;
  44.121 +				case 3:
  44.122 +					if (BLDMOD & top)
  44.123 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  44.124 +					break;
  44.125 +				}
  44.126 +			}
  44.127 +		}
  44.128 +
  44.129 +		lineMix[x] = color;
  44.130 +	}
  44.131 +}
  44.132 +
  44.133 +void mode0RenderLineNoWindow()
  44.134 +{
  44.135 +	u16 *palette = (u16 *)paletteRAM;
  44.136 +
  44.137 +	if (DISPCNT & 0x80)
  44.138 +	{
  44.139 +		for (int x = 0; x < 240; x++)
  44.140 +		{
  44.141 +			lineMix[x] = 0x7fff;
  44.142 +		}
  44.143 +		return;
  44.144 +	}
  44.145 +
  44.146 +	if (layerEnable & 0x0100)
  44.147 +	{
  44.148 +		gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
  44.149 +	}
  44.150 +
  44.151 +	if (layerEnable & 0x0200)
  44.152 +	{
  44.153 +		gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
  44.154 +	}
  44.155 +
  44.156 +	if (layerEnable & 0x0400)
  44.157 +	{
  44.158 +		gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2);
  44.159 +	}
  44.160 +
  44.161 +	if (layerEnable & 0x0800)
  44.162 +	{
  44.163 +		gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3);
  44.164 +	}
  44.165 +
  44.166 +	gfxDrawSprites(lineOBJ);
  44.167 +
  44.168 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
  44.169 +
  44.170 +	int effect = (BLDMOD >> 6) & 3;
  44.171 +
  44.172 +	for (int x = 0; x < 240; x++)
  44.173 +	{
  44.174 +		u32 color = backdrop;
  44.175 +		u8  top   = 0x20;
  44.176 +
  44.177 +		if (line0[x] < color)
  44.178 +		{
  44.179 +			color = line0[x];
  44.180 +			top   = 0x01;
  44.181 +		}
  44.182 +
  44.183 +		if (line1[x] < (color & 0xFF000000))
  44.184 +		{
  44.185 +			color = line1[x];
  44.186 +			top   = 0x02;
  44.187 +		}
  44.188 +
  44.189 +		if (line2[x] < (color & 0xFF000000))
  44.190 +		{
  44.191 +			color = line2[x];
  44.192 +			top   = 0x04;
  44.193 +		}
  44.194 +
  44.195 +		if (line3[x] < (color & 0xFF000000))
  44.196 +		{
  44.197 +			color = line3[x];
  44.198 +			top   = 0x08;
  44.199 +		}
  44.200 +
  44.201 +		if (lineOBJ[x] < (color & 0xFF000000))
  44.202 +		{
  44.203 +			color = lineOBJ[x];
  44.204 +			top   = 0x10;
  44.205 +		}
  44.206 +
  44.207 +		if (!(color & 0x00010000))
  44.208 +		{
  44.209 +			switch (effect)
  44.210 +			{
  44.211 +			case 0:
  44.212 +				break;
  44.213 +			case 1:
  44.214 +			{
  44.215 +				if (top & BLDMOD)
  44.216 +				{
  44.217 +					u32 back = backdrop;
  44.218 +					u8  top2 = 0x20;
  44.219 +					if (line0[x] < back)
  44.220 +					{
  44.221 +						if (top != 0x01)
  44.222 +						{
  44.223 +							back = line0[x];
  44.224 +							top2 = 0x01;
  44.225 +						}
  44.226 +					}
  44.227 +
  44.228 +					if (line1[x] < (back & 0xFF000000))
  44.229 +					{
  44.230 +						if (top != 0x02)
  44.231 +						{
  44.232 +							back = line1[x];
  44.233 +							top2 = 0x02;
  44.234 +						}
  44.235 +					}
  44.236 +
  44.237 +					if (line2[x] < (back & 0xFF000000))
  44.238 +					{
  44.239 +						if (top != 0x04)
  44.240 +						{
  44.241 +							back = line2[x];
  44.242 +							top2 = 0x04;
  44.243 +						}
  44.244 +					}
  44.245 +
  44.246 +					if (line3[x] < (back & 0xFF000000))
  44.247 +					{
  44.248 +						if (top != 0x08)
  44.249 +						{
  44.250 +							back = line3[x];
  44.251 +							top2 = 0x08;
  44.252 +						}
  44.253 +					}
  44.254 +
  44.255 +					if (lineOBJ[x] < (back & 0xFF000000))
  44.256 +					{
  44.257 +						if (top != 0x10)
  44.258 +						{
  44.259 +							back = lineOBJ[x];
  44.260 +							top2 = 0x10;
  44.261 +						}
  44.262 +					}
  44.263 +
  44.264 +					if (top2 & (BLDMOD>>8))
  44.265 +						color = gfxAlphaBlend(color, back,
  44.266 +						                      coeff[COLEV & 0x1F],
  44.267 +						                      coeff[(COLEV >> 8) & 0x1F]);
  44.268 +				}
  44.269 +				break;
  44.270 +			}
  44.271 +			case 2:
  44.272 +				if (BLDMOD & top)
  44.273 +					color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  44.274 +				break;
  44.275 +			case 3:
  44.276 +				if (BLDMOD & top)
  44.277 +					color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  44.278 +				break;
  44.279 +			}
  44.280 +		}
  44.281 +		else
  44.282 +		{
  44.283 +			// semi-transparent OBJ
  44.284 +			u32 back = backdrop;
  44.285 +			u8  top2 = 0x20;
  44.286 +
  44.287 +			if (line0[x] < back)
  44.288 +			{
  44.289 +				back = line0[x];
  44.290 +				top2 = 0x01;
  44.291 +			}
  44.292 +
  44.293 +			if (line1[x] < (back & 0xFF000000))
  44.294 +			{
  44.295 +				back = line1[x];
  44.296 +				top2 = 0x02;
  44.297 +			}
  44.298 +
  44.299 +			if (line2[x] < (back & 0xFF000000))
  44.300 +			{
  44.301 +				back = line2[x];
  44.302 +				top2 = 0x04;
  44.303 +			}
  44.304 +
  44.305 +			if (line3[x] < (back & 0xFF000000))
  44.306 +			{
  44.307 +				back = line3[x];
  44.308 +				top2 = 0x08;
  44.309 +			}
  44.310 +
  44.311 +			if (top2 & (BLDMOD>>8))
  44.312 +				color = gfxAlphaBlend(color, back,
  44.313 +				                      coeff[COLEV & 0x1F],
  44.314 +				                      coeff[(COLEV >> 8) & 0x1F]);
  44.315 +			else
  44.316 +			{
  44.317 +				switch ((BLDMOD >> 6) & 3)
  44.318 +				{
  44.319 +				case 2:
  44.320 +					if (BLDMOD & top)
  44.321 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  44.322 +					break;
  44.323 +				case 3:
  44.324 +					if (BLDMOD & top)
  44.325 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  44.326 +					break;
  44.327 +				}
  44.328 +			}
  44.329 +		}
  44.330 +
  44.331 +		lineMix[x] = color;
  44.332 +	}
  44.333 +}
  44.334 +
  44.335 +void mode0RenderLineAll()
  44.336 +{
  44.337 +	u16 *palette = (u16 *)paletteRAM;
  44.338 +
  44.339 +	if (DISPCNT & 0x80)
  44.340 +	{
  44.341 +		for (int x = 0; x < 240; x++)
  44.342 +		{
  44.343 +			lineMix[x] = 0x7fff;
  44.344 +		}
  44.345 +		return;
  44.346 +	}
  44.347 +
  44.348 +	bool inWindow0 = false;
  44.349 +	bool inWindow1 = false;
  44.350 +
  44.351 +	if (layerEnable & 0x2000)
  44.352 +	{
  44.353 +		u8 v0 = WIN0V >> 8;
  44.354 +		u8 v1 = WIN0V & 255;
  44.355 +		inWindow0 = ((v0 == v1) && (v0 >= 0xe8));
  44.356 +		if (v1 >= v0)
  44.357 +			inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1);
  44.358 +		else
  44.359 +			inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1);
  44.360 +	}
  44.361 +	if (layerEnable & 0x4000)
  44.362 +	{
  44.363 +		u8 v0 = WIN1V >> 8;
  44.364 +		u8 v1 = WIN1V & 255;
  44.365 +		inWindow1 = ((v0 == v1) && (v0 >= 0xe8));
  44.366 +		if (v1 >= v0)
  44.367 +			inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1);
  44.368 +		else
  44.369 +			inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1);
  44.370 +	}
  44.371 +
  44.372 +	if ((layerEnable & 0x0100))
  44.373 +	{
  44.374 +		gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
  44.375 +	}
  44.376 +
  44.377 +	if ((layerEnable & 0x0200))
  44.378 +	{
  44.379 +		gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
  44.380 +	}
  44.381 +
  44.382 +	if ((layerEnable & 0x0400))
  44.383 +	{
  44.384 +		gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2);
  44.385 +	}
  44.386 +
  44.387 +	if ((layerEnable & 0x0800))
  44.388 +	{
  44.389 +		gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3);
  44.390 +	}
  44.391 +
  44.392 +	gfxDrawSprites(lineOBJ);
  44.393 +	gfxDrawOBJWin(lineOBJWin);
  44.394 +
  44.395 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
  44.396 +
  44.397 +	u8 inWin0Mask = WININ & 0xFF;
  44.398 +	u8 inWin1Mask = WININ >> 8;
  44.399 +	u8 outMask    = WINOUT & 0xFF;
  44.400 +
  44.401 +	for (int x = 0; x < 240; x++)
  44.402 +	{
  44.403 +		u32 color = backdrop;
  44.404 +		u8  top   = 0x20;
  44.405 +		u8  mask  = outMask;
  44.406 +
  44.407 +		if (!(lineOBJWin[x] & 0x80000000))
  44.408 +		{
  44.409 +			mask = WINOUT >> 8;
  44.410 +		}
  44.411 +
  44.412 +		if (inWindow1)
  44.413 +		{
  44.414 +			if (gfxInWin1[x])
  44.415 +				mask = inWin1Mask;
  44.416 +		}
  44.417 +
  44.418 +		if (inWindow0)
  44.419 +		{
  44.420 +			if (gfxInWin0[x])
  44.421 +			{
  44.422 +				mask = inWin0Mask;
  44.423 +			}
  44.424 +		}
  44.425 +
  44.426 +		if ((mask & 1) && (line0[x] < color))
  44.427 +		{
  44.428 +			color = line0[x];
  44.429 +			top   = 0x01;
  44.430 +		}
  44.431 +
  44.432 +		if ((mask & 2) && ((u8)(line1[x]>>24) < (u8)(color >> 24)))
  44.433 +		{
  44.434 +			color = line1[x];
  44.435 +			top   = 0x02;
  44.436 +		}
  44.437 +
  44.438 +		if ((mask & 4) && ((u8)(line2[x]>>24) < (u8)(color >> 24)))
  44.439 +		{
  44.440 +			color = line2[x];
  44.441 +			top   = 0x04;
  44.442 +		}
  44.443 +
  44.444 +		if ((mask & 8) && ((u8)(line3[x]>>24) < (u8)(color >> 24)))
  44.445 +		{
  44.446 +			color = line3[x];
  44.447 +			top   = 0x08;
  44.448 +		}
  44.449 +
  44.450 +		if ((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)))
  44.451 +		{
  44.452 +			color = lineOBJ[x];
  44.453 +			top   = 0x10;
  44.454 +		}
  44.455 +
  44.456 +		// special FX on in the window
  44.457 +		if (mask & 32)
  44.458 +		{
  44.459 +			if (!(color & 0x00010000))
  44.460 +			{
  44.461 +				switch ((BLDMOD >> 6) & 3)
  44.462 +				{
  44.463 +				case 0:
  44.464 +					break;
  44.465 +				case 1:
  44.466 +				{
  44.467 +					if (top & BLDMOD)
  44.468 +					{
  44.469 +						u32 back = backdrop;
  44.470 +						u8  top2 = 0x20;
  44.471 +						if ((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24))
  44.472 +						{
  44.473 +							if (top != 0x01)
  44.474 +							{
  44.475 +								back = line0[x];
  44.476 +								top2 = 0x01;
  44.477 +							}
  44.478 +						}
  44.479 +
  44.480 +						if ((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24))
  44.481 +						{
  44.482 +							if (top != 0x02)
  44.483 +							{
  44.484 +								back = line1[x];
  44.485 +								top2 = 0x02;
  44.486 +							}
  44.487 +						}
  44.488 +
  44.489 +						if ((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24))
  44.490 +						{
  44.491 +							if (top != 0x04)
  44.492 +							{
  44.493 +								back = line2[x];
  44.494 +								top2 = 0x04;
  44.495 +							}
  44.496 +						}
  44.497 +
  44.498 +						if ((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24))
  44.499 +						{
  44.500 +							if (top != 0x08)
  44.501 +							{
  44.502 +								back = line3[x];
  44.503 +								top2 = 0x08;
  44.504 +							}
  44.505 +						}
  44.506 +
  44.507 +						if ((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  44.508 +						{
  44.509 +							if (top != 0x10)
  44.510 +							{
  44.511 +								back = lineOBJ[x];
  44.512 +								top2 = 0x10;
  44.513 +							}
  44.514 +						}
  44.515 +
  44.516 +						if (top2 & (BLDMOD>>8))
  44.517 +							color = gfxAlphaBlend(color, back,
  44.518 +							                      coeff[COLEV & 0x1F],
  44.519 +							                      coeff[(COLEV >> 8) & 0x1F]);
  44.520 +					}
  44.521 +					break;
  44.522 +				}
  44.523 +				case 2:
  44.524 +					if (BLDMOD & top)
  44.525 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  44.526 +					break;
  44.527 +				case 3:
  44.528 +					if (BLDMOD & top)
  44.529 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  44.530 +					break;
  44.531 +				}
  44.532 +			}
  44.533 +			else
  44.534 +			{
  44.535 +				// semi-transparent OBJ
  44.536 +				u32 back = backdrop;
  44.537 +				u8  top2 = 0x20;
  44.538 +
  44.539 +				if ((mask & 1) && ((u8)(line0[x]>>24) < (u8)(back >> 24)))
  44.540 +				{
  44.541 +					back = line0[x];
  44.542 +					top2 = 0x01;
  44.543 +				}
  44.544 +
  44.545 +				if ((mask & 2) && ((u8)(line1[x]>>24) < (u8)(back >> 24)))
  44.546 +				{
  44.547 +					back = line1[x];
  44.548 +					top2 = 0x02;
  44.549 +				}
  44.550 +
  44.551 +				if ((mask & 4) && ((u8)(line2[x]>>24) < (u8)(back >> 24)))
  44.552 +				{
  44.553 +					back = line2[x];
  44.554 +					top2 = 0x04;
  44.555 +				}
  44.556 +
  44.557 +				if ((mask & 8) && ((u8)(line3[x]>>24) < (u8)(back >> 24)))
  44.558 +				{
  44.559 +					back = line3[x];
  44.560 +					top2 = 0x08;
  44.561 +				}
  44.562 +
  44.563 +				if (top2 & (BLDMOD>>8))
  44.564 +					color = gfxAlphaBlend(color, back,
  44.565 +					                      coeff[COLEV & 0x1F],
  44.566 +					                      coeff[(COLEV >> 8) & 0x1F]);
  44.567 +				else
  44.568 +				{
  44.569 +					switch ((BLDMOD >> 6) & 3)
  44.570 +					{
  44.571 +					case 2:
  44.572 +						if (BLDMOD & top)
  44.573 +							color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  44.574 +						break;
  44.575 +					case 3:
  44.576 +						if (BLDMOD & top)
  44.577 +							color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  44.578 +						break;
  44.579 +					}
  44.580 +				}
  44.581 +			}
  44.582 +		}
  44.583 +		else if (color & 0x00010000)
  44.584 +		{
  44.585 +			// semi-transparent OBJ
  44.586 +			u32 back = backdrop;
  44.587 +			u8  top2 = 0x20;
  44.588 +
  44.589 +			if ((mask & 1) && ((u8)(line0[x]>>24) < (u8)(back >> 24)))
  44.590 +			{
  44.591 +				back = line0[x];
  44.592 +				top2 = 0x01;
  44.593 +			}
  44.594 +
  44.595 +			if ((mask & 2) && ((u8)(line1[x]>>24) < (u8)(back >> 24)))
  44.596 +			{
  44.597 +				back = line1[x];
  44.598 +				top2 = 0x02;
  44.599 +			}
  44.600 +
  44.601 +			if ((mask & 4) && ((u8)(line2[x]>>24) < (u8)(back >> 24)))
  44.602 +			{
  44.603 +				back = line2[x];
  44.604 +				top2 = 0x04;
  44.605 +			}
  44.606 +
  44.607 +			if ((mask & 8) && ((u8)(line3[x]>>24) < (u8)(back >> 24)))
  44.608 +			{
  44.609 +				back = line3[x];
  44.610 +				top2 = 0x08;
  44.611 +			}
  44.612 +
  44.613 +			if (top2 & (BLDMOD>>8))
  44.614 +				color = gfxAlphaBlend(color, back,
  44.615 +				                      coeff[COLEV & 0x1F],
  44.616 +				                      coeff[(COLEV >> 8) & 0x1F]);
  44.617 +			else
  44.618 +			{
  44.619 +				switch ((BLDMOD >> 6) & 3)
  44.620 +				{
  44.621 +				case 2:
  44.622 +					if (BLDMOD & top)
  44.623 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  44.624 +					break;
  44.625 +				case 3:
  44.626 +					if (BLDMOD & top)
  44.627 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  44.628 +					break;
  44.629 +				}
  44.630 +			}
  44.631 +		}
  44.632 +
  44.633 +		lineMix[x] = color;
  44.634 +	}
  44.635 +}
  44.636 +
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/src/gba/Mode1.cpp	Sun Mar 04 14:33:52 2012 -0600
    45.3 @@ -0,0 +1,580 @@
    45.4 +#include "GBAGfx.h"
    45.5 +#include "GBAGlobals.h"
    45.6 +
    45.7 +void mode1RenderLine()
    45.8 +{
    45.9 +	u16 *palette = (u16 *)paletteRAM;
   45.10 +
   45.11 +	if (DISPCNT & 0x80)
   45.12 +	{
   45.13 +		for (int x = 0; x < 240; x++)
   45.14 +		{
   45.15 +			lineMix[x] = 0x7fff;
   45.16 +		}
   45.17 +		gfxLastVCOUNT = VCOUNT;
   45.18 +		return;
   45.19 +	}
   45.20 +
   45.21 +	if (layerEnable & 0x0100)
   45.22 +	{
   45.23 +		gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
   45.24 +	}
   45.25 +
   45.26 +	if (layerEnable & 0x0200)
   45.27 +	{
   45.28 +		gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
   45.29 +	}
   45.30 +
   45.31 +	if (layerEnable & 0x0400)
   45.32 +	{
   45.33 +		int changed = gfxBG2Changed;
   45.34 +		if (gfxLastVCOUNT > VCOUNT)
   45.35 +			changed = 3;
   45.36 +		gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
   45.37 +		                 BG2PA, BG2PB, BG2PC, BG2PD,
   45.38 +		                 gfxBG2X, gfxBG2Y, changed, line2);
   45.39 +	}
   45.40 +
   45.41 +	gfxDrawSprites(lineOBJ);
   45.42 +
   45.43 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
   45.44 +
   45.45 +	for (int x = 0; x < 240; x++)
   45.46 +	{
   45.47 +		u32 color = backdrop;
   45.48 +		u8  top   = 0x20;
   45.49 +
   45.50 +		if (line0[x] < color)
   45.51 +		{
   45.52 +			color = line0[x];
   45.53 +			top   = 0x01;
   45.54 +		}
   45.55 +
   45.56 +		if ((u8)(line1[x]>>24) < (u8)(color >> 24))
   45.57 +		{
   45.58 +			color = line1[x];
   45.59 +			top   = 0x02;
   45.60 +		}
   45.61 +
   45.62 +		if ((u8)(line2[x]>>24) < (u8)(color >> 24))
   45.63 +		{
   45.64 +			color = line2[x];
   45.65 +			top   = 0x04;
   45.66 +		}
   45.67 +
   45.68 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))
   45.69 +		{
   45.70 +			color = lineOBJ[x];
   45.71 +			top   = 0x10;
   45.72 +		}
   45.73 +
   45.74 +		if ((top & 0x10) && (color & 0x00010000))
   45.75 +		{
   45.76 +			// semi-transparent OBJ
   45.77 +			u32 back = backdrop;
   45.78 +			u8  top2 = 0x20;
   45.79 +
   45.80 +			if ((u8)(line0[x]>>24) < (u8)(back >> 24))
   45.81 +			{
   45.82 +				back = line0[x];
   45.83 +				top2 = 0x01;
   45.84 +			}
   45.85 +
   45.86 +			if ((u8)(line1[x]>>24) < (u8)(back >> 24))
   45.87 +			{
   45.88 +				back = line1[x];
   45.89 +				top2 = 0x02;
   45.90 +			}
   45.91 +
   45.92 +			if ((u8)(line2[x]>>24) < (u8)(back >> 24))
   45.93 +			{
   45.94 +				back = line2[x];
   45.95 +				top2 = 0x04;
   45.96 +			}
   45.97 +
   45.98 +			if (top2 & (BLDMOD>>8))
   45.99 +				color = gfxAlphaBlend(color, back,
  45.100 +				                      coeff[COLEV & 0x1F],
  45.101 +				                      coeff[(COLEV >> 8) & 0x1F]);
  45.102 +			else
  45.103 +			{
  45.104 +				switch ((BLDMOD >> 6) & 3)
  45.105 +				{
  45.106 +				case 2:
  45.107 +					if (BLDMOD & top)
  45.108 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  45.109 +					break;
  45.110 +				case 3:
  45.111 +					if (BLDMOD & top)
  45.112 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  45.113 +					break;
  45.114 +				}
  45.115 +			}
  45.116 +		}
  45.117 +
  45.118 +		lineMix[x] = color;
  45.119 +	}
  45.120 +	gfxBG2Changed = 0;
  45.121 +	gfxLastVCOUNT = VCOUNT;
  45.122 +}
  45.123 +
  45.124 +void mode1RenderLineNoWindow()
  45.125 +{
  45.126 +	u16 *palette = (u16 *)paletteRAM;
  45.127 +
  45.128 +	if (DISPCNT & 0x80)
  45.129 +	{
  45.130 +		for (int x = 0; x < 240; x++)
  45.131 +		{
  45.132 +			lineMix[x] = 0x7fff;
  45.133 +		}
  45.134 +		gfxLastVCOUNT = VCOUNT;
  45.135 +		return;
  45.136 +	}
  45.137 +
  45.138 +	if (layerEnable & 0x0100)
  45.139 +	{
  45.140 +		gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
  45.141 +	}
  45.142 +
  45.143 +	if (layerEnable & 0x0200)
  45.144 +	{
  45.145 +		gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
  45.146 +	}
  45.147 +
  45.148 +	if (layerEnable & 0x0400)
  45.149 +	{
  45.150 +		int changed = gfxBG2Changed;
  45.151 +		if (gfxLastVCOUNT > VCOUNT)
  45.152 +			changed = 3;
  45.153 +		gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
  45.154 +		                 BG2PA, BG2PB, BG2PC, BG2PD,
  45.155 +		                 gfxBG2X, gfxBG2Y, changed, line2);
  45.156 +	}
  45.157 +
  45.158 +	gfxDrawSprites(lineOBJ);
  45.159 +
  45.160 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
  45.161 +
  45.162 +	for (int x = 0; x < 240; x++)
  45.163 +	{
  45.164 +		u32 color = backdrop;
  45.165 +		u8  top   = 0x20;
  45.166 +
  45.167 +		if (line0[x] < color)
  45.168 +		{
  45.169 +			color = line0[x];
  45.170 +			top   = 0x01;
  45.171 +		}
  45.172 +
  45.173 +		if ((u8)(line1[x]>>24) < (u8)(color >> 24))
  45.174 +		{
  45.175 +			color = line1[x];
  45.176 +			top   = 0x02;
  45.177 +		}
  45.178 +
  45.179 +		if ((u8)(line2[x]>>24) < (u8)(color >> 24))
  45.180 +		{
  45.181 +			color = line2[x];
  45.182 +			top   = 0x04;
  45.183 +		}
  45.184 +
  45.185 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))
  45.186 +		{
  45.187 +			color = lineOBJ[x];
  45.188 +			top   = 0x10;
  45.189 +		}
  45.190 +
  45.191 +		if (!(color & 0x00010000))
  45.192 +		{
  45.193 +			switch ((BLDMOD >> 6) & 3)
  45.194 +			{
  45.195 +			case 0:
  45.196 +				break;
  45.197 +			case 1:
  45.198 +			{
  45.199 +				if (top & BLDMOD)
  45.200 +				{
  45.201 +					u32 back = backdrop;
  45.202 +					u8  top2 = 0x20;
  45.203 +					if ((u8)(line0[x]>>24) < (u8)(back >> 24))
  45.204 +					{
  45.205 +						if (top != 0x01)
  45.206 +						{
  45.207 +							back = line0[x];
  45.208 +							top2 = 0x01;
  45.209 +						}
  45.210 +					}
  45.211 +
  45.212 +					if ((u8)(line1[x]>>24) < (u8)(back >> 24))
  45.213 +					{
  45.214 +						if (top != 0x02)
  45.215 +						{
  45.216 +							back = line1[x];
  45.217 +							top2 = 0x02;
  45.218 +						}
  45.219 +					}
  45.220 +
  45.221 +					if ((u8)(line2[x]>>24) < (u8)(back >> 24))
  45.222 +					{
  45.223 +						if (top != 0x04)
  45.224 +						{
  45.225 +							back = line2[x];
  45.226 +							top2 = 0x04;
  45.227 +						}
  45.228 +					}
  45.229 +
  45.230 +					if ((u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  45.231 +					{
  45.232 +						if (top != 0x10)
  45.233 +						{
  45.234 +							back = lineOBJ[x];
  45.235 +							top2 = 0x10;
  45.236 +						}
  45.237 +					}
  45.238 +
  45.239 +					if (top2 & (BLDMOD>>8))
  45.240 +						color = gfxAlphaBlend(color, back,
  45.241 +						                      coeff[COLEV & 0x1F],
  45.242 +						                      coeff[(COLEV >> 8) & 0x1F]);
  45.243 +				}
  45.244 +				break;
  45.245 +			}
  45.246 +			case 2:
  45.247 +				if (BLDMOD & top)
  45.248 +					color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  45.249 +				break;
  45.250 +			case 3:
  45.251 +				if (BLDMOD & top)
  45.252 +					color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  45.253 +				break;
  45.254 +			}
  45.255 +		}
  45.256 +		else
  45.257 +		{
  45.258 +			// semi-transparent OBJ
  45.259 +			u32 back = backdrop;
  45.260 +			u8  top2 = 0x20;
  45.261 +
  45.262 +			if ((u8)(line0[x]>>24) < (u8)(back >> 24))
  45.263 +			{
  45.264 +				back = line0[x];
  45.265 +				top2 = 0x01;
  45.266 +			}
  45.267 +
  45.268 +			if ((u8)(line1[x]>>24) < (u8)(back >> 24))
  45.269 +			{
  45.270 +				back = line1[x];
  45.271 +				top2 = 0x02;
  45.272 +			}
  45.273 +
  45.274 +			if ((u8)(line2[x]>>24) < (u8)(back >> 24))
  45.275 +			{
  45.276 +				back = line2[x];
  45.277 +				top2 = 0x04;
  45.278 +			}
  45.279 +
  45.280 +			if (top2 & (BLDMOD>>8))
  45.281 +				color = gfxAlphaBlend(color, back,
  45.282 +				                      coeff[COLEV & 0x1F],
  45.283 +				                      coeff[(COLEV >> 8) & 0x1F]);
  45.284 +			else
  45.285 +			{
  45.286 +				switch ((BLDMOD >> 6) & 3)
  45.287 +				{
  45.288 +				case 2:
  45.289 +					if (BLDMOD & top)
  45.290 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  45.291 +					break;
  45.292 +				case 3:
  45.293 +					if (BLDMOD & top)
  45.294 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  45.295 +					break;
  45.296 +				}
  45.297 +			}
  45.298 +		}
  45.299 +
  45.300 +		lineMix[x] = color;
  45.301 +	}
  45.302 +	gfxBG2Changed = 0;
  45.303 +	gfxLastVCOUNT = VCOUNT;
  45.304 +}
  45.305 +
  45.306 +void mode1RenderLineAll()
  45.307 +{
  45.308 +	u16 *palette = (u16 *)paletteRAM;
  45.309 +
  45.310 +	if (DISPCNT & 0x80)
  45.311 +	{
  45.312 +		for (int x = 0; x < 240; x++)
  45.313 +		{
  45.314 +			lineMix[x] = 0x7fff;
  45.315 +		}
  45.316 +		gfxLastVCOUNT = VCOUNT;
  45.317 +		return;
  45.318 +	}
  45.319 +
  45.320 +	bool inWindow0 = false;
  45.321 +	bool inWindow1 = false;
  45.322 +
  45.323 +	if (layerEnable & 0x2000)
  45.324 +	{
  45.325 +		u8 v0 = WIN0V >> 8;
  45.326 +		u8 v1 = WIN0V & 255;
  45.327 +		inWindow0 = ((v0 == v1) && (v0 >= 0xe8));
  45.328 +		if (v1 >= v0)
  45.329 +			inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1);
  45.330 +		else
  45.331 +			inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1);
  45.332 +	}
  45.333 +	if (layerEnable & 0x4000)
  45.334 +	{
  45.335 +		u8 v0 = WIN1V >> 8;
  45.336 +		u8 v1 = WIN1V & 255;
  45.337 +		inWindow1 = ((v0 == v1) && (v0 >= 0xe8));
  45.338 +		if (v1 >= v0)
  45.339 +			inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1);
  45.340 +		else
  45.341 +			inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1);
  45.342 +	}
  45.343 +
  45.344 +	if (layerEnable & 0x0100)
  45.345 +	{
  45.346 +		gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
  45.347 +	}
  45.348 +
  45.349 +	if (layerEnable & 0x0200)
  45.350 +	{
  45.351 +		gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
  45.352 +	}
  45.353 +
  45.354 +	if (layerEnable & 0x0400)
  45.355 +	{
  45.356 +		int changed = gfxBG2Changed;
  45.357 +		if (gfxLastVCOUNT > VCOUNT)
  45.358 +			changed = 3;
  45.359 +		gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
  45.360 +		                 BG2PA, BG2PB, BG2PC, BG2PD,
  45.361 +		                 gfxBG2X, gfxBG2Y, changed, line2);
  45.362 +	}
  45.363 +
  45.364 +	gfxDrawSprites(lineOBJ);
  45.365 +	gfxDrawOBJWin(lineOBJWin);
  45.366 +
  45.367 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
  45.368 +
  45.369 +	u8 inWin0Mask = WININ & 0xFF;
  45.370 +	u8 inWin1Mask = WININ >> 8;
  45.371 +	u8 outMask    = WINOUT & 0xFF;
  45.372 +
  45.373 +	for (int x = 0; x < 240; x++)
  45.374 +	{
  45.375 +		u32 color = backdrop;
  45.376 +		u8  top   = 0x20;
  45.377 +		u8  mask  = outMask;
  45.378 +
  45.379 +		if (!(lineOBJWin[x] & 0x80000000))
  45.380 +		{
  45.381 +			mask = WINOUT >> 8;
  45.382 +		}
  45.383 +
  45.384 +		if (inWindow1)
  45.385 +		{
  45.386 +			if (gfxInWin1[x])
  45.387 +				mask = inWin1Mask;
  45.388 +		}
  45.389 +
  45.390 +		if (inWindow0)
  45.391 +		{
  45.392 +			if (gfxInWin0[x])
  45.393 +			{
  45.394 +				mask = inWin0Mask;
  45.395 +			}
  45.396 +		}
  45.397 +
  45.398 +		if (line0[x] < color && (mask & 1))
  45.399 +		{
  45.400 +			color = line0[x];
  45.401 +			top   = 0x01;
  45.402 +		}
  45.403 +
  45.404 +		if ((u8)(line1[x]>>24) < (u8)(color >> 24) && (mask & 2))
  45.405 +		{
  45.406 +			color = line1[x];
  45.407 +			top   = 0x02;
  45.408 +		}
  45.409 +
  45.410 +		if ((u8)(line2[x]>>24) < (u8)(color >> 24) && (mask & 4))
  45.411 +		{
  45.412 +			color = line2[x];
  45.413 +			top   = 0x04;
  45.414 +		}
  45.415 +
  45.416 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16))
  45.417 +		{
  45.418 +			color = lineOBJ[x];
  45.419 +			top   = 0x10;
  45.420 +		}
  45.421 +
  45.422 +		// special FX on the window
  45.423 +		if (mask & 32)
  45.424 +		{
  45.425 +			if (!(color & 0x00010000))
  45.426 +			{
  45.427 +				switch ((BLDMOD >> 6) & 3)
  45.428 +				{
  45.429 +				case 0:
  45.430 +					break;
  45.431 +				case 1:
  45.432 +				{
  45.433 +					if (top & BLDMOD)
  45.434 +					{
  45.435 +						u32 back = backdrop;
  45.436 +						u8  top2 = 0x20;
  45.437 +						if ((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24))
  45.438 +						{
  45.439 +							if (top != 0x01)
  45.440 +							{
  45.441 +								back = line0[x];
  45.442 +								top2 = 0x01;
  45.443 +							}
  45.444 +						}
  45.445 +
  45.446 +						if ((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24))
  45.447 +						{
  45.448 +							if (top != 0x02)
  45.449 +							{
  45.450 +								back = line1[x];
  45.451 +								top2 = 0x02;
  45.452 +							}
  45.453 +						}
  45.454 +
  45.455 +						if ((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24))
  45.456 +						{
  45.457 +							if (top != 0x04)
  45.458 +							{
  45.459 +								back = line2[x];
  45.460 +								top2 = 0x04;
  45.461 +							}
  45.462 +						}
  45.463 +
  45.464 +						if ((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  45.465 +						{
  45.466 +							if (top != 0x10)
  45.467 +							{
  45.468 +								back = lineOBJ[x];
  45.469 +								top2 = 0x10;
  45.470 +							}
  45.471 +						}
  45.472 +
  45.473 +						if (top2 & (BLDMOD>>8))
  45.474 +							color = gfxAlphaBlend(color, back,
  45.475 +							                      coeff[COLEV & 0x1F],
  45.476 +							                      coeff[(COLEV >> 8) & 0x1F]);
  45.477 +					}
  45.478 +					break;
  45.479 +				}
  45.480 +				case 2:
  45.481 +					if (BLDMOD & top)
  45.482 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  45.483 +					break;
  45.484 +				case 3:
  45.485 +					if (BLDMOD & top)
  45.486 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  45.487 +					break;
  45.488 +				}
  45.489 +			}
  45.490 +			else
  45.491 +			{
  45.492 +				// semi-transparent OBJ
  45.493 +				u32 back = backdrop;
  45.494 +				u8  top2 = 0x20;
  45.495 +
  45.496 +				if ((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24))
  45.497 +				{
  45.498 +					back = line0[x];
  45.499 +					top2 = 0x01;
  45.500 +				}
  45.501 +
  45.502 +				if ((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24))
  45.503 +				{
  45.504 +					back = line1[x];
  45.505 +					top2 = 0x02;
  45.506 +				}
  45.507 +
  45.508 +				if ((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24))
  45.509 +				{
  45.510 +					back = line2[x];
  45.511 +					top2 = 0x04;
  45.512 +				}
  45.513 +
  45.514 +				if (top2 & (BLDMOD>>8))
  45.515 +					color = gfxAlphaBlend(color, back,
  45.516 +					                      coeff[COLEV & 0x1F],
  45.517 +					                      coeff[(COLEV >> 8) & 0x1F]);
  45.518 +				else
  45.519 +				{
  45.520 +					switch ((BLDMOD >> 6) & 3)
  45.521 +					{
  45.522 +					case 2:
  45.523 +						if (BLDMOD & top)
  45.524 +							color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  45.525 +						break;
  45.526 +					case 3:
  45.527 +						if (BLDMOD & top)
  45.528 +							color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  45.529 +						break;
  45.530 +					}
  45.531 +				}
  45.532 +			}
  45.533 +		}
  45.534 +		else if (color & 0x00010000)
  45.535 +		{
  45.536 +			// semi-transparent OBJ
  45.537 +			u32 back = backdrop;
  45.538 +			u8  top2 = 0x20;
  45.539 +
  45.540 +			if ((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24))
  45.541 +			{
  45.542 +				back = line0[x];
  45.543 +				top2 = 0x01;
  45.544 +			}
  45.545 +
  45.546 +			if ((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24))
  45.547 +			{
  45.548 +				back = line1[x];
  45.549 +				top2 = 0x02;
  45.550 +			}
  45.551 +
  45.552 +			if ((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24))
  45.553 +			{
  45.554 +				back = line2[x];
  45.555 +				top2 = 0x04;
  45.556 +			}
  45.557 +
  45.558 +			if (top2 & (BLDMOD>>8))
  45.559 +				color = gfxAlphaBlend(color, back,
  45.560 +				                      coeff[COLEV & 0x1F],
  45.561 +				                      coeff[(COLEV >> 8) & 0x1F]);
  45.562 +			else
  45.563 +			{
  45.564 +				switch ((BLDMOD >> 6) & 3)
  45.565 +				{
  45.566 +				case 2:
  45.567 +					if (BLDMOD & top)
  45.568 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  45.569 +					break;
  45.570 +				case 3:
  45.571 +					if (BLDMOD & top)
  45.572 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  45.573 +					break;
  45.574 +				}
  45.575 +			}
  45.576 +		}
  45.577 +
  45.578 +		lineMix[x] = color;
  45.579 +	}
  45.580 +	gfxBG2Changed = 0;
  45.581 +	gfxLastVCOUNT = VCOUNT;
  45.582 +}
  45.583 +
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/src/gba/Mode2.cpp	Sun Mar 04 14:33:52 2012 -0600
    46.3 @@ -0,0 +1,530 @@
    46.4 +#include "GBAGfx.h"
    46.5 +#include "GBAGlobals.h"
    46.6 +
    46.7 +void mode2RenderLine()
    46.8 +{
    46.9 +	u16 *palette = (u16 *)paletteRAM;
   46.10 +
   46.11 +	if (DISPCNT & 0x80)
   46.12 +	{
   46.13 +		for (int x = 0; x < 240; x++)
   46.14 +		{
   46.15 +			lineMix[x] = 0x7fff;
   46.16 +		}
   46.17 +		gfxLastVCOUNT = VCOUNT;
   46.18 +		return;
   46.19 +	}
   46.20 +
   46.21 +	if (layerEnable & 0x0400)
   46.22 +	{
   46.23 +		int changed = gfxBG2Changed;
   46.24 +		if (gfxLastVCOUNT > VCOUNT)
   46.25 +			changed = 3;
   46.26 +
   46.27 +		gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
   46.28 +		                 BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y,
   46.29 +		                 changed, line2);
   46.30 +	}
   46.31 +
   46.32 +	if (layerEnable & 0x0800)
   46.33 +	{
   46.34 +		int changed = gfxBG3Changed;
   46.35 +		if (gfxLastVCOUNT > VCOUNT)
   46.36 +			changed = 3;
   46.37 +
   46.38 +		gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H,
   46.39 +		                 BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y,
   46.40 +		                 changed, line3);
   46.41 +	}
   46.42 +
   46.43 +	gfxDrawSprites(lineOBJ);
   46.44 +
   46.45 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
   46.46 +
   46.47 +	for (int x = 0; x < 240; x++)
   46.48 +	{
   46.49 +		u32 color = backdrop;
   46.50 +		u8  top   = 0x20;
   46.51 +
   46.52 +		if ((u8)(line2[x]>>24) < (u8)(color >> 24))
   46.53 +		{
   46.54 +			color = line2[x];
   46.55 +			top   = 0x04;
   46.56 +		}
   46.57 +
   46.58 +		if ((u8)(line3[x]>>24) < (u8)(color >> 24))
   46.59 +		{
   46.60 +			color = line3[x];
   46.61 +			top   = 0x08;
   46.62 +		}
   46.63 +
   46.64 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))
   46.65 +		{
   46.66 +			color = lineOBJ[x];
   46.67 +			top   = 0x10;
   46.68 +		}
   46.69 +
   46.70 +		if ((top & 0x10) && (color & 0x00010000))
   46.71 +		{
   46.72 +			// semi-transparent OBJ
   46.73 +			u32 back = backdrop;
   46.74 +			u8  top2 = 0x20;
   46.75 +
   46.76 +			if ((u8)(line2[x]>>24) < (u8)(back >> 24))
   46.77 +			{
   46.78 +				back = line2[x];
   46.79 +				top2 = 0x04;
   46.80 +			}
   46.81 +
   46.82 +			if ((u8)(line3[x]>>24) < (u8)(back >> 24))
   46.83 +			{
   46.84 +				back = line3[x];
   46.85 +				top2 = 0x08;
   46.86 +			}
   46.87 +
   46.88 +			if (top2 & (BLDMOD>>8))
   46.89 +				color = gfxAlphaBlend(color, back,
   46.90 +				                      coeff[COLEV & 0x1F],
   46.91 +				                      coeff[(COLEV >> 8) & 0x1F]);
   46.92 +			else
   46.93 +			{
   46.94 +				switch ((BLDMOD >> 6) & 3)
   46.95 +				{
   46.96 +				case 2:
   46.97 +					if (BLDMOD & top)
   46.98 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
   46.99 +					break;
  46.100 +				case 3:
  46.101 +					if (BLDMOD & top)
  46.102 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  46.103 +					break;
  46.104 +				}
  46.105 +			}
  46.106 +		}
  46.107 +
  46.108 +		lineMix[x] = color;
  46.109 +	}
  46.110 +	gfxBG2Changed = 0;
  46.111 +	gfxBG3Changed = 0;
  46.112 +	gfxLastVCOUNT = VCOUNT;
  46.113 +}
  46.114 +
  46.115 +void mode2RenderLineNoWindow()
  46.116 +{
  46.117 +	u16 *palette = (u16 *)paletteRAM;
  46.118 +
  46.119 +	if (DISPCNT & 0x80)
  46.120 +	{
  46.121 +		for (int x = 0; x < 240; x++)
  46.122 +		{
  46.123 +			lineMix[x] = 0x7fff;
  46.124 +		}
  46.125 +		gfxLastVCOUNT = VCOUNT;
  46.126 +		return;
  46.127 +	}
  46.128 +
  46.129 +	if (layerEnable & 0x0400)
  46.130 +	{
  46.131 +		int changed = gfxBG2Changed;
  46.132 +		if (gfxLastVCOUNT > VCOUNT)
  46.133 +			changed = 3;
  46.134 +
  46.135 +		gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
  46.136 +		                 BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y,
  46.137 +		                 changed, line2);
  46.138 +	}
  46.139 +
  46.140 +	if (layerEnable & 0x0800)
  46.141 +	{
  46.142 +		int changed = gfxBG3Changed;
  46.143 +		if (gfxLastVCOUNT > VCOUNT)
  46.144 +			changed = 3;
  46.145 +
  46.146 +		gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H,
  46.147 +		                 BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y,
  46.148 +		                 changed, line3);
  46.149 +	}
  46.150 +
  46.151 +	gfxDrawSprites(lineOBJ);
  46.152 +
  46.153 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
  46.154 +
  46.155 +	for (int x = 0; x < 240; x++)
  46.156 +	{
  46.157 +		u32 color = backdrop;
  46.158 +		u8  top   = 0x20;
  46.159 +
  46.160 +		if ((u8)(line2[x]>>24) < (u8)(color >> 24))
  46.161 +		{
  46.162 +			color = line2[x];
  46.163 +			top   = 0x04;
  46.164 +		}
  46.165 +
  46.166 +		if ((u8)(line3[x]>>24) < (u8)(color >> 24))
  46.167 +		{
  46.168 +			color = line3[x];
  46.169 +			top   = 0x08;
  46.170 +		}
  46.171 +
  46.172 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))
  46.173 +		{
  46.174 +			color = lineOBJ[x];
  46.175 +			top   = 0x10;
  46.176 +		}
  46.177 +
  46.178 +		if (!(color & 0x00010000))
  46.179 +		{
  46.180 +			switch ((BLDMOD >> 6) & 3)
  46.181 +			{
  46.182 +			case 0:
  46.183 +				break;
  46.184 +			case 1:
  46.185 +			{
  46.186 +				if (top & BLDMOD)
  46.187 +				{
  46.188 +					u32 back = backdrop;
  46.189 +					u8  top2 = 0x20;
  46.190 +
  46.191 +					if ((u8)(line2[x]>>24) < (u8)(back >> 24))
  46.192 +					{
  46.193 +						if (top != 0x04)
  46.194 +						{
  46.195 +							back = line2[x];
  46.196 +							top2 = 0x04;
  46.197 +						}
  46.198 +					}
  46.199 +
  46.200 +					if ((u8)(line3[x]>>24) < (u8)(back >> 24))
  46.201 +					{
  46.202 +						if (top != 0x08)
  46.203 +						{
  46.204 +							back = line3[x];
  46.205 +							top2 = 0x08;
  46.206 +						}
  46.207 +					}
  46.208 +
  46.209 +					if ((u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  46.210 +					{
  46.211 +						if (top != 0x10)
  46.212 +						{
  46.213 +							back = lineOBJ[x];
  46.214 +							top2 = 0x10;
  46.215 +						}
  46.216 +					}
  46.217 +
  46.218 +					if (top2 & (BLDMOD>>8))
  46.219 +						color = gfxAlphaBlend(color, back,
  46.220 +						                      coeff[COLEV & 0x1F],
  46.221 +						                      coeff[(COLEV >> 8) & 0x1F]);
  46.222 +				}
  46.223 +				break;
  46.224 +			}
  46.225 +			case 2:
  46.226 +				if (BLDMOD & top)
  46.227 +					color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  46.228 +				break;
  46.229 +			case 3:
  46.230 +				if (BLDMOD & top)
  46.231 +					color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  46.232 +				break;
  46.233 +			}
  46.234 +		}
  46.235 +		else
  46.236 +		{
  46.237 +			// semi-transparent OBJ
  46.238 +			u32 back = backdrop;
  46.239 +			u8  top2 = 0x20;
  46.240 +
  46.241 +			if ((u8)(line2[x]>>24) < (u8)(back >> 24))
  46.242 +			{
  46.243 +				back = line2[x];
  46.244 +				top2 = 0x04;
  46.245 +			}
  46.246 +
  46.247 +			if ((u8)(line3[x]>>24) < (u8)(back >> 24))
  46.248 +			{
  46.249 +				back = line3[x];
  46.250 +				top2 = 0x08;
  46.251 +			}
  46.252 +
  46.253 +			if (top2 & (BLDMOD>>8))
  46.254 +				color = gfxAlphaBlend(color, back,
  46.255 +				                      coeff[COLEV & 0x1F],
  46.256 +				                      coeff[(COLEV >> 8) & 0x1F]);
  46.257 +			else
  46.258 +			{
  46.259 +				switch ((BLDMOD >> 6) & 3)
  46.260 +				{
  46.261 +				case 2:
  46.262 +					if (BLDMOD & top)
  46.263 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  46.264 +					break;
  46.265 +				case 3:
  46.266 +					if (BLDMOD & top)
  46.267 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  46.268 +					break;
  46.269 +				}
  46.270 +			}
  46.271 +		}
  46.272 +
  46.273 +		lineMix[x] = color;
  46.274 +	}
  46.275 +	gfxBG2Changed = 0;
  46.276 +	gfxBG3Changed = 0;
  46.277 +	gfxLastVCOUNT = VCOUNT;
  46.278 +}
  46.279 +
  46.280 +void mode2RenderLineAll()
  46.281 +{
  46.282 +	u16 *palette = (u16 *)paletteRAM;
  46.283 +
  46.284 +	if (DISPCNT & 0x80)
  46.285 +	{
  46.286 +		for (int x = 0; x < 240; x++)
  46.287 +		{
  46.288 +			lineMix[x] = 0x7fff;
  46.289 +		}
  46.290 +		gfxLastVCOUNT = VCOUNT;
  46.291 +		return;
  46.292 +	}
  46.293 +
  46.294 +	bool inWindow0 = false;
  46.295 +	bool inWindow1 = false;
  46.296 +
  46.297 +	if (layerEnable & 0x2000)
  46.298 +	{
  46.299 +		u8 v0 = WIN0V >> 8;
  46.300 +		u8 v1 = WIN0V & 255;
  46.301 +		inWindow0 = ((v0 == v1) && (v0 >= 0xe8));
  46.302 +		if (v1 >= v0)
  46.303 +			inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1);
  46.304 +		else
  46.305 +			inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1);
  46.306 +	}
  46.307 +	if (layerEnable & 0x4000)
  46.308 +	{
  46.309 +		u8 v0 = WIN1V >> 8;
  46.310 +		u8 v1 = WIN1V & 255;
  46.311 +		inWindow1 = ((v0 == v1) && (v0 >= 0xe8));
  46.312 +		if (v1 >= v0)
  46.313 +			inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1);
  46.314 +		else
  46.315 +			inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1);
  46.316 +	}
  46.317 +
  46.318 +	if (layerEnable & 0x0400)
  46.319 +	{
  46.320 +		int changed = gfxBG2Changed;
  46.321 +		if (gfxLastVCOUNT > VCOUNT)
  46.322 +			changed = 3;
  46.323 +
  46.324 +		gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
  46.325 +		                 BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y,
  46.326 +		                 changed, line2);
  46.327 +	}
  46.328 +
  46.329 +	if (layerEnable & 0x0800)
  46.330 +	{
  46.331 +		int changed = gfxBG3Changed;
  46.332 +		if (gfxLastVCOUNT > VCOUNT)
  46.333 +			changed = 3;
  46.334 +
  46.335 +		gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H,
  46.336 +		                 BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y,
  46.337 +		                 changed, line3);
  46.338 +	}
  46.339 +
  46.340 +	gfxDrawSprites(lineOBJ);
  46.341 +	gfxDrawOBJWin(lineOBJWin);
  46.342 +
  46.343 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
  46.344 +
  46.345 +	u8 inWin0Mask = WININ & 0xFF;
  46.346 +	u8 inWin1Mask = WININ >> 8;
  46.347 +	u8 outMask    = WINOUT & 0xFF;
  46.348 +
  46.349 +	for (int x = 0; x < 240; x++)
  46.350 +	{
  46.351 +		u32 color = backdrop;
  46.352 +		u8  top   = 0x20;
  46.353 +		u8  mask  = outMask;
  46.354 +
  46.355 +		if (!(lineOBJWin[x] & 0x80000000))
  46.356 +		{
  46.357 +			mask = WINOUT >> 8;
  46.358 +		}
  46.359 +
  46.360 +		if (inWindow1)
  46.361 +		{
  46.362 +			if (gfxInWin1[x])
  46.363 +				mask = inWin1Mask;
  46.364 +		}
  46.365 +
  46.366 +		if (inWindow0)
  46.367 +		{
  46.368 +			if (gfxInWin0[x])
  46.369 +			{
  46.370 +				mask = inWin0Mask;
  46.371 +			}
  46.372 +		}
  46.373 +
  46.374 +		if (line2[x] < color && (mask & 4))
  46.375 +		{
  46.376 +			color = line2[x];
  46.377 +			top   = 0x04;
  46.378 +		}
  46.379 +
  46.380 +		if ((u8)(line3[x]>>24) < (u8)(color >> 24) && (mask & 8))
  46.381 +		{
  46.382 +			color = line3[x];
  46.383 +			top   = 0x08;
  46.384 +		}
  46.385 +
  46.386 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16))
  46.387 +		{
  46.388 +			color = lineOBJ[x];
  46.389 +			top   = 0x10;
  46.390 +		}
  46.391 +
  46.392 +		if (mask & 32)
  46.393 +		{
  46.394 +			if (!(color & 0x00010000))
  46.395 +			{
  46.396 +				switch ((BLDMOD >> 6) & 3)
  46.397 +				{
  46.398 +				case 0:
  46.399 +					break;
  46.400 +				case 1:
  46.401 +				{
  46.402 +					if (top & BLDMOD)
  46.403 +					{
  46.404 +						u32 back = backdrop;
  46.405 +						u8  top2 = 0x20;
  46.406 +
  46.407 +						if ((mask & 4) && line2[x] < back)
  46.408 +						{
  46.409 +							if (top != 0x04)
  46.410 +							{
  46.411 +								back = line2[x];
  46.412 +								top2 = 0x04;
  46.413 +							}
  46.414 +						}
  46.415 +
  46.416 +						if ((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24))
  46.417 +						{
  46.418 +							if (top != 0x08)
  46.419 +							{
  46.420 +								back = line3[x];
  46.421 +								top2 = 0x08;
  46.422 +							}
  46.423 +						}
  46.424 +
  46.425 +						if ((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  46.426 +						{
  46.427 +							if (top != 0x10)
  46.428 +							{
  46.429 +								back = lineOBJ[x];
  46.430 +								top2 = 0x10;
  46.431 +							}
  46.432 +						}
  46.433 +
  46.434 +						if (top2 & (BLDMOD>>8))
  46.435 +							color = gfxAlphaBlend(color, back,
  46.436 +							                      coeff[COLEV & 0x1F],
  46.437 +							                      coeff[(COLEV >> 8) & 0x1F]);
  46.438 +					}
  46.439 +					break;
  46.440 +				}
  46.441 +				case 2:
  46.442 +					if (BLDMOD & top)
  46.443 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  46.444 +					break;
  46.445 +				case 3:
  46.446 +					if (BLDMOD & top)
  46.447 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  46.448 +					break;
  46.449 +				}
  46.450 +			}
  46.451 +			else
  46.452 +			{
  46.453 +				// semi-transparent OBJ
  46.454 +				u32 back = backdrop;
  46.455 +				u8  top2 = 0x20;
  46.456 +
  46.457 +				if ((mask & 4) && line2[x] < back)
  46.458 +				{
  46.459 +					back = line2[x];
  46.460 +					top2 = 0x04;
  46.461 +				}
  46.462 +
  46.463 +				if ((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24))
  46.464 +				{
  46.465 +					back = line3[x];
  46.466 +					top2 = 0x08;
  46.467 +				}
  46.468 +
  46.469 +				if (top2 & (BLDMOD>>8))
  46.470 +					color = gfxAlphaBlend(color, back,
  46.471 +					                      coeff[COLEV & 0x1F],
  46.472 +					                      coeff[(COLEV >> 8) & 0x1F]);
  46.473 +				else
  46.474 +				{
  46.475 +					switch ((BLDMOD >> 6) & 3)
  46.476 +					{
  46.477 +					case 2:
  46.478 +						if (BLDMOD & top)
  46.479 +							color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  46.480 +						break;
  46.481 +					case 3:
  46.482 +						if (BLDMOD & top)
  46.483 +							color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  46.484 +						break;
  46.485 +					}
  46.486 +				}
  46.487 +			}
  46.488 +		}
  46.489 +		else if (color & 0x00010000)
  46.490 +		{
  46.491 +			// semi-transparent OBJ
  46.492 +			u32 back = backdrop;
  46.493 +			u8  top2 = 0x20;
  46.494 +
  46.495 +			if ((mask & 4) && line2[x] < back)
  46.496 +			{
  46.497 +				back = line2[x];
  46.498 +				top2 = 0x04;
  46.499 +			}
  46.500 +
  46.501 +			if ((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24))
  46.502 +			{
  46.503 +				back = line3[x];
  46.504 +				top2 = 0x08;
  46.505 +			}
  46.506 +
  46.507 +			if (top2 & (BLDMOD>>8))
  46.508 +				color = gfxAlphaBlend(color, back,
  46.509 +				                      coeff[COLEV & 0x1F],
  46.510 +				                      coeff[(COLEV >> 8) & 0x1F]);
  46.511 +			else
  46.512 +			{
  46.513 +				switch ((BLDMOD >> 6) & 3)
  46.514 +				{
  46.515 +				case 2:
  46.516 +					if (BLDMOD & top)
  46.517 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  46.518 +					break;
  46.519 +				case 3:
  46.520 +					if (BLDMOD & top)
  46.521 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  46.522 +					break;
  46.523 +				}
  46.524 +			}
  46.525 +		}
  46.526 +
  46.527 +		lineMix[x] = color;
  46.528 +	}
  46.529 +	gfxBG2Changed = 0;
  46.530 +	gfxBG3Changed = 0;
  46.531 +	gfxLastVCOUNT = VCOUNT;
  46.532 +}
  46.533 +
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/src/gba/Mode3.cpp	Sun Mar 04 14:33:52 2012 -0600
    47.3 @@ -0,0 +1,443 @@
    47.4 +#include "GBAGfx.h"
    47.5 +#include "GBAGlobals.h"
    47.6 +
    47.7 +void mode3RenderLine()
    47.8 +{
    47.9 +	u16 *palette = (u16 *)paletteRAM;
   47.10 +
   47.11 +	if (DISPCNT & 0x80)
   47.12 +	{
   47.13 +		for (int x = 0; x < 240; x++)
   47.14 +		{
   47.15 +			lineMix[x] = 0x7fff;
   47.16 +		}
   47.17 +		gfxLastVCOUNT = VCOUNT;
   47.18 +		return;
   47.19 +	}
   47.20 +
   47.21 +	if (layerEnable & 0x0400)
   47.22 +	{
   47.23 +		int changed = gfxBG2Changed;
   47.24 +
   47.25 +		if (gfxLastVCOUNT > VCOUNT)
   47.26 +			changed = 3;
   47.27 +
   47.28 +		gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H,
   47.29 +		                      BG2Y_L, BG2Y_H, BG2PA, BG2PB,
   47.30 +		                      BG2PC, BG2PD,
   47.31 +		                      gfxBG2X, gfxBG2Y, changed,
   47.32 +		                      line2);
   47.33 +	}
   47.34 +
   47.35 +	gfxDrawSprites(lineOBJ);
   47.36 +
   47.37 +	u32 background = (READ16LE(&palette[0]) | 0x30000000);
   47.38 +
   47.39 +	for (int x = 0; x < 240; x++)
   47.40 +	{
   47.41 +		u32 color = background;
   47.42 +		u8  top   = 0x20;
   47.43 +
   47.44 +		if (line2[x] < color)
   47.45 +		{
   47.46 +			color = line2[x];
   47.47 +			top   = 0x04;
   47.48 +		}
   47.49 +
   47.50 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))
   47.51 +		{
   47.52 +			color = lineOBJ[x];
   47.53 +			top   = 0x10;
   47.54 +		}
   47.55 +
   47.56 +		if ((top & 0x10) && (color & 0x00010000))
   47.57 +		{
   47.58 +			// semi-transparent OBJ
   47.59 +			u32 back = background;
   47.60 +			u8  top2 = 0x20;
   47.61 +
   47.62 +			if (line2[x] < back)
   47.63 +			{
   47.64 +				back = line2[x];
   47.65 +				top2 = 0x04;
   47.66 +			}
   47.67 +
   47.68 +			if (top2 & (BLDMOD>>8))
   47.69 +				color = gfxAlphaBlend(color, back,
   47.70 +				                      coeff[COLEV & 0x1F],
   47.71 +				                      coeff[(COLEV >> 8) & 0x1F]);
   47.72 +			else
   47.73 +			{
   47.74 +				switch ((BLDMOD >> 6) & 3)
   47.75 +				{
   47.76 +				case 2:
   47.77 +					if (BLDMOD & top)
   47.78 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
   47.79 +					break;
   47.80 +				case 3:
   47.81 +					if (BLDMOD & top)
   47.82 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
   47.83 +					break;
   47.84 +				}
   47.85 +			}
   47.86 +		}
   47.87 +
   47.88 +		lineMix[x] = color;
   47.89 +	}
   47.90 +	gfxBG2Changed = 0;
   47.91 +	gfxLastVCOUNT = VCOUNT;
   47.92 +}
   47.93 +
   47.94 +void mode3RenderLineNoWindow()
   47.95 +{
   47.96 +	u16 *palette = (u16 *)paletteRAM;
   47.97 +
   47.98 +	if (DISPCNT & 0x80)
   47.99 +	{
  47.100 +		for (int x = 0; x < 240; x++)
  47.101 +		{
  47.102 +			lineMix[x] = 0x7fff;
  47.103 +		}
  47.104 +		gfxLastVCOUNT = VCOUNT;
  47.105 +		return;
  47.106 +	}
  47.107 +
  47.108 +	if (layerEnable & 0x0400)
  47.109 +	{
  47.110 +		int changed = gfxBG2Changed;
  47.111 +
  47.112 +		if (gfxLastVCOUNT > VCOUNT)
  47.113 +			changed = 3;
  47.114 +
  47.115 +		gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H,
  47.116 +		                      BG2Y_L, BG2Y_H, BG2PA, BG2PB,
  47.117 +		                      BG2PC, BG2PD,
  47.118 +		                      gfxBG2X, gfxBG2Y, changed,
  47.119 +		                      line2);
  47.120 +	}
  47.121 +
  47.122 +	gfxDrawSprites(lineOBJ);
  47.123 +
  47.124 +	u32 background = (READ16LE(&palette[0]) | 0x30000000);
  47.125 +
  47.126 +	for (int x = 0; x < 240; x++)
  47.127 +	{
  47.128 +		u32 color = background;
  47.129 +		u8  top   = 0x20;
  47.130 +
  47.131 +		if (line2[x] < color)
  47.132 +		{
  47.133 +			color = line2[x];
  47.134 +			top   = 0x04;
  47.135 +		}
  47.136 +
  47.137 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))
  47.138 +		{
  47.139 +			color = lineOBJ[x];
  47.140 +			top   = 0x10;
  47.141 +		}
  47.142 +
  47.143 +		if (!(color & 0x00010000))
  47.144 +		{
  47.145 +			switch ((BLDMOD >> 6) & 3)
  47.146 +			{
  47.147 +			case 0:
  47.148 +				break;
  47.149 +			case 1:
  47.150 +			{
  47.151 +				if (top & BLDMOD)
  47.152 +				{
  47.153 +					u32 back = background;
  47.154 +					u8  top2 = 0x20;
  47.155 +
  47.156 +					if (line2[x] < back)
  47.157 +					{
  47.158 +						if (top != 0x04)
  47.159 +						{
  47.160 +							back = line2[x];
  47.161 +							top2 = 0x04;
  47.162 +						}
  47.163 +					}
  47.164 +
  47.165 +					if ((u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  47.166 +					{
  47.167 +						if (top != 0x10)
  47.168 +						{
  47.169 +							back = lineOBJ[x];
  47.170 +							top2 = 0x10;
  47.171 +						}
  47.172 +					}
  47.173 +
  47.174 +					if (top2 & (BLDMOD>>8))
  47.175 +						color = gfxAlphaBlend(color, back,
  47.176 +						                      coeff[COLEV & 0x1F],
  47.177 +						                      coeff[(COLEV >> 8) & 0x1F]);
  47.178 +				}
  47.179 +				break;
  47.180 +			}
  47.181 +			case 2:
  47.182 +				if (BLDMOD & top)
  47.183 +					color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  47.184 +				break;
  47.185 +			case 3:
  47.186 +				if (BLDMOD & top)
  47.187 +					color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  47.188 +				break;
  47.189 +			}
  47.190 +		}
  47.191 +		else
  47.192 +		{
  47.193 +			// semi-transparent OBJ
  47.194 +			u32 back = background;
  47.195 +			u8  top2 = 0x20;
  47.196 +
  47.197 +			if (line2[x] < back)
  47.198 +			{
  47.199 +				back = line2[x];
  47.200 +				top2 = 0x04;
  47.201 +			}
  47.202 +
  47.203 +			if (top2 & (BLDMOD>>8))
  47.204 +				color = gfxAlphaBlend(color, back,
  47.205 +				                      coeff[COLEV & 0x1F],
  47.206 +				                      coeff[(COLEV >> 8) & 0x1F]);
  47.207 +			else
  47.208 +			{
  47.209 +				switch ((BLDMOD >> 6) & 3)
  47.210 +				{
  47.211 +				case 2:
  47.212 +					if (BLDMOD & top)
  47.213 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  47.214 +					break;
  47.215 +				case 3:
  47.216 +					if (BLDMOD & top)
  47.217 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  47.218 +					break;
  47.219 +				}
  47.220 +			}
  47.221 +		}
  47.222 +
  47.223 +		lineMix[x] = color;
  47.224 +	}
  47.225 +	gfxBG2Changed = 0;
  47.226 +	gfxLastVCOUNT = VCOUNT;
  47.227 +}
  47.228 +
  47.229 +void mode3RenderLineAll()
  47.230 +{
  47.231 +	u16 *palette = (u16 *)paletteRAM;
  47.232 +
  47.233 +	if (DISPCNT & 0x80)
  47.234 +	{
  47.235 +		for (int x = 0; x < 240; x++)
  47.236 +		{
  47.237 +			lineMix[x] = 0x7fff;
  47.238 +		}
  47.239 +		gfxLastVCOUNT = VCOUNT;
  47.240 +		return;
  47.241 +	}
  47.242 +
  47.243 +	bool inWindow0 = false;
  47.244 +	bool inWindow1 = false;
  47.245 +
  47.246 +	if (layerEnable & 0x2000)
  47.247 +	{
  47.248 +		u8 v0 = WIN0V >> 8;
  47.249 +		u8 v1 = WIN0V & 255;
  47.250 +		inWindow0 = ((v0 == v1) && (v0 >= 0xe8));
  47.251 +		if (v1 >= v0)
  47.252 +			inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1);
  47.253 +		else
  47.254 +			inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1);
  47.255 +	}
  47.256 +	if (layerEnable & 0x4000)
  47.257 +	{
  47.258 +		u8 v0 = WIN1V >> 8;
  47.259 +		u8 v1 = WIN1V & 255;
  47.260 +		inWindow1 = ((v0 == v1) && (v0 >= 0xe8));
  47.261 +		if (v1 >= v0)
  47.262 +			inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1);
  47.263 +		else
  47.264 +			inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1);
  47.265 +	}
  47.266 +
  47.267 +	if (layerEnable & 0x0400)
  47.268 +	{
  47.269 +		int changed = gfxBG2Changed;
  47.270 +
  47.271 +		if (gfxLastVCOUNT > VCOUNT)
  47.272 +			changed = 3;
  47.273 +
  47.274 +		gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H,
  47.275 +		                      BG2Y_L, BG2Y_H, BG2PA, BG2PB,
  47.276 +		                      BG2PC, BG2PD,
  47.277 +		                      gfxBG2X, gfxBG2Y, changed,
  47.278 +		                      line2);
  47.279 +	}
  47.280 +
  47.281 +	gfxDrawSprites(lineOBJ);
  47.282 +	gfxDrawOBJWin(lineOBJWin);
  47.283 +
  47.284 +	u8 inWin0Mask = WININ & 0xFF;
  47.285 +	u8 inWin1Mask = WININ >> 8;
  47.286 +	u8 outMask    = WINOUT & 0xFF;
  47.287 +
  47.288 +	u32 background = (READ16LE(&palette[0]) | 0x30000000);
  47.289 +
  47.290 +	for (int x = 0; x < 240; x++)
  47.291 +	{
  47.292 +		u32 color = background;
  47.293 +		u8  top   = 0x20;
  47.294 +		u8  mask  = outMask;
  47.295 +
  47.296 +		if (!(lineOBJWin[x] & 0x80000000))
  47.297 +		{
  47.298 +			mask = WINOUT >> 8;
  47.299 +		}
  47.300 +
  47.301 +		if (inWindow1)
  47.302 +		{
  47.303 +			if (gfxInWin1[x])
  47.304 +				mask = inWin1Mask;
  47.305 +		}
  47.306 +
  47.307 +		if (inWindow0)
  47.308 +		{
  47.309 +			if (gfxInWin0[x])
  47.310 +			{
  47.311 +				mask = inWin0Mask;
  47.312 +			}
  47.313 +		}
  47.314 +
  47.315 +		if ((mask & 4) && (line2[x] < color))
  47.316 +		{
  47.317 +			color = line2[x];
  47.318 +			top   = 0x04;
  47.319 +		}
  47.320 +
  47.321 +		if ((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24)))
  47.322 +		{
  47.323 +			color = lineOBJ[x];
  47.324 +			top   = 0x10;
  47.325 +		}
  47.326 +
  47.327 +		if (mask & 32)
  47.328 +		{
  47.329 +			if (!(color & 0x00010000))
  47.330 +			{
  47.331 +				switch ((BLDMOD >> 6) & 3)
  47.332 +				{
  47.333 +				case 0:
  47.334 +					break;
  47.335 +				case 1:
  47.336 +				{
  47.337 +					if (top & BLDMOD)
  47.338 +					{
  47.339 +						u32 back = background;
  47.340 +						u8  top2 = 0x20;
  47.341 +
  47.342 +						if ((mask & 4) && line2[x] < back)
  47.343 +						{
  47.344 +							if (top != 0x04)
  47.345 +							{
  47.346 +								back = line2[x];
  47.347 +								top2 = 0x04;
  47.348 +							}
  47.349 +						}
  47.350 +
  47.351 +						if ((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  47.352 +						{
  47.353 +							if (top != 0x10)
  47.354 +							{
  47.355 +								back = lineOBJ[x];
  47.356 +								top2 = 0x10;
  47.357 +							}
  47.358 +						}
  47.359 +
  47.360 +						if (top2 & (BLDMOD>>8))
  47.361 +							color = gfxAlphaBlend(color, back,
  47.362 +							                      coeff[COLEV & 0x1F],
  47.363 +							                      coeff[(COLEV >> 8) & 0x1F]);
  47.364 +					}
  47.365 +					break;
  47.366 +				}
  47.367 +				case 2:
  47.368 +					if (BLDMOD & top)
  47.369 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  47.370 +					break;
  47.371 +				case 3:
  47.372 +					if (BLDMOD & top)
  47.373 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  47.374 +					break;
  47.375 +				}
  47.376 +			}
  47.377 +			else
  47.378 +			{
  47.379 +				// semi-transparent OBJ
  47.380 +				u32 back = background;
  47.381 +				u8  top2 = 0x20;
  47.382 +
  47.383 +				if ((mask & 4) && line2[x] < back)
  47.384 +				{
  47.385 +					back = line2[x];
  47.386 +					top2 = 0x04;
  47.387 +				}
  47.388 +
  47.389 +				if (top2 & (BLDMOD>>8))
  47.390 +					color = gfxAlphaBlend(color, back,
  47.391 +					                      coeff[COLEV & 0x1F],
  47.392 +					                      coeff[(COLEV >> 8) & 0x1F]);
  47.393 +				else
  47.394 +				{
  47.395 +					switch ((BLDMOD >> 6) & 3)
  47.396 +					{
  47.397 +					case 2:
  47.398 +						if (BLDMOD & top)
  47.399 +							color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  47.400 +						break;
  47.401 +					case 3:
  47.402 +						if (BLDMOD & top)
  47.403 +							color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  47.404 +						break;
  47.405 +					}
  47.406 +				}
  47.407 +			}
  47.408 +		}
  47.409 +		else if (color & 0x00010000)
  47.410 +		{
  47.411 +			// semi-transparent OBJ
  47.412 +			u32 back = background;
  47.413 +			u8  top2 = 0x20;
  47.414 +
  47.415 +			if ((mask & 4) && line2[x] < back)
  47.416 +			{
  47.417 +				back = line2[x];
  47.418 +				top2 = 0x04;
  47.419 +			}
  47.420 +
  47.421 +			if (top2 & (BLDMOD>>8))
  47.422 +				color = gfxAlphaBlend(color, back,
  47.423 +				                      coeff[COLEV & 0x1F],
  47.424 +				                      coeff[(COLEV >> 8) & 0x1F]);
  47.425 +			else
  47.426 +			{
  47.427 +				switch ((BLDMOD >> 6) & 3)
  47.428 +				{
  47.429 +				case 2:
  47.430 +					if (BLDMOD & top)
  47.431 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  47.432 +					break;
  47.433 +				case 3:
  47.434 +					if (BLDMOD & top)
  47.435 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  47.436 +					break;
  47.437 +				}
  47.438 +			}
  47.439 +		}
  47.440 +
  47.441 +		lineMix[x] = color;
  47.442 +	}
  47.443 +	gfxBG2Changed = 0;
  47.444 +	gfxLastVCOUNT = VCOUNT;
  47.445 +}
  47.446 +
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/src/gba/Mode4.cpp	Sun Mar 04 14:33:52 2012 -0600
    48.3 @@ -0,0 +1,440 @@
    48.4 +#include "GBAGfx.h"
    48.5 +#include "GBAGlobals.h"
    48.6 +
    48.7 +void mode4RenderLine()
    48.8 +{
    48.9 +	u16 *palette = (u16 *)paletteRAM;
   48.10 +
   48.11 +	if (DISPCNT & 0x0080)
   48.12 +	{
   48.13 +		for (int x = 0; x < 240; x++)
   48.14 +		{
   48.15 +			lineMix[x] = 0x7fff;
   48.16 +		}
   48.17 +		gfxLastVCOUNT = VCOUNT;
   48.18 +		return;
   48.19 +	}
   48.20 +
   48.21 +	if (layerEnable & 0x400)
   48.22 +	{
   48.23 +		int changed = gfxBG2Changed;
   48.24 +
   48.25 +		if (gfxLastVCOUNT > VCOUNT)
   48.26 +			changed = 3;
   48.27 +
   48.28 +		gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
   48.29 +		                    BG2PA, BG2PB, BG2PC, BG2PD,
   48.30 +		                    gfxBG2X, gfxBG2Y, changed,
   48.31 +		                    line2);
   48.32 +	}
   48.33 +
   48.34 +	gfxDrawSprites(lineOBJ);
   48.35 +
   48.36 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
   48.37 +
   48.38 +	for (int x = 0; x < 240; x++)
   48.39 +	{
   48.40 +		u32 color = backdrop;
   48.41 +		u8  top   = 0x20;
   48.42 +
   48.43 +		if (line2[x] < color)
   48.44 +		{
   48.45 +			color = line2[x];
   48.46 +			top   = 0x04;
   48.47 +		}
   48.48 +
   48.49 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))
   48.50 +		{
   48.51 +			color = lineOBJ[x];
   48.52 +			top   = 0x10;
   48.53 +		}
   48.54 +
   48.55 +		if ((top & 0x10) && (color & 0x00010000))
   48.56 +		{
   48.57 +			// semi-transparent OBJ
   48.58 +			u32 back = backdrop;
   48.59 +			u8  top2 = 0x20;
   48.60 +
   48.61 +			if (line2[x] < back)
   48.62 +			{
   48.63 +				back = line2[x];
   48.64 +				top2 = 0x04;
   48.65 +			}
   48.66 +
   48.67 +			if (top2 & (BLDMOD>>8))
   48.68 +				color = gfxAlphaBlend(color, back,
   48.69 +				                      coeff[COLEV & 0x1F],
   48.70 +				                      coeff[(COLEV >> 8) & 0x1F]);
   48.71 +			else
   48.72 +			{
   48.73 +				switch ((BLDMOD >> 6) & 3)
   48.74 +				{
   48.75 +				case 2:
   48.76 +					if (BLDMOD & top)
   48.77 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
   48.78 +					break;
   48.79 +				case 3:
   48.80 +					if (BLDMOD & top)
   48.81 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
   48.82 +					break;
   48.83 +				}
   48.84 +			}
   48.85 +		}
   48.86 +
   48.87 +		lineMix[x] = color;
   48.88 +	}
   48.89 +	gfxBG2Changed = 0;
   48.90 +	gfxLastVCOUNT = VCOUNT;
   48.91 +}
   48.92 +
   48.93 +void mode4RenderLineNoWindow()
   48.94 +{
   48.95 +	u16 *palette = (u16 *)paletteRAM;
   48.96 +
   48.97 +	if (DISPCNT & 0x0080)
   48.98 +	{
   48.99 +		for (int x = 0; x < 240; x++)
  48.100 +		{
  48.101 +			lineMix[x] = 0x7fff;
  48.102 +		}
  48.103 +		gfxLastVCOUNT = VCOUNT;
  48.104 +		return;
  48.105 +	}
  48.106 +
  48.107 +	if (layerEnable & 0x400)
  48.108 +	{
  48.109 +		int changed = gfxBG2Changed;
  48.110 +
  48.111 +		if (gfxLastVCOUNT > VCOUNT)
  48.112 +			changed = 3;
  48.113 +
  48.114 +		gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
  48.115 +		                    BG2PA, BG2PB, BG2PC, BG2PD,
  48.116 +		                    gfxBG2X, gfxBG2Y, changed,
  48.117 +		                    line2);
  48.118 +	}
  48.119 +
  48.120 +	gfxDrawSprites(lineOBJ);
  48.121 +
  48.122 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
  48.123 +
  48.124 +	for (int x = 0; x < 240; x++)
  48.125 +	{
  48.126 +		u32 color = backdrop;
  48.127 +		u8  top   = 0x20;
  48.128 +
  48.129 +		if (line2[x] < color)
  48.130 +		{
  48.131 +			color = line2[x];
  48.132 +			top   = 0x04;
  48.133 +		}
  48.134 +
  48.135 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))
  48.136 +		{
  48.137 +			color = lineOBJ[x];
  48.138 +			top   = 0x10;
  48.139 +		}
  48.140 +
  48.141 +		if (!(color & 0x00010000))
  48.142 +		{
  48.143 +			switch ((BLDMOD >> 6) & 3)
  48.144 +			{
  48.145 +			case 0:
  48.146 +				break;
  48.147 +			case 1:
  48.148 +			{
  48.149 +				if (top & BLDMOD)
  48.150 +				{
  48.151 +					u32 back = backdrop;
  48.152 +					u8  top2 = 0x20;
  48.153 +
  48.154 +					if (line2[x] < back)
  48.155 +					{
  48.156 +						if (top != 0x04)
  48.157 +						{
  48.158 +							back = line2[x];
  48.159 +							top2 = 0x04;
  48.160 +						}
  48.161 +					}
  48.162 +
  48.163 +					if ((u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  48.164 +					{
  48.165 +						if (top != 0x10)
  48.166 +						{
  48.167 +							back = lineOBJ[x];
  48.168 +							top2 = 0x10;
  48.169 +						}
  48.170 +					}
  48.171 +
  48.172 +					if (top2 & (BLDMOD>>8))
  48.173 +						color = gfxAlphaBlend(color, back,
  48.174 +						                      coeff[COLEV & 0x1F],
  48.175 +						                      coeff[(COLEV >> 8) & 0x1F]);
  48.176 +				}
  48.177 +				break;
  48.178 +			}
  48.179 +			case 2:
  48.180 +				if (BLDMOD & top)
  48.181 +					color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  48.182 +				break;
  48.183 +			case 3:
  48.184 +				if (BLDMOD & top)
  48.185 +					color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  48.186 +				break;
  48.187 +			}
  48.188 +		}
  48.189 +		else
  48.190 +		{
  48.191 +			// semi-transparent OBJ
  48.192 +			u32 back = backdrop;
  48.193 +			u8  top2 = 0x20;
  48.194 +
  48.195 +			if (line2[x] < back)
  48.196 +			{
  48.197 +				back = line2[x];
  48.198 +				top2 = 0x04;
  48.199 +			}
  48.200 +
  48.201 +			if (top2 & (BLDMOD>>8))
  48.202 +				color = gfxAlphaBlend(color, back,
  48.203 +				                      coeff[COLEV & 0x1F],
  48.204 +				                      coeff[(COLEV >> 8) & 0x1F]);
  48.205 +			else
  48.206 +			{
  48.207 +				switch ((BLDMOD >> 6) & 3)
  48.208 +				{
  48.209 +				case 2:
  48.210 +					if (BLDMOD & top)
  48.211 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  48.212 +					break;
  48.213 +				case 3:
  48.214 +					if (BLDMOD & top)
  48.215 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  48.216 +					break;
  48.217 +				}
  48.218 +			}
  48.219 +		}
  48.220 +
  48.221 +		lineMix[x] = color;
  48.222 +	}
  48.223 +	gfxBG2Changed = 0;
  48.224 +	gfxLastVCOUNT = VCOUNT;
  48.225 +}
  48.226 +
  48.227 +void mode4RenderLineAll()
  48.228 +{
  48.229 +	u16 *palette = (u16 *)paletteRAM;
  48.230 +
  48.231 +	if (DISPCNT & 0x0080)
  48.232 +	{
  48.233 +		for (int x = 0; x < 240; x++)
  48.234 +		{
  48.235 +			lineMix[x] = 0x7fff;
  48.236 +		}
  48.237 +		gfxLastVCOUNT = VCOUNT;
  48.238 +		return;
  48.239 +	}
  48.240 +
  48.241 +	bool inWindow0 = false;
  48.242 +	bool inWindow1 = false;
  48.243 +
  48.244 +	if (layerEnable & 0x2000)
  48.245 +	{
  48.246 +		u8 v0 = WIN0V >> 8;
  48.247 +		u8 v1 = WIN0V & 255;
  48.248 +		inWindow0 = ((v0 == v1) && (v0 >= 0xe8));
  48.249 +		if (v1 >= v0)
  48.250 +			inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1);
  48.251 +		else
  48.252 +			inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1);
  48.253 +	}
  48.254 +	if (layerEnable & 0x4000)
  48.255 +	{
  48.256 +		u8 v0 = WIN1V >> 8;
  48.257 +		u8 v1 = WIN1V & 255;
  48.258 +		inWindow1 = ((v0 == v1) && (v0 >= 0xe8));
  48.259 +		if (v1 >= v0)
  48.260 +			inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1);
  48.261 +		else
  48.262 +			inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1);
  48.263 +	}
  48.264 +
  48.265 +	if (layerEnable & 0x400)
  48.266 +	{
  48.267 +		int changed = gfxBG2Changed;
  48.268 +
  48.269 +		if (gfxLastVCOUNT > VCOUNT)
  48.270 +			changed = 3;
  48.271 +
  48.272 +		gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
  48.273 +		                    BG2PA, BG2PB, BG2PC, BG2PD,
  48.274 +		                    gfxBG2X, gfxBG2Y, changed,
  48.275 +		                    line2);
  48.276 +	}
  48.277 +
  48.278 +	gfxDrawSprites(lineOBJ);
  48.279 +	gfxDrawOBJWin(lineOBJWin);
  48.280 +
  48.281 +	u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
  48.282 +
  48.283 +	u8 inWin0Mask = WININ & 0xFF;
  48.284 +	u8 inWin1Mask = WININ >> 8;
  48.285 +	u8 outMask    = WINOUT & 0xFF;
  48.286 +
  48.287 +	for (int x = 0; x < 240; x++)
  48.288 +	{
  48.289 +		u32 color = backdrop;
  48.290 +		u8  top   = 0x20;
  48.291 +		u8  mask  = outMask;
  48.292 +
  48.293 +		if (!(lineOBJWin[x] & 0x80000000))
  48.294 +		{
  48.295 +			mask = WINOUT >> 8;
  48.296 +		}
  48.297 +
  48.298 +		if (inWindow1)
  48.299 +		{
  48.300 +			if (gfxInWin1[x])
  48.301 +				mask = inWin1Mask;
  48.302 +		}
  48.303 +
  48.304 +		if (inWindow0)
  48.305 +		{
  48.306 +			if (gfxInWin0[x])
  48.307 +			{
  48.308 +				mask = inWin0Mask;
  48.309 +			}
  48.310 +		}
  48.311 +
  48.312 +		if ((mask & 4) && (line2[x] < color))
  48.313 +		{
  48.314 +			color = line2[x];
  48.315 +			top   = 0x04;
  48.316 +		}
  48.317 +
  48.318 +		if ((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24)))
  48.319 +		{
  48.320 +			color = lineOBJ[x];
  48.321 +			top   = 0x10;
  48.322 +		}
  48.323 +
  48.324 +		if (mask & 32)
  48.325 +		{
  48.326 +			if (!(color & 0x00010000))
  48.327 +			{
  48.328 +				switch ((BLDMOD >> 6) & 3)
  48.329 +				{
  48.330 +				case 0:
  48.331 +					break;
  48.332 +				case 1:
  48.333 +				{
  48.334 +					if (top & BLDMOD)
  48.335 +					{
  48.336 +						u32 back = backdrop;
  48.337 +						u8  top2 = 0x20;
  48.338 +
  48.339 +						if ((mask & 4) && line2[x] < back)
  48.340 +						{
  48.341 +							if (top != 0x04)
  48.342 +							{
  48.343 +								back = line2[x];
  48.344 +								top2 = 0x04;
  48.345 +							}
  48.346 +						}
  48.347 +
  48.348 +						if ((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  48.349 +						{
  48.350 +							if (top != 0x10)
  48.351 +							{
  48.352 +								back = lineOBJ[x];
  48.353 +								top2 = 0x10;
  48.354 +							}
  48.355 +						}
  48.356 +
  48.357 +						if (top2 & (BLDMOD>>8))
  48.358 +							color = gfxAlphaBlend(color, back,
  48.359 +							                      coeff[COLEV & 0x1F],
  48.360 +							                      coeff[(COLEV >> 8) & 0x1F]);
  48.361 +					}
  48.362 +					break;
  48.363 +				}
  48.364 +				case 2:
  48.365 +					if (BLDMOD & top)
  48.366 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  48.367 +					break;
  48.368 +				case 3:
  48.369 +					if (BLDMOD & top)
  48.370 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  48.371 +					break;
  48.372 +				}
  48.373 +			}
  48.374 +			else
  48.375 +			{
  48.376 +				// semi-transparent OBJ
  48.377 +				u32 back = backdrop;
  48.378 +				u8  top2 = 0x20;
  48.379 +
  48.380 +				if ((mask & 4) && line2[x] < back)
  48.381 +				{
  48.382 +					back = line2[x];
  48.383 +					top2 = 0x04;
  48.384 +				}
  48.385 +
  48.386 +				if (top2 & (BLDMOD>>8))
  48.387 +					color = gfxAlphaBlend(color, back,
  48.388 +					                      coeff[COLEV & 0x1F],
  48.389 +					                      coeff[(COLEV >> 8) & 0x1F]);
  48.390 +				else
  48.391 +				{
  48.392 +					switch ((BLDMOD >> 6) & 3)
  48.393 +					{
  48.394 +					case 2:
  48.395 +						if (BLDMOD & top)
  48.396 +							color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  48.397 +						break;
  48.398 +					case 3:
  48.399 +						if (BLDMOD & top)
  48.400 +							color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  48.401 +						break;
  48.402 +					}
  48.403 +				}
  48.404 +			}
  48.405 +		}
  48.406 +		else if (color & 0x00010000)
  48.407 +		{
  48.408 +			// semi-transparent OBJ
  48.409 +			u32 back = backdrop;
  48.410 +			u8  top2 = 0x20;
  48.411 +
  48.412 +			if ((mask & 4) && line2[x] < back)
  48.413 +			{
  48.414 +				back = line2[x];
  48.415 +				top2 = 0x04;
  48.416 +			}
  48.417 +
  48.418 +			if (top2 & (BLDMOD>>8))
  48.419 +				color = gfxAlphaBlend(color, back,
  48.420 +				                      coeff[COLEV & 0x1F],
  48.421 +				                      coeff[(COLEV >> 8) & 0x1F]);
  48.422 +			else
  48.423 +			{
  48.424 +				switch ((BLDMOD >> 6) & 3)
  48.425 +				{
  48.426 +				case 2:
  48.427 +					if (BLDMOD & top)
  48.428 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  48.429 +					break;
  48.430 +				case 3:
  48.431 +					if (BLDMOD & top)
  48.432 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  48.433 +					break;
  48.434 +				}
  48.435 +			}
  48.436 +		}
  48.437 +
  48.438 +		lineMix[x] = color;
  48.439 +	}
  48.440 +	gfxBG2Changed = 0;
  48.441 +	gfxLastVCOUNT = VCOUNT;
  48.442 +}
  48.443 +
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/src/gba/Mode5.cpp	Sun Mar 04 14:33:52 2012 -0600
    49.3 @@ -0,0 +1,443 @@
    49.4 +#include "GBAGfx.h"
    49.5 +#include "GBAGlobals.h"
    49.6 +
    49.7 +void mode5RenderLine()
    49.8 +{
    49.9 +	if (DISPCNT & 0x0080)
   49.10 +	{
   49.11 +		for (int x = 0; x < 240; x++)
   49.12 +		{
   49.13 +			lineMix[x] = 0x7fff;
   49.14 +		}
   49.15 +		gfxLastVCOUNT = VCOUNT;
   49.16 +		return;
   49.17 +	}
   49.18 +
   49.19 +	u16 *palette = (u16 *)paletteRAM;
   49.20 +
   49.21 +	if (layerEnable & 0x0400)
   49.22 +	{
   49.23 +		int changed = gfxBG2Changed;
   49.24 +
   49.25 +		if (gfxLastVCOUNT > VCOUNT)
   49.26 +			changed = 3;
   49.27 +
   49.28 +		gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H,
   49.29 +		                         BG2Y_L, BG2Y_H, BG2PA, BG2PB,
   49.30 +		                         BG2PC, BG2PD,
   49.31 +		                         gfxBG2X, gfxBG2Y, changed,
   49.32 +		                         line2);
   49.33 +	}
   49.34 +
   49.35 +	gfxDrawSprites(lineOBJ);
   49.36 +
   49.37 +	u32 background = (READ16LE(&palette[0]) | 0x30000000);
   49.38 +
   49.39 +	for (int x = 0; x < 240; x++)
   49.40 +	{
   49.41 +		u32 color = background;
   49.42 +		u8  top   = 0x20;
   49.43 +
   49.44 +		if (line2[x] < color)
   49.45 +		{
   49.46 +			color = line2[x];
   49.47 +			top   = 0x04;
   49.48 +		}
   49.49 +
   49.50 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))
   49.51 +		{
   49.52 +			color = lineOBJ[x];
   49.53 +			top   = 0x10;
   49.54 +		}
   49.55 +
   49.56 +		if ((top & 0x10) && (color & 0x00010000))
   49.57 +		{
   49.58 +			// semi-transparent OBJ
   49.59 +			u32 back = background;
   49.60 +			u8  top2 = 0x20;
   49.61 +
   49.62 +			if (line2[x] < back)
   49.63 +			{
   49.64 +				back = line2[x];
   49.65 +				top2 = 0x04;
   49.66 +			}
   49.67 +
   49.68 +			if (top2 & (BLDMOD>>8))
   49.69 +				color = gfxAlphaBlend(color, back,
   49.70 +				                      coeff[COLEV & 0x1F],
   49.71 +				                      coeff[(COLEV >> 8) & 0x1F]);
   49.72 +			else
   49.73 +			{
   49.74 +				switch ((BLDMOD >> 6) & 3)
   49.75 +				{
   49.76 +				case 2:
   49.77 +					if (BLDMOD & top)
   49.78 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
   49.79 +					break;
   49.80 +				case 3:
   49.81 +					if (BLDMOD & top)
   49.82 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
   49.83 +					break;
   49.84 +				}
   49.85 +			}
   49.86 +		}
   49.87 +
   49.88 +		lineMix[x] = color;
   49.89 +	}
   49.90 +	gfxBG2Changed = 0;
   49.91 +	gfxLastVCOUNT = VCOUNT;
   49.92 +}
   49.93 +
   49.94 +void mode5RenderLineNoWindow()
   49.95 +{
   49.96 +	if (DISPCNT & 0x0080)
   49.97 +	{
   49.98 +		for (int x = 0; x < 240; x++)
   49.99 +		{
  49.100 +			lineMix[x] = 0x7fff;
  49.101 +		}
  49.102 +		gfxLastVCOUNT = VCOUNT;
  49.103 +		return;
  49.104 +	}
  49.105 +
  49.106 +	u16 *palette = (u16 *)paletteRAM;
  49.107 +
  49.108 +	if (layerEnable & 0x0400)
  49.109 +	{
  49.110 +		int changed = gfxBG2Changed;
  49.111 +
  49.112 +		if (gfxLastVCOUNT > VCOUNT)
  49.113 +			changed = 3;
  49.114 +
  49.115 +		gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H,
  49.116 +		                         BG2Y_L, BG2Y_H, BG2PA, BG2PB,
  49.117 +		                         BG2PC, BG2PD,
  49.118 +		                         gfxBG2X, gfxBG2Y, changed,
  49.119 +		                         line2);
  49.120 +	}
  49.121 +
  49.122 +	gfxDrawSprites(lineOBJ);
  49.123 +
  49.124 +	u32 background = (READ16LE(&palette[0]) | 0x30000000);
  49.125 +
  49.126 +	for (int x = 0; x < 240; x++)
  49.127 +	{
  49.128 +		u32 color = background;
  49.129 +		u8  top   = 0x20;
  49.130 +
  49.131 +		if (line2[x] < color)
  49.132 +		{
  49.133 +			color = line2[x];
  49.134 +			top   = 0x04;
  49.135 +		}
  49.136 +
  49.137 +		if ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))
  49.138 +		{
  49.139 +			color = lineOBJ[x];
  49.140 +			top   = 0x10;
  49.141 +		}
  49.142 +
  49.143 +		if (!(color & 0x00010000))
  49.144 +		{
  49.145 +			switch ((BLDMOD >> 6) & 3)
  49.146 +			{
  49.147 +			case 0:
  49.148 +				break;
  49.149 +			case 1:
  49.150 +			{
  49.151 +				if (top & BLDMOD)
  49.152 +				{
  49.153 +					u32 back = background;
  49.154 +					u8  top2 = 0x20;
  49.155 +
  49.156 +					if (line2[x] < back)
  49.157 +					{
  49.158 +						if (top != 0x04)
  49.159 +						{
  49.160 +							back = line2[x];
  49.161 +							top2 = 0x04;
  49.162 +						}
  49.163 +					}
  49.164 +
  49.165 +					if ((u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  49.166 +					{
  49.167 +						if (top != 0x10)
  49.168 +						{
  49.169 +							back = lineOBJ[x];
  49.170 +							top2 = 0x10;
  49.171 +						}
  49.172 +					}
  49.173 +
  49.174 +					if (top2 & (BLDMOD>>8))
  49.175 +						color = gfxAlphaBlend(color, back,
  49.176 +						                      coeff[COLEV & 0x1F],
  49.177 +						                      coeff[(COLEV >> 8) & 0x1F]);
  49.178 +				}
  49.179 +				break;
  49.180 +			}
  49.181 +			case 2:
  49.182 +				if (BLDMOD & top)
  49.183 +					color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  49.184 +				break;
  49.185 +			case 3:
  49.186 +				if (BLDMOD & top)
  49.187 +					color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  49.188 +				break;
  49.189 +			}
  49.190 +		}
  49.191 +		else
  49.192 +		{
  49.193 +			// semi-transparent OBJ
  49.194 +			u32 back = background;
  49.195 +			u8  top2 = 0x20;
  49.196 +
  49.197 +			if (line2[x] < back)
  49.198 +			{
  49.199 +				back = line2[x];
  49.200 +				top2 = 0x04;
  49.201 +			}
  49.202 +
  49.203 +			if (top2 & (BLDMOD>>8))
  49.204 +				color = gfxAlphaBlend(color, back,
  49.205 +				                      coeff[COLEV & 0x1F],
  49.206 +				                      coeff[(COLEV >> 8) & 0x1F]);
  49.207 +			else
  49.208 +			{
  49.209 +				switch ((BLDMOD >> 6) & 3)
  49.210 +				{
  49.211 +				case 2:
  49.212 +					if (BLDMOD & top)
  49.213 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  49.214 +					break;
  49.215 +				case 3:
  49.216 +					if (BLDMOD & top)
  49.217 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  49.218 +					break;
  49.219 +				}
  49.220 +			}
  49.221 +		}
  49.222 +
  49.223 +		lineMix[x] = color;
  49.224 +	}
  49.225 +	gfxBG2Changed = 0;
  49.226 +	gfxLastVCOUNT = VCOUNT;
  49.227 +}
  49.228 +
  49.229 +void mode5RenderLineAll()
  49.230 +{
  49.231 +	if (DISPCNT & 0x0080)
  49.232 +	{
  49.233 +		for (int x = 0; x < 240; x++)
  49.234 +		{
  49.235 +			lineMix[x] = 0x7fff;
  49.236 +		}
  49.237 +		gfxLastVCOUNT = VCOUNT;
  49.238 +		return;
  49.239 +	}
  49.240 +
  49.241 +	u16 *palette = (u16 *)paletteRAM;
  49.242 +
  49.243 +	if (layerEnable & 0x0400)
  49.244 +	{
  49.245 +		int changed = gfxBG2Changed;
  49.246 +
  49.247 +		if (gfxLastVCOUNT > VCOUNT)
  49.248 +			changed = 3;
  49.249 +
  49.250 +		gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H,
  49.251 +		                         BG2Y_L, BG2Y_H, BG2PA, BG2PB,
  49.252 +		                         BG2PC, BG2PD,
  49.253 +		                         gfxBG2X, gfxBG2Y, changed,
  49.254 +		                         line2);
  49.255 +	}
  49.256 +
  49.257 +	gfxDrawSprites(lineOBJ);
  49.258 +	gfxDrawOBJWin(lineOBJWin);
  49.259 +
  49.260 +	bool inWindow0 = false;
  49.261 +	bool inWindow1 = false;
  49.262 +
  49.263 +	if (layerEnable & 0x2000)
  49.264 +	{
  49.265 +		u8 v0 = WIN0V >> 8;
  49.266 +		u8 v1 = WIN0V & 255;
  49.267 +		inWindow0 = ((v0 == v1) && (v0 >= 0xe8));
  49.268 +		if (v1 >= v0)
  49.269 +			inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1);
  49.270 +		else
  49.271 +			inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1);
  49.272 +	}
  49.273 +	if (layerEnable & 0x4000)
  49.274 +	{
  49.275 +		u8 v0 = WIN1V >> 8;
  49.276 +		u8 v1 = WIN1V & 255;
  49.277 +		inWindow1 = ((v0 == v1) && (v0 >= 0xe8));
  49.278 +		if (v1 >= v0)
  49.279 +			inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1);
  49.280 +		else
  49.281 +			inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1);
  49.282 +	}
  49.283 +
  49.284 +	u8 inWin0Mask = WININ & 0xFF;
  49.285 +	u8 inWin1Mask = WININ >> 8;
  49.286 +	u8 outMask    = WINOUT & 0xFF;
  49.287 +
  49.288 +	u32 background = (READ16LE(&palette[0]) | 0x30000000);
  49.289 +
  49.290 +	for (int x = 0; x < 240; x++)
  49.291 +	{
  49.292 +		u32 color = background;
  49.293 +		u8  top   = 0x20;
  49.294 +		u8  mask  = outMask;
  49.295 +
  49.296 +		if (!(lineOBJWin[x] & 0x80000000))
  49.297 +		{
  49.298 +			mask = WINOUT >> 8;
  49.299 +		}
  49.300 +
  49.301 +		if (inWindow1)
  49.302 +		{
  49.303 +			if (gfxInWin1[x])
  49.304 +				mask = inWin1Mask;
  49.305 +		}
  49.306 +
  49.307 +		if (inWindow0)
  49.308 +		{
  49.309 +			if (gfxInWin0[x])
  49.310 +			{
  49.311 +				mask = inWin0Mask;
  49.312 +			}
  49.313 +		}
  49.314 +
  49.315 +		if ((mask & 4) && (line2[x] < color))
  49.316 +		{
  49.317 +			color = line2[x];
  49.318 +			top   = 0x04;
  49.319 +		}
  49.320 +
  49.321 +		if ((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24)))
  49.322 +		{
  49.323 +			color = lineOBJ[x];
  49.324 +			top   = 0x10;
  49.325 +		}
  49.326 +
  49.327 +		if (mask & 32)
  49.328 +		{
  49.329 +			if (!(color & 0x00010000))
  49.330 +			{
  49.331 +				switch ((BLDMOD >> 6) & 3)
  49.332 +				{
  49.333 +				case 0:
  49.334 +					break;
  49.335 +				case 1:
  49.336 +				{
  49.337 +					if (top & BLDMOD)
  49.338 +					{
  49.339 +						u32 back = background;
  49.340 +						u8  top2 = 0x20;
  49.341 +
  49.342 +						if ((mask & 4) && line2[x] < back)
  49.343 +						{
  49.344 +							if (top != 0x04)
  49.345 +							{
  49.346 +								back = line2[x];
  49.347 +								top2 = 0x04;
  49.348 +							}
  49.349 +						}
  49.350 +
  49.351 +						if ((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24))
  49.352 +						{
  49.353 +							if (top != 0x10)
  49.354 +							{
  49.355 +								back = lineOBJ[x];
  49.356 +								top2 = 0x10;
  49.357 +							}
  49.358 +						}
  49.359 +
  49.360 +						if (top2 & (BLDMOD>>8))
  49.361 +							color = gfxAlphaBlend(color, back,
  49.362 +							                      coeff[COLEV & 0x1F],
  49.363 +							                      coeff[(COLEV >> 8) & 0x1F]);
  49.364 +					}
  49.365 +					break;
  49.366 +				}
  49.367 +				case 2:
  49.368 +					if (BLDMOD & top)
  49.369 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  49.370 +					break;
  49.371 +				case 3:
  49.372 +					if (BLDMOD & top)
  49.373 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  49.374 +					break;
  49.375 +				}
  49.376 +			}
  49.377 +			else
  49.378 +			{
  49.379 +				// semi-transparent OBJ
  49.380 +				u32 back = background;
  49.381 +				u8  top2 = 0x20;
  49.382 +
  49.383 +				if ((mask & 4) && line2[x] < back)
  49.384 +				{
  49.385 +					back = line2[x];
  49.386 +					top2 = 0x04;
  49.387 +				}
  49.388 +
  49.389 +				if (top2 & (BLDMOD>>8))
  49.390 +					color = gfxAlphaBlend(color, back,
  49.391 +					                      coeff[COLEV & 0x1F],
  49.392 +					                      coeff[(COLEV >> 8) & 0x1F]);
  49.393 +				else
  49.394 +				{
  49.395 +					switch ((BLDMOD >> 6) & 3)
  49.396 +					{
  49.397 +					case 2:
  49.398 +						if (BLDMOD & top)
  49.399 +							color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  49.400 +						break;
  49.401 +					case 3:
  49.402 +						if (BLDMOD & top)
  49.403 +							color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  49.404 +						break;
  49.405 +					}
  49.406 +				}
  49.407 +			}
  49.408 +		}
  49.409 +		else if (color & 0x00010000)
  49.410 +		{
  49.411 +			// semi-transparent OBJ
  49.412 +			u32 back = background;
  49.413 +			u8  top2 = 0x20;
  49.414 +
  49.415 +			if ((mask & 4) && line2[x] < back)
  49.416 +			{
  49.417 +				back = line2[x];
  49.418 +				top2 = 0x04;
  49.419 +			}
  49.420 +
  49.421 +			if (top2 & (BLDMOD>>8))
  49.422 +				color = gfxAlphaBlend(color, back,
  49.423 +				                      coeff[COLEV & 0x1F],
  49.424 +				                      coeff[(COLEV >> 8) & 0x1F]);
  49.425 +			else
  49.426 +			{
  49.427 +				switch ((BLDMOD >> 6) & 3)
  49.428 +				{
  49.429 +				case 2:
  49.430 +					if (BLDMOD & top)
  49.431 +						color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
  49.432 +					break;
  49.433 +				case 3:
  49.434 +					if (BLDMOD & top)
  49.435 +						color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
  49.436 +					break;
  49.437 +				}
  49.438 +			}
  49.439 +		}
  49.440 +
  49.441 +		lineMix[x] = color;
  49.442 +	}
  49.443 +	gfxBG2Changed = 0;
  49.444 +	gfxLastVCOUNT = VCOUNT;
  49.445 +}
  49.446 +
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/src/gba/RTC.cpp	Sun Mar 04 14:33:52 2012 -0600
    50.3 @@ -0,0 +1,240 @@
    50.4 +#include <cstring>
    50.5 +
    50.6 +#include "../Port.h"
    50.7 +#include "../NLS.h"
    50.8 +#include "../common/System.h" // systemMessage
    50.9 +#include "../common/Util.h"
   50.10 +#include "../common/movie.h"
   50.11 +#include "GBAGlobals.h"
   50.12 +
   50.13 +enum RTCSTATE { IDLE, COMMAND, DATA, READDATA };
   50.14 +
   50.15 +typedef struct
   50.16 +{
   50.17 +	u8       byte0;
   50.18 +	u8       byte1;
   50.19 +	u8       byte2;
   50.20 +	u8       command;
   50.21 +	int      dataLen;
   50.22 +	int      bits;
   50.23 +	RTCSTATE state;
   50.24 +	u8       data[12];
   50.25 +	// reserved variables for future
   50.26 +	u8   reserved[12];
   50.27 +	bool reserved2;
   50.28 +	u32  reserved3;
   50.29 +} RTCCLOCKDATA;
   50.30 +
   50.31 +static RTCCLOCKDATA rtcClockData;
   50.32 +static bool         rtcEnabled = false;
   50.33 +
   50.34 +void rtcEnable(bool enable)
   50.35 +{
   50.36 +	rtcEnabled = enable;
   50.37 +}
   50.38 +
   50.39 +bool rtcIsEnabled()
   50.40 +{
   50.41 +	return rtcEnabled;
   50.42 +}
   50.43 +
   50.44 +u16 rtcRead(u32 address)
   50.45 +{
   50.46 +	if (rtcEnabled)
   50.47 +	{
   50.48 +		if (address == 0x80000c8)
   50.49 +			return rtcClockData.byte2;
   50.50 +		else if (address == 0x80000c6)
   50.51 +			return rtcClockData.byte1;
   50.52 +		else if (address == 0x80000c4)
   50.53 +		{
   50.54 +			return rtcClockData.byte0;
   50.55 +		}
   50.56 +	}
   50.57 +
   50.58 +	return READ16LE((&rom[address & 0x1FFFFFE]));
   50.59 +}
   50.60 +
   50.61 +static u8 toBCD(u8 value)
   50.62 +{
   50.63 +	value = value % 100;
   50.64 +	int l = value % 10;
   50.65 +	int h = value / 10;
   50.66 +	return h * 16 + l;
   50.67 +}
   50.68 +
   50.69 +bool rtcWrite(u32 address, u16 value)
   50.70 +{
   50.71 +	if (!rtcEnabled)
   50.72 +		return false;
   50.73 +
   50.74 +	if (address == 0x80000c8)
   50.75 +	{
   50.76 +		rtcClockData.byte2 = (u8)value; // enable ?
   50.77 +	}
   50.78 +	else if (address == 0x80000c6)
   50.79 +	{
   50.80 +		rtcClockData.byte1 = (u8)value; // read/write
   50.81 +	}
   50.82 +	else if (address == 0x80000c4)
   50.83 +	{
   50.84 +		if (rtcClockData.byte2 & 1)
   50.85 +		{
   50.86 +			if (rtcClockData.state == IDLE && rtcClockData.byte0 == 1 && value == 5)
   50.87 +			{
   50.88 +				rtcClockData.state   = COMMAND;
   50.89 +				rtcClockData.bits    = 0;
   50.90 +				rtcClockData.command = 0;
   50.91 +			}
   50.92 +			else if (!(rtcClockData.byte0 & 1) && (value & 1)) // bit transfer
   50.93 +			{
   50.94 +				rtcClockData.byte0 = (u8)value;
   50.95 +				switch (rtcClockData.state)
   50.96 +				{
   50.97 +				case COMMAND:
   50.98 +					rtcClockData.command |= ((value & 2) >> 1) << (7-rtcClockData.bits);
   50.99 +					rtcClockData.bits++;
  50.100 +					if (rtcClockData.bits == 8)
  50.101 +					{
  50.102 +						rtcClockData.bits = 0;
  50.103 +						switch (rtcClockData.command)
  50.104 +						{
  50.105 +						case 0x60:
  50.106 +							// not sure what this command does but it doesn't take parameters
  50.107 +							// maybe it is a reset or stop
  50.108 +							rtcClockData.state = IDLE;
  50.109 +							rtcClockData.bits  = 0;
  50.110 +							break;
  50.111 +						case 0x62:
  50.112 +							// this sets the control state but not sure what those values are
  50.113 +							rtcClockData.state   = READDATA;
  50.114 +							rtcClockData.dataLen = 1;
  50.115 +							break;
  50.116 +						case 0x63:
  50.117 +							rtcClockData.dataLen = 1;
  50.118 +							rtcClockData.data[0] = 0x40;
  50.119 +							rtcClockData.state   = DATA;
  50.120 +							break;
  50.121 +						case 0x65:
  50.122 +						{
  50.123 +							struct tm *newtime;
  50.124 +							time_t     long_time;
  50.125 +
  50.126 +							if (VBAMovieActive() || VBAMovieLoading())
  50.127 +							{
  50.128 +								long_time = VBAMovieGetId() + VBAMovieGetFrameCounter()/60;
  50.129 +								newtime   = gmtime(&long_time);
  50.130 +							}
  50.131 +							else
  50.132 +							{
  50.133 +								time(&long_time);      /* Get time as long integer. */
  50.134 +								newtime = localtime(&long_time); /* Convert to local time. */
  50.135 +							}
  50.136 +
  50.137 +							rtcClockData.dataLen = 7;
  50.138 +							rtcClockData.data[0] = toBCD(newtime->tm_year);
  50.139 +							rtcClockData.data[1] = toBCD(newtime->tm_mon+1);
  50.140 +							rtcClockData.data[2] = toBCD(newtime->tm_mday);
  50.141 +							rtcClockData.data[3] = 0;
  50.142 +							rtcClockData.data[4] = toBCD(newtime->tm_hour);
  50.143 +							rtcClockData.data[5] = toBCD(newtime->tm_min);
  50.144 +							rtcClockData.data[6] = toBCD(newtime->tm_sec);
  50.145 +							rtcClockData.state   = DATA;
  50.146 +							break;
  50.147 +						}
  50.148 +						case 0x67:
  50.149 +						{
  50.150 +							struct tm *newtime;
  50.151 +							time_t     long_time;
  50.152 +
  50.153 +							if (VBAMovieActive() || VBAMovieLoading())
  50.154 +							{
  50.155 +								long_time = VBAMovieGetId() + VBAMovieGetFrameCounter()/60;
  50.156 +								newtime   = gmtime(&long_time);
  50.157 +							}
  50.158 +							else
  50.159 +							{
  50.160 +								time(&long_time);      /* Get time as long integer. */
  50.161 +								newtime = localtime(&long_time); /* Convert to local time. */
  50.162 +							}
  50.163 +
  50.164 +							rtcClockData.dataLen = 3;
  50.165 +							rtcClockData.data[0] = toBCD(newtime->tm_hour);
  50.166 +							rtcClockData.data[1] = toBCD(newtime->tm_min);
  50.167 +							rtcClockData.data[2] = toBCD(newtime->tm_sec);
  50.168 +							rtcClockData.state   = DATA;
  50.169 +							break;
  50.170 +						}
  50.171 +						default:
  50.172 +							systemMessage(0, N_("Unknown RTC command %02x"), rtcClockData.command);
  50.173 +							rtcClockData.state = IDLE;
  50.174 +							break;
  50.175 +						}
  50.176 +					}
  50.177 +					break;
  50.178 +				case DATA:
  50.179 +					if (rtcClockData.byte1 & 2)
  50.180 +					{}
  50.181 +					else
  50.182 +					{
  50.183 +						rtcClockData.byte0 = (rtcClockData.byte0 & ~2) |
  50.184 +						                     ((rtcClockData.data[rtcClockData.bits >> 3] >>
  50.185 +						                       (rtcClockData.bits & 7)) & 1)*2;
  50.186 +						rtcClockData.bits++;
  50.187 +						if (rtcClockData.bits == 8*rtcClockData.dataLen)
  50.188 +						{
  50.189 +							rtcClockData.bits  = 0;
  50.190 +							rtcClockData.state = IDLE;
  50.191 +						}
  50.192 +					}
  50.193 +					break;
  50.194 +				case READDATA:
  50.195 +					if (!(rtcClockData.byte1 & 2))
  50.196 +					{}
  50.197 +					else
  50.198 +					{
  50.199 +						rtcClockData.data[rtcClockData.bits >> 3] =
  50.200 +						    (rtcClockData.data[rtcClockData.bits >> 3] >> 1) |
  50.201 +						    ((value << 6) & 128);
  50.202 +						rtcClockData.bits++;
  50.203 +						if (rtcClockData.bits == 8*rtcClockData.dataLen)
  50.204 +						{
  50.205 +							rtcClockData.bits  = 0;
  50.206 +							rtcClockData.state = IDLE;
  50.207 +						}
  50.208 +					}
  50.209 +					break;
  50.210 +				default:
  50.211 +					break;
  50.212 +				}
  50.213 +			}
  50.214 +			else
  50.215 +				rtcClockData.byte0 = (u8)value;
  50.216 +		}
  50.217 +	}
  50.218 +	return true;
  50.219 +}
  50.220 +
  50.221 +void rtcReset()
  50.222 +{
  50.223 +	memset(&rtcClockData, 0, sizeof(rtcClockData));
  50.224 +
  50.225 +	rtcClockData.byte0   = 0;
  50.226 +	rtcClockData.byte1   = 0;
  50.227 +	rtcClockData.byte2   = 0;
  50.228 +	rtcClockData.command = 0;
  50.229 +	rtcClockData.dataLen = 0;
  50.230 +	rtcClockData.bits    = 0;
  50.231 +	rtcClockData.state   = IDLE;
  50.232 +}
  50.233 +
  50.234 +void rtcSaveGame(gzFile gzFile)
  50.235 +{
  50.236 +	utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData));
  50.237 +}
  50.238 +
  50.239 +void rtcReadGame(gzFile gzFile)
  50.240 +{
  50.241 +	utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData));
  50.242 +}
  50.243 +
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/src/gba/RTC.h	Sun Mar 04 14:33:52 2012 -0600
    51.3 @@ -0,0 +1,17 @@
    51.4 +#ifndef VBA_RTC_H
    51.5 +#define VBA_RTC_H
    51.6 +
    51.7 +#if _MSC_VER > 1000
    51.8 +#pragma once
    51.9 +#endif // _MSC_VER > 1000
   51.10 +
   51.11 +extern u16 rtcRead(u32 address);
   51.12 +extern bool rtcWrite(u32 address, u16 value);
   51.13 +extern void rtcEnable(bool);
   51.14 +extern bool rtcIsEnabled();
   51.15 +extern void rtcReset();
   51.16 +
   51.17 +extern void rtcReadGame(gzFile gzFile);
   51.18 +extern void rtcSaveGame(gzFile gzFile);
   51.19 +
   51.20 +#endif // VBA_RTC_H
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/src/gba/Sram.cpp	Sun Mar 04 14:33:52 2012 -0600
    52.3 @@ -0,0 +1,15 @@
    52.4 +#include "../common/System.h"
    52.5 +#include "Flash.h"
    52.6 +#include "Sram.h"
    52.7 +
    52.8 +u8 sramRead(u32 address)
    52.9 +{
   52.10 +	return flashSaveMemory[address & 0xFFFF];
   52.11 +}
   52.12 +
   52.13 +void sramWrite(u32 address, u8 byte)
   52.14 +{
   52.15 +	flashSaveMemory[address & 0xFFFF] = byte;
   52.16 +	systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
   52.17 +}
   52.18 +
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/src/gba/Sram.h	Sun Mar 04 14:33:52 2012 -0600
    53.3 @@ -0,0 +1,11 @@
    53.4 +#ifndef VBA_SRAM_H
    53.5 +#define VBA_SRAM_H
    53.6 +
    53.7 +#if _MSC_VER > 1000
    53.8 +#pragma once
    53.9 +#endif // _MSC_VER > 1000
   53.10 +
   53.11 +extern u8 sramRead(u32 address);
   53.12 +extern void sramWrite(u32 address, u8 byte);
   53.13 +
   53.14 +#endif // VBA_SRAM_H
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/src/gba/agbprint.cpp	Sun Mar 04 14:33:52 2012 -0600
    54.3 @@ -0,0 +1,82 @@
    54.4 +#include <cstdio>
    54.5 +#include <cstring>
    54.6 +
    54.7 +#include "GBAGlobals.h"
    54.8 +
    54.9 +extern void (*dbgOutput)(char *, u32);
   54.10 +extern int systemVerbose;
   54.11 +
   54.12 +static bool agbPrintEnabled = false;
   54.13 +static bool agbPrintProtect = false;
   54.14 +
   54.15 +bool agbPrintWrite(u32 address, u16 value)
   54.16 +{
   54.17 +	if (agbPrintEnabled)
   54.18 +	{
   54.19 +		if (address == 0x9fe2ffe) // protect
   54.20 +		{
   54.21 +			agbPrintProtect = (value != 0);
   54.22 +			debuggerWriteHalfWord(address, value);
   54.23 +			return true;
   54.24 +		}
   54.25 +		else
   54.26 +		{
   54.27 +			if (agbPrintProtect &&
   54.28 +			    ((address >= 0x9fe20f8 && address <= 0x9fe20ff) // control structure
   54.29 +			     || (address >= 0x8fd0000 && address <= 0x8fdffff)
   54.30 +			     || (address >= 0x9fd0000 && address <= 0x9fdffff)))
   54.31 +			{
   54.32 +				debuggerWriteHalfWord(address, value);
   54.33 +				return true;
   54.34 +			}
   54.35 +		}
   54.36 +	}
   54.37 +	return false;
   54.38 +}
   54.39 +
   54.40 +void agbPrintReset()
   54.41 +{
   54.42 +	agbPrintProtect = false;
   54.43 +}
   54.44 +
   54.45 +void agbPrintEnable(bool enable)
   54.46 +{
   54.47 +	agbPrintEnabled = enable;
   54.48 +}
   54.49 +
   54.50 +bool agbPrintIsEnabled()
   54.51 +{
   54.52 +	return agbPrintEnabled;
   54.53 +}
   54.54 +
   54.55 +void agbPrintFlush()
   54.56 +{
   54.57 +	u16 get = debuggerReadHalfWord(0x9fe20fc);
   54.58 +	u16 put = debuggerReadHalfWord(0x9fe20fe);
   54.59 +
   54.60 +	u32 address = (debuggerReadHalfWord(0x9fe20fa) << 16);
   54.61 +	if (address != 0xfd0000 && address != 0x1fd0000)
   54.62 +	{
   54.63 +		dbgOutput("Did you forget to call AGBPrintInit?\n", 0);
   54.64 +		// get rid of the text otherwise we will continue to be called
   54.65 +		debuggerWriteHalfWord(0x9fe20fc, put);
   54.66 +		return;
   54.67 +	}
   54.68 +
   54.69 +	u8 *data = &rom[address];
   54.70 +
   54.71 +	while (get != put)
   54.72 +	{
   54.73 +		char c = data[get++];
   54.74 +		char s[2];
   54.75 +		s[0] = c;
   54.76 +		s[1] = 0;
   54.77 +
   54.78 +		if (systemVerbose & VERBOSE_AGBPRINT)
   54.79 +			dbgOutput(s, 0);
   54.80 +		if (c == '\n')
   54.81 +			break;
   54.82 +	}
   54.83 +	debuggerWriteHalfWord(0x9fe20fc, get);
   54.84 +}
   54.85 +
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/src/gba/agbprint.h	Sun Mar 04 14:33:52 2012 -0600
    55.3 @@ -0,0 +1,14 @@
    55.4 +#ifndef VBA_AGBPRINT_H
    55.5 +#define VBA_AGBPRINT_H
    55.6 +
    55.7 +#if _MSC_VER > 1000
    55.8 +#pragma once
    55.9 +#endif // _MSC_VER > 1000
   55.10 +
   55.11 +extern void agbPrintEnable(bool);
   55.12 +extern bool agbPrintIsEnabled();
   55.13 +extern void agbPrintReset();
   55.14 +extern bool agbPrintWrite(u32, u16);
   55.15 +extern void agbPrintFlush();
   55.16 +
   55.17 +#endif // VBA_AGBPRINT_H
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/src/gba/arm-new.h	Sun Mar 04 14:33:52 2012 -0600
    56.3 @@ -0,0 +1,7453 @@
    56.4 +#ifdef BKPT_SUPPORT
    56.5 +#define CONSOLE_OUTPUT(a, b) \
    56.6 +    extern void (*dbgOutput)(char *, u32); \
    56.7 +    if ((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) { \
    56.8 +		dbgOutput((a), (b)); \
    56.9 +	}
   56.10 +#else
   56.11 +#define CONSOLE_OUTPUT(a, b)
   56.12 +#endif
   56.13 +
   56.14 +#define OP_AND \
   56.15 +    reg[dest].I = reg[(opcode >> 16) & 15].I & value; \
   56.16 +    CONSOLE_OUTPUT(NULL, reg[2].I);
   56.17 +
   56.18 +#define OP_ANDS \
   56.19 +    reg[dest].I = reg[(opcode >> 16) & 15].I & value; \
   56.20 +      \
   56.21 +    N_FLAG = (reg[dest].I & 0x80000000) ? true : false; \
   56.22 +    Z_FLAG = (reg[dest].I) ? false : true; \
   56.23 +    C_FLAG = C_OUT;
   56.24 +
   56.25 +#define OP_EOR \
   56.26 +    reg[dest].I = reg[(opcode >> 16) & 15].I ^ value;
   56.27 +
   56.28 +#define OP_EORS \
   56.29 +    reg[dest].I = reg[(opcode >> 16) & 15].I ^ value; \
   56.30 +      \
   56.31 +    N_FLAG = (reg[dest].I & 0x80000000) ? true : false; \
   56.32 +    Z_FLAG = (reg[dest].I) ? false : true; \
   56.33 +    C_FLAG = C_OUT;
   56.34 +#ifdef C_CORE
   56.35 +#define NEG(i) ((i) >> 31)
   56.36 +#define POS(i) ((~(i)) >> 31)
   56.37 +#define ADDCARRY(a, b, c) \
   56.38 +    C_FLAG = ((NEG(a) & NEG(b)) | \
   56.39 +              (NEG(a) & POS(c)) | \
   56.40 +              (NEG(b) & POS(c))) ? true : false;
   56.41 +#define ADDOVERFLOW(a, b, c) \
   56.42 +    V_FLAG = ((NEG(a) & NEG(b) & POS(c)) | \
   56.43 +              (POS(a) & POS(b) & NEG(c))) ? true : false;
   56.44 +#define SUBCARRY(a, b, c) \
   56.45 +    C_FLAG = ((NEG(a) & POS(b)) | \
   56.46 +              (NEG(a) & POS(c)) | \
   56.47 +              (POS(b) & POS(c))) ? true : false;
   56.48 +#define SUBOVERFLOW(a, b, c) \
   56.49 +    V_FLAG = ((NEG(a) & POS(b) & POS(c)) | \
   56.50 +              (POS(a) & NEG(b) & NEG(c))) ? true : false;
   56.51 +#define OP_SUB \
   56.52 +	{ \
   56.53 +		reg[dest].I = reg[base].I - value; \
   56.54 +	}
   56.55 +#define OP_SUBS \
   56.56 +	{ \
   56.57 +		u32 lhs = reg[base].I; \
   56.58 +		u32 rhs = value; \
   56.59 +		u32 res = lhs - rhs; \
   56.60 +		reg[dest].I = res; \
   56.61 +		Z_FLAG		= (res == 0) ? true : false; \
   56.62 +		N_FLAG		= NEG(res) ? true : false; \
   56.63 +		SUBCARRY(lhs, rhs, res); \
   56.64 +		SUBOVERFLOW(lhs, rhs, res); \
   56.65 +	}
   56.66 +#define OP_RSB \
   56.67 +	{ \
   56.68 +		reg[dest].I = value - reg[base].I; \
   56.69 +	}
   56.70 +#define OP_RSBS \
   56.71 +	{ \
   56.72 +		u32 lhs = reg[base].I; \
   56.73 +		u32 rhs = value; \
   56.74 +		u32 res = rhs - lhs; \
   56.75 +		reg[dest].I = res; \
   56.76 +		Z_FLAG		= (res == 0) ? true : false; \
   56.77 +		N_FLAG		= NEG(res) ? true : false; \
   56.78 +		SUBCARRY(rhs, lhs, res); \
   56.79 +		SUBOVERFLOW(rhs, lhs, res); \
   56.80 +	}
   56.81 +#define OP_ADD \
   56.82 +	{ \
   56.83 +		reg[dest].I = reg[base].I + value; \
   56.84 +	}
   56.85 +#define OP_ADDS \
   56.86 +	{ \
   56.87 +		u32 lhs = reg[base].I; \
   56.88 +		u32 rhs = value; \
   56.89 +		u32 res = lhs + rhs; \
   56.90 +		reg[dest].I = res; \
   56.91 +		Z_FLAG		= (res == 0) ? true : false; \
   56.92 +		N_FLAG		= NEG(res) ? true : false; \
   56.93 +		ADDCARRY(lhs, rhs, res); \
   56.94 +		ADDOVERFLOW(lhs, rhs, res); \
   56.95 +	}
   56.96 +#define OP_ADC \
   56.97 +	{ \
   56.98 +		reg[dest].I = reg[base].I + value + (u32)C_FLAG; \
   56.99 +	}
  56.100 +#define OP_ADCS \
  56.101 +	{ \
  56.102 +		u32 lhs = reg[base].I; \
  56.103 +		u32 rhs = value; \
  56.104 +		u32 res = lhs + rhs + (u32)C_FLAG; \
  56.105 +		reg[dest].I = res; \
  56.106 +		Z_FLAG		= (res == 0) ? true : false; \
  56.107 +		N_FLAG		= NEG(res) ? true : false; \
  56.108 +		ADDCARRY(lhs, rhs, res); \
  56.109 +		ADDOVERFLOW(lhs, rhs, res); \
  56.110 +	}
  56.111 +#define OP_SBC \
  56.112 +	{ \
  56.113 +		reg[dest].I = reg[base].I - value - !((u32)C_FLAG); \
  56.114 +	}
  56.115 +#define OP_SBCS \
  56.116 +	{ \
  56.117 +		u32 lhs = reg[base].I; \
  56.118 +		u32 rhs = value; \
  56.119 +		u32 res = lhs - rhs - !((u32)C_FLAG); \
  56.120 +		reg[dest].I = res; \
  56.121 +		Z_FLAG		= (res == 0) ? true : false; \
  56.122 +		N_FLAG		= NEG(res) ? true : false; \
  56.123 +		SUBCARRY(lhs, rhs, res); \
  56.124 +		SUBOVERFLOW(lhs, rhs, res); \
  56.125 +	}
  56.126 +#define OP_RSC \
  56.127 +	{ \
  56.128 +		reg[dest].I = value - reg[base].I - !((u32)C_FLAG); \
  56.129 +	}
  56.130 +#define OP_RSCS \
  56.131 +	{ \
  56.132 +		u32 lhs = reg[base].I; \
  56.133 +		u32 rhs = value; \
  56.134 +		u32 res = rhs - lhs - !((u32)C_FLAG); \
  56.135 +		reg[dest].I = res; \
  56.136 +		Z_FLAG		= (res == 0) ? true : false; \
  56.137 +		N_FLAG		= NEG(res) ? true : false; \
  56.138 +		SUBCARRY(rhs, lhs, res); \
  56.139 +		SUBOVERFLOW(rhs, lhs, res); \
  56.140 +	}
  56.141 +#define OP_CMP \
  56.142 +	{ \
  56.143 +		u32 lhs = reg[base].I; \
  56.144 +		u32 rhs = value; \
  56.145 +		u32 res = lhs - rhs; \
  56.146 +		Z_FLAG = (res == 0) ? true : false; \
  56.147 +		N_FLAG = NEG(res) ? true : false; \
  56.148 +		SUBCARRY(lhs, rhs, res); \
  56.149 +		SUBOVERFLOW(lhs, rhs, res); \
  56.150 +	}
  56.151 +#define OP_CMN \
  56.152 +	{ \
  56.153 +		u32 lhs = reg[base].I; \
  56.154 +		u32 rhs = value; \
  56.155 +		u32 res = lhs + rhs; \
  56.156 +		Z_FLAG = (res == 0) ? true : false; \
  56.157 +		N_FLAG = NEG(res) ? true : false; \
  56.158 +		ADDCARRY(lhs, rhs, res); \
  56.159 +		ADDOVERFLOW(lhs, rhs, res); \
  56.160 +	}
  56.161 +
  56.162 +#define LOGICAL_LSL_REG \
  56.163 +	{ \
  56.164 +		u32 v = reg[opcode & 0x0f].I; \
  56.165 +		C_OUT = (v >> (32 - shift)) & 1 ? true : false; \
  56.166 +		value = v << shift; \
  56.167 +	}
  56.168 +#define LOGICAL_LSR_REG \
  56.169 +	{ \
  56.170 +		u32 v = reg[opcode & 0x0f].I; \
  56.171 +		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
  56.172 +		value = v >> shift; \
  56.173 +	}
  56.174 +#define LOGICAL_ASR_REG \
  56.175 +	{ \
  56.176 +		u32 v = reg[opcode & 0x0f].I; \
  56.177 +		C_OUT = ((s32)v >> (int)(shift - 1)) & 1 ? true : false; \
  56.178 +		value = (s32)v >> (int)shift; \
  56.179 +	}
  56.180 +#define LOGICAL_ROR_REG \
  56.181 +	{ \
  56.182 +		u32 v = reg[opcode & 0x0f].I; \
  56.183 +		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
  56.184 +		value = ((v << (32 - shift)) | \
  56.185 +		         (v >> shift)); \
  56.186 +	}
  56.187 +#define LOGICAL_RRX_REG \
  56.188 +	{ \
  56.189 +		u32 v = reg[opcode & 0x0f].I; \
  56.190 +		shift = (int)C_FLAG; \
  56.191 +		C_OUT = (v  & 1) ? true : false; \
  56.192 +		value = ((v >> 1) | \
  56.193 +		         (shift << 31)); \
  56.194 +	}
  56.195 +#define LOGICAL_ROR_IMM \
  56.196 +	{ \
  56.197 +		u32 v = opcode & 0xff; \
  56.198 +		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
  56.199 +		value = ((v << (32 - shift)) | \
  56.200 +		         (v >> shift)); \
  56.201 +	}
  56.202 +#define ARITHMETIC_LSL_REG \
  56.203 +	{ \
  56.204 +		u32 v = reg[opcode & 0x0f].I; \
  56.205 +		value = v << shift; \
  56.206 +	}
  56.207 +#define ARITHMETIC_LSR_REG \
  56.208 +	{ \
  56.209 +		u32 v = reg[opcode & 0x0f].I; \
  56.210 +		value = v >> shift; \
  56.211 +	}
  56.212 +#define ARITHMETIC_ASR_REG \
  56.213 +	{ \
  56.214 +		u32 v = reg[opcode & 0x0f].I; \
  56.215 +		value = (s32)v >> (int)shift; \
  56.216 +	}
  56.217 +#define ARITHMETIC_ROR_REG \
  56.218 +	{ \
  56.219 +		u32 v = reg[opcode & 0x0f].I; \
  56.220 +		value = ((v << (32 - shift)) | \
  56.221 +		         (v >> shift)); \
  56.222 +	}
  56.223 +#define ARITHMETIC_RRX_REG \
  56.224 +	{ \
  56.225 +		u32 v = reg[opcode & 0x0f].I; \
  56.226 +		shift = (int)C_FLAG; \
  56.227 +		value = ((v >> 1) | \
  56.228 +		         (shift << 31)); \
  56.229 +	}
  56.230 +#define ARITHMETIC_ROR_IMM \
  56.231 +	{ \
  56.232 +		u32 v = opcode & 0xff; \
  56.233 +		value = ((v << (32 - shift)) | \
  56.234 +		         (v >> shift)); \
  56.235 +	}
  56.236 +#define ROR_IMM_MSR \
  56.237 +	{ \
  56.238 +		u32 v = opcode & 0xff; \
  56.239 +		value = ((v << (32 - shift)) | \
  56.240 +		         (v >> shift)); \
  56.241 +	}
  56.242 +#define ROR_VALUE \
  56.243 +	{ \
  56.244 +		value = ((value << (32 - shift)) | \
  56.245 +		         (value >> shift)); \
  56.246 +	}
  56.247 +#define RCR_VALUE \
  56.248 +	{ \
  56.249 +		shift = (int)C_FLAG; \
  56.250 +		value = ((value >> 1) | \
  56.251 +		         (shift << 31)); \
  56.252 +	}
  56.253 +#else
  56.254 +#ifdef __GNUC__
  56.255 +		#ifdef __POWERPC__
  56.256 +			#define OP_SUB \
  56.257 +	{ \
  56.258 +		reg[dest].I = reg[base].I - value; \
  56.259 +	}
  56.260 +			#define OP_SUBS \
  56.261 +	{ \
  56.262 +		register int Flags;                             \
  56.263 +		register int Result;                            \
  56.264 +		asm volatile ("subco. %0, %2, %3\n"              \
  56.265 +		              "mcrxr cr1\n"                       \
  56.266 +		              "mfcr %1\n"                         \
  56.267 +					  : "=r" (Result),                    \
  56.268 +		              "=r" (Flags)                      \
  56.269 +					  : "r" (reg[base].I),                \
  56.270 +		              "r" (value)                       \
  56.271 +		              );                                  \
  56.272 +		reg[dest].I = Result;                           \
  56.273 +		Z_FLAG		= (Flags >> 29) & 1;                     \
  56.274 +		N_FLAG		= (Flags >> 31) & 1;                     \
  56.275 +		C_FLAG		= (Flags >> 25) & 1;                     \
  56.276 +		V_FLAG		= (Flags >> 26) & 1;                     \
  56.277 +	}
  56.278 +			#define OP_RSB \
  56.279 +	{ \
  56.280 +		reg[dest].I = value - reg[base].I; \
  56.281 +	}
  56.282 +			#define OP_RSBS \
  56.283 +	{ \
  56.284 +		register int Flags;                             \
  56.285 +		register int Result;                            \
  56.286 +		asm volatile ("subfco. %0, %2, %3\n"             \
  56.287 +		              "mcrxr cr1\n"                       \
  56.288 +		              "mfcr %1\n"                         \
  56.289 +					  : "=r" (Result),                    \
  56.290 +		              "=r" (Flags)                      \
  56.291 +					  : "r" (reg[base].I),                \
  56.292 +		              "r" (value)                       \
  56.293 +		              );                                  \
  56.294 +		reg[dest].I = Result;                           \
  56.295 +		Z_FLAG		= (Flags >> 29) & 1;                     \
  56.296 +		N_FLAG		= (Flags >> 31) & 1;                     \
  56.297 +		C_FLAG		= (Flags >> 25) & 1;                     \
  56.298 +		V_FLAG		= (Flags >> 26) & 1;                     \
  56.299 +	}
  56.300 +			#define OP_ADD \
  56.301 +	{ \
  56.302 +		reg[dest].I = reg[base].I + value; \
  56.303 +	}
  56.304 +
  56.305 +			#define OP_ADDS \
  56.306 +	{ \
  56.307 +		register int Flags;                             \
  56.308 +		register int Result;                            \
  56.309 +		asm volatile ("addco. %0, %2, %3\n"              \
  56.310 +		              "mcrxr cr1\n"                       \
  56.311 +		              "mfcr %1\n"                         \
  56.312 +					  : "=r" (Result),                    \
  56.313 +		              "=r" (Flags)                      \
  56.314 +					  : "r" (reg[base].I),                \
  56.315 +		              "r" (value)                       \
  56.316 +		              );                                  \
  56.317 +		reg[dest].I = Result;                           \
  56.318 +		Z_FLAG		= (Flags >> 29) & 1;                     \
  56.319 +		N_FLAG		= (Flags >> 31) & 1;                     \
  56.320 +		C_FLAG		= (Flags >> 25) & 1;                     \
  56.321 +		V_FLAG		= (Flags >> 26) & 1;                     \
  56.322 +	}
  56.323 +			#define OP_ADC \
  56.324 +	{ \
  56.325 +		reg[dest].I = reg[base].I + value + (u32)C_FLAG; \
  56.326 +	}
  56.327 +			#define OP_ADCS \
  56.328 +	{ \
  56.329 +		register int Flags;                             \
  56.330 +		register int Result;                            \
  56.331 +		asm volatile ("mtspr xer, %4\n"                  \
  56.332 +		              "addeo. %0, %2, %3\n"              \
  56.333 +		              "mcrxr cr1\n"                      \
  56.334 +		              "mfcr      %1\n"                   \
  56.335 +					  : "=r" (Result),                   \
  56.336 +		              "=r" (Flags)                     \
  56.337 +					  : "r" (reg[base].I),               \
  56.338 +		              "r" (value),                     \
  56.339 +		              "r" (C_FLAG << 29)               \
  56.340 +		              );                                 \
  56.341 +		reg[dest].I = Result;                           \
  56.342 +		Z_FLAG		= (Flags >> 29) & 1;                     \
  56.343 +		N_FLAG		= (Flags >> 31) & 1;                     \
  56.344 +		C_FLAG		= (Flags >> 25) & 1;                     \
  56.345 +		V_FLAG		= (Flags >> 26) & 1;                     \
  56.346 +	}
  56.347 +			#define OP_SBC \
  56.348 +	{ \
  56.349 +		reg[dest].I = reg[base].I - value - (C_FLAG ^ 1); \
  56.350 +	}
  56.351 +			#define OP_SBCS \
  56.352 +	{ \
  56.353 +		register int Flags;                             \
  56.354 +		register int Result;                            \
  56.355 +		asm volatile ("mtspr xer, %4\n"                  \
  56.356 +		              "subfeo. %0, %3, %2\n"             \
  56.357 +		              "mcrxr cr1\n"                      \
  56.358 +		              "mfcr      %1\n"                   \
  56.359 +					  : "=r" (Result),                   \
  56.360 +		              "=r" (Flags)                     \
  56.361 +					  : "r" (reg[base].I),               \
  56.362 +		              "r" (value),                     \
  56.363 +		              "r" (C_FLAG << 29)               \
  56.364 +		              );                                 \
  56.365 +		reg[dest].I = Result;                           \
  56.366 +		Z_FLAG		= (Flags >> 29) & 1;                     \
  56.367 +		N_FLAG		= (Flags >> 31) & 1;                     \
  56.368 +		C_FLAG		= (Flags >> 25) & 1;                     \
  56.369 +		V_FLAG		= (Flags >> 26) & 1;                     \
  56.370 +	}
  56.371 +			#define OP_RSC \
  56.372 +	{ \
  56.373 +		reg[dest].I = value - reg[base].I - (C_FLAG ^ 1); \
  56.374 +	}
  56.375 +			#define OP_RSCS \
  56.376 +	{ \
  56.377 +		register int Flags;                             \
  56.378 +		register int Result;                            \
  56.379 +		asm volatile ("mtspr xer, %4\n"                  \
  56.380 +		              "subfeo. %0, %2, %3\n"             \
  56.381 +		              "mcrxr cr1\n"                      \
  56.382 +		              "mfcr      %1\n"                   \
  56.383 +					  : "=r" (Result),                   \
  56.384 +		              "=r" (Flags)                     \
  56.385 +					  : "r" (reg[base].I),               \
  56.386 +		              "r" (value),                     \
  56.387 +		              "r" (C_FLAG << 29)               \
  56.388 +		              );                                 \
  56.389 +		reg[dest].I = Result;                           \
  56.390 +		Z_FLAG		= (Flags >> 29) & 1;                     \
  56.391 +		N_FLAG		= (Flags >> 31) & 1;                     \
  56.392 +		C_FLAG		= (Flags >> 25) & 1;                     \
  56.393 +		V_FLAG		= (Flags >> 26) & 1;                     \
  56.394 +	}
  56.395 +			#define OP_CMP \
  56.396 +	{ \
  56.397 +		register int Flags;                             \
  56.398 +		register int Result;                            \
  56.399 +		asm volatile ("subco. %0, %2, %3\n"              \
  56.400 +		              "mcrxr cr1\n"                       \
  56.401 +		              "mfcr %1\n"                         \
  56.402 +					  : "=r" (Result),                    \
  56.403 +		              "=r" (Flags)                      \
  56.404 +					  : "r" (reg[base].I),                \
  56.405 +		              "r" (value)                       \
  56.406 +		              );                                  \
  56.407 +		Z_FLAG = (Flags >> 29) & 1;                     \
  56.408 +		N_FLAG = (Flags >> 31) & 1;                     \
  56.409 +		C_FLAG = (Flags >> 25) & 1;                     \
  56.410 +		V_FLAG = (Flags >> 26) & 1;                     \
  56.411 +	}
  56.412 +			#define OP_CMN \
  56.413 +	{ \
  56.414 +		register int Flags;                             \
  56.415 +		register int Result;                            \
  56.416 +		asm volatile ("addco. %0, %2, %3\n"              \
  56.417 +		              "mcrxr cr1\n"                       \
  56.418 +		              "mfcr %1\n"                         \
  56.419 +					  : "=r" (Result),                    \
  56.420 +		              "=r" (Flags)                      \
  56.421 +					  : "r" (reg[base].I),                \
  56.422 +		              "r" (value)                       \
  56.423 +		              );                                  \
  56.424 +		Z_FLAG = (Flags >> 29) & 1;                     \
  56.425 +		N_FLAG = (Flags >> 31) & 1;                     \
  56.426 +		C_FLAG = (Flags >> 25) & 1;                     \
  56.427 +		V_FLAG = (Flags >> 26) & 1;                     \
  56.428 +	}
  56.429 +
  56.430 +			#define LOGICAL_LSL_REG \
  56.431 +	{ \
  56.432 +		u32 v = reg[opcode & 0x0f].I; \
  56.433 +		C_OUT = (v >> (32 - shift)) & 1 ? true : false; \
  56.434 +		value = v << shift; \
  56.435 +	}
  56.436 +			#define LOGICAL_LSR_REG \
  56.437 +	{ \
  56.438 +		u32 v = reg[opcode & 0x0f].I; \
  56.439 +		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
  56.440 +		value = v >> shift; \
  56.441 +	}
  56.442 +			#define LOGICAL_ASR_REG \
  56.443 +	{ \
  56.444 +		u32 v = reg[opcode & 0x0f].I; \
  56.445 +		C_OUT = ((s32)v >> (int)(shift - 1)) & 1 ? true : false; \
  56.446 +		value = (s32)v >> (int)shift; \
  56.447 +	}
  56.448 +			#define LOGICAL_ROR_REG \
  56.449 +	{ \
  56.450 +		u32 v = reg[opcode & 0x0f].I; \
  56.451 +		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
  56.452 +		value = ((v << (32 - shift)) | \
  56.453 +		         (v >> shift)); \
  56.454 +	}
  56.455 +			#define LOGICAL_RRX_REG \
  56.456 +	{ \
  56.457 +		u32 v = reg[opcode & 0x0f].I; \
  56.458 +		shift = (int)C_FLAG; \
  56.459 +		C_OUT = (v  & 1) ? true : false; \
  56.460 +		value = ((v >> 1) | \
  56.461 +		         (shift << 31)); \
  56.462 +	}
  56.463 +			#define LOGICAL_ROR_IMM \
  56.464 +	{ \
  56.465 +		u32 v = opcode & 0xff; \
  56.466 +		C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
  56.467 +		value = ((v << (32 - shift)) | \
  56.468 +		         (v >> shift)); \
  56.469 +	}
  56.470 +			#define ARITHMETIC_LSL_REG \
  56.471 +	{ \
  56.472 +		u32 v = reg[opcode & 0x0f].I; \
  56.473 +		value = v << shift; \
  56.474 +	}
  56.475 +			#define ARITHMETIC_LSR_REG \
  56.476 +	{ \
  56.477 +		u32 v = reg[opcode & 0x0f].I; \
  56.478 +		value = v >> shift; \
  56.479 +	}
  56.480 +			#define ARITHMETIC_ASR_REG \
  56.481 +	{ \
  56.482 +		u32 v = reg[opcode & 0x0f].I; \
  56.483 +		value = (s32)v >> (int)shift; \
  56.484 +	}
  56.485 +			#define ARITHMETIC_ROR_REG \
  56.486 +	{ \
  56.487 +		u32 v = reg[opcode & 0x0f].I; \
  56.488 +		value = ((v << (32 - shift)) | \
  56.489 +		         (v >> shift)); \
  56.490 +	}
  56.491 +			#define ARITHMETIC_RRX_REG \
  56.492 +	{ \
  56.493 +		u32 v = reg[opcode & 0x0f].I; \
  56.494 +		shift = (int)C_FLAG; \
  56.495 +		value = ((v >> 1) | \
  56.496 +		         (shift << 31)); \
  56.497 +	}
  56.498 +			#define ARITHMETIC_ROR_IMM \
  56.499 +	{ \
  56.500 +		u32 v = opcode & 0xff; \
  56.501 +		value = ((v << (32 - shift)) | \
  56.502 +		         (v >> shift)); \
  56.503 +	}
  56.504 +			#define ROR_IMM_MSR \
  56.505 +	{ \
  56.506 +		u32 v = opcode & 0xff; \
  56.507 +		value = ((v << (32 - shift)) | \
  56.508 +		         (v >> shift)); \
  56.509 +	}
  56.510 +			#define ROR_VALUE \
  56.511 +	{ \
  56.512 +		value = ((value << (32 - shift)) | \
  56.513 +		         (value >> shift)); \
  56.514 +	}
  56.515 +			#define RCR_VALUE \
  56.516 +	{ \
  56.517 +		shift = (int)C_FLAG; \
  56.518 +		value = ((value >> 1) | \
  56.519 +		         (shift << 31)); \
  56.520 +	}
  56.521 +#else
  56.522 +#define OP_SUB \
  56.523 +    asm ("sub %1, %%ebx;" \
  56.524 +		 : "=b" (reg[dest].I) \
  56.525 +		 : "r" (value), "b" (reg[base].I));
  56.526 +
  56.527 +#define OP_SUBS \
  56.528 +    asm ("sub %1, %%ebx;" \
  56.529 +         "setsb N_FLAG;" \
  56.530 +         "setzb Z_FLAG;" \
  56.531 +         "setncb C_FLAG;" \
  56.532 +         "setob V_FLAG;" \
  56.533 +		 : "=b" (reg[dest].I) \
  56.534 +		 : "r" (value), "b" (reg[base].I));
  56.535 +
  56.536 +#define OP_RSB \
  56.537 +    asm  ("sub %1, %%ebx;" \
  56.538 +		  : "=b" (reg[dest].I) \
  56.539 +		  : "r" (reg[base].I), "b" (value));
  56.540 +
  56.541 +#define OP_RSBS \
  56.542 +    asm  ("sub %1, %%ebx;" \
  56.543 +          "setsb N_FLAG;" \
  56.544 +          "setzb Z_FLAG;" \
  56.545 +          "setncb C_FLAG;" \
  56.546 +          "setob V_FLAG;" \
  56.547 +		  : "=b" (reg[dest].I) \
  56.548 +		  : "r" (reg[base].I), "b" (value));
  56.549 +
  56.550 +#define OP_ADD \
  56.551 +    asm  ("add %1, %%ebx;" \
  56.552 +		  : "=b" (reg[dest].I) \
  56.553 +		  : "r" (value), "b" (reg[base].I));
  56.554 +
  56.555 +#define OP_ADDS \
  56.556 +    asm  ("add %1, %%ebx;" \
  56.557 +          "setsb N_FLAG;" \
  56.558 +          "setzb Z_FLAG;" \
  56.559 +          "setcb C_FLAG;" \
  56.560 +          "setob V_FLAG;" \
  56.561 +		  : "=b" (reg[dest].I) \
  56.562 +		  : "r" (value), "b" (reg[base].I));
  56.563 +
  56.564 +#define OP_ADC \
  56.565 +    asm  ("bt $0, C_FLAG;" \
  56.566 +          "adc %1, %%ebx;" \
  56.567 +		  : "=b" (reg[dest].I) \
  56.568 +		  : "r" (value), "b" (reg[base].I));
  56.569 +
  56.570 +#define OP_ADCS \
  56.571 +    asm  ("bt $0, C_FLAG;" \
  56.572 +          "adc %1, %%ebx;" \
  56.573 +          "setsb N_FLAG;" \
  56.574 +          "setzb Z_FLAG;" \
  56.575 +          "setcb C_FLAG;" \
  56.576 +          "setob V_FLAG;" \
  56.577 +		  : "=b" (reg[dest].I) \
  56.578 +		  : "r" (value), "b" (reg[base].I));
  56.579 +
  56.580 +#define OP_SBC \
  56.581 +    asm  ("bt $0, C_FLAG;" \
  56.582 +          "cmc;" \
  56.583 +          "sbb %1, %%ebx;" \
  56.584 +		  : "=b" (reg[dest].I) \
  56.585 +		  : "r" (value), "b" (reg[base].I));
  56.586 +
  56.587 +#define OP_SBCS \
  56.588 +    asm  ("bt $0, C_FLAG;" \
  56.589 +          "cmc;" \
  56.590 +          "sbb %1, %%ebx;" \
  56.591 +          "setsb N_FLAG;" \
  56.592 +          "setzb Z_FLAG;" \
  56.593 +          "setncb C_FLAG;" \
  56.594 +          "setob V_FLAG;" \
  56.595 +		  : "=b" (reg[dest].I) \
  56.596 +		  : "r" (value), "b" (reg[base].I));
  56.597 +#define OP_RSC \
  56.598 +    asm  ("bt $0, C_FLAG;" \
  56.599 +          "cmc;" \
  56.600 +          "sbb %1, %%ebx;" \
  56.601 +		  : "=b" (reg[dest].I) \
  56.602 +		  : "r" (reg[base].I), "b" (value));
  56.603 +
  56.604 +#define OP_RSCS \
  56.605 +    asm  ("bt $0, C_FLAG;" \
  56.606 +          "cmc;" \
  56.607 +          "sbb %1, %%ebx;" \
  56.608 +          "setsb N_FLAG;" \
  56.609 +          "setzb Z_FLAG;" \
  56.610 +          "setncb C_FLAG;" \
  56.611 +          "setob V_FLAG;" \
  56.612 +		  : "=b" (reg[dest].I) \
  56.613 +		  : "r" (reg[base].I), "b" (value));
  56.614 +#define OP_CMP \
  56.615 +    asm  ("sub %0, %1;" \
  56.616 +          "setsb N_FLAG;" \
  56.617 +          "setzb Z_FLAG;" \
  56.618 +          "setncb C_FLAG;" \
  56.619 +          "setob V_FLAG;" \
  56.620 +		  : \
  56.621 +		  : "r" (value), "r" (reg[base].I));
  56.622 +
  56.623 +#define OP_CMN \
  56.624 +    asm  ("add %0, %1;" \
  56.625 +          "setsb N_FLAG;" \
  56.626 +          "setzb Z_FLAG;" \
  56.627 +          "setcb C_FLAG;" \
  56.628 +          "setob V_FLAG;" \
  56.629 +		  : \
  56.630 +		  : "r" (value), "r" (reg[base].I));
  56.631 +#define LOGICAL_LSL_REG \
  56.632 +    asm ("shl %%cl, %%eax;" \
  56.633 +         "setcb %%cl;" \
  56.634 +		 : "=a" (value), "=c" (C_OUT) \
  56.635 +		 : "a" (reg[opcode & 0x0f].I), "c" (shift));
  56.636 +
  56.637 +#define LOGICAL_LSR_REG \
  56.638 +    asm ("shr %%cl, %%eax;" \
  56.639 +         "setcb %%cl;" \
  56.640 +		 : "=a" (value), "=c" (C_OUT) \
  56.641 +		 : "a" (reg[opcode & 0x0f].I), "c" (shift));
  56.642 +
  56.643 +#define LOGICAL_ASR_REG \
  56.644 +    asm ("sar %%cl, %%eax;" \
  56.645 +         "setcb %%cl;" \
  56.646 +		 : "=a" (value), "=c" (C_OUT) \
  56.647 +		 : "a" (reg[opcode & 0x0f].I), "c" (shift));
  56.648 +
  56.649 +#define LOGICAL_ROR_REG \
  56.650 +    asm ("ror %%cl, %%eax;" \
  56.651 +         "setcb %%cl;" \
  56.652 +		 : "=a" (value), "=c" (C_OUT) \
  56.653 +		 : "a" (reg[opcode & 0x0f].I), "c" (shift));
  56.654 +
  56.655 +#define LOGICAL_RRX_REG \
  56.656 +    asm ("bt $0, C_FLAG;" \
  56.657 +         "rcr $1, %%eax;" \
  56.658 +         "setcb %%cl;" \
  56.659 +		 : "=a" (value), "=c" (C_OUT) \
  56.660 +		 : "a" (reg[opcode & 0x0f].I));
  56.661 +
  56.662 +#define LOGICAL_ROR_IMM \
  56.663 +    asm ("ror %%cl, %%eax;" \
  56.664 +         "setcb %%cl;" \
  56.665 +		 : "=a" (value), "=c" (C_OUT) \
  56.666 +		 : "a" (opcode & 0xff), "c" (shift));
  56.667 +#define ARITHMETIC_LSL_REG \
  56.668 +    asm ("\
  56.669 +             shl %%cl, %%eax;" \
  56.670 +		 : "=a" (value) \
  56.671 +		 : "a" (reg[opcode & 0x0f].I), "c" (shift));
  56.672 +
  56.673 +#define ARITHMETIC_LSR_REG \
  56.674 +    asm ("\
  56.675 +             shr %%cl, %%eax;" \
  56.676 +		 : "=a" (value) \
  56.677 +		 : "a" (reg[opcode & 0x0f].I), "c" (shift));
  56.678 +
  56.679 +#define ARITHMETIC_ASR_REG \
  56.680 +    asm ("\
  56.681 +             sar %%cl, %%eax;" \
  56.682 +		 : "=a" (value) \
  56.683 +		 : "a" (reg[opcode & 0x0f].I), "c" (shift));
  56.684 +
  56.685 +#define ARITHMETIC_ROR_REG \
  56.686 +    asm ("\
  56.687 +             ror %%cl, %%eax;" \
  56.688 +		 : "=a" (value) \
  56.689 +		 : "a" (reg[opcode & 0x0f].I), "c" (shift));
  56.690 +
  56.691 +#define ARITHMETIC_RRX_REG \
  56.692 +    asm ("\
  56.693 +             bt $0, C_FLAG;\
  56.694 +             rcr $1, %%eax;" \
  56.695 +		 : "=a" (value) \
  56.696 +		 : "a" (reg[opcode & 0x0f].I));
  56.697 +
  56.698 +#define ARITHMETIC_ROR_IMM \
  56.699 +    asm ("\
  56.700 +             ror %%cl, %%eax;" \
  56.701 +		 : "=a" (value) \
  56.702 +		 : "a" (opcode & 0xff), "c" (shift));
  56.703 +#define ROR_IMM_MSR \
  56.704 +    asm ("ror %%cl, %%eax;" \
  56.705 +		 : "=a" (value) \
  56.706 +		 : "a" (opcode & 0xFF), "c" (shift));
  56.707 +#define ROR_VALUE \
  56.708 +    asm ("ror %%cl, %0" \
  56.709 +		 : "=r" (value) \
  56.710 +		 : "r" (value), "c" (shift));
  56.711 +#define RCR_VALUE \
  56.712 +    asm ("bt $0, C_FLAG;" \
  56.713 +         "rcr $1, %0" \
  56.714 +		 : "=r" (value) \
  56.715 +		 : "r" (value));
  56.716 +#endif
  56.717 +#else
  56.718 +#define OP_SUB \
  56.719 +	{ \
  56.720 +		__asm mov ebx, base \
  56.721 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.722 +		__asm sub ebx, value \
  56.723 +		__asm mov eax, dest \
  56.724 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.725 +	}
  56.726 +
  56.727 +#define OP_SUBS \
  56.728 +	{ \
  56.729 +		__asm mov ebx, base \
  56.730 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.731 +		__asm sub ebx, value \
  56.732 +		__asm mov eax, dest \
  56.733 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.734 +		__asm sets byte ptr N_FLAG \
  56.735 +		__asm setz byte ptr Z_FLAG \
  56.736 +		__asm setnc byte ptr C_FLAG \
  56.737 +		__asm seto byte ptr V_FLAG \
  56.738 +	}
  56.739 +
  56.740 +#define OP_RSB \
  56.741 +	{ \
  56.742 +		__asm mov ebx, base \
  56.743 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.744 +		__asm mov eax, value \
  56.745 +		__asm sub eax, ebx \
  56.746 +		__asm mov ebx, dest \
  56.747 +		__asm mov dword ptr [OFFSET reg + 4 * ebx], eax \
  56.748 +	}
  56.749 +
  56.750 +#define OP_RSBS \
  56.751 +	{ \
  56.752 +		__asm mov ebx, base \
  56.753 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.754 +		__asm mov eax, value \
  56.755 +		__asm sub eax, ebx \
  56.756 +		__asm mov ebx, dest \
  56.757 +		__asm mov dword ptr [OFFSET reg + 4 * ebx], eax \
  56.758 +		__asm sets byte ptr N_FLAG \
  56.759 +		__asm setz byte ptr Z_FLAG \
  56.760 +		__asm setnc byte ptr C_FLAG \
  56.761 +		__asm seto byte ptr V_FLAG \
  56.762 +	}
  56.763 +
  56.764 +#define OP_ADD \
  56.765 +	{ \
  56.766 +		__asm mov ebx, base \
  56.767 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.768 +		__asm add ebx, value \
  56.769 +		__asm mov eax, dest \
  56.770 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.771 +	}
  56.772 +
  56.773 +#define OP_ADDS \
  56.774 +	{ \
  56.775 +		__asm mov ebx, base \
  56.776 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.777 +		__asm add ebx, value \
  56.778 +		__asm mov eax, dest \
  56.779 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.780 +		__asm sets byte ptr N_FLAG \
  56.781 +		__asm setz byte ptr Z_FLAG \
  56.782 +		__asm setc byte ptr C_FLAG \
  56.783 +		__asm seto byte ptr V_FLAG \
  56.784 +	}
  56.785 +
  56.786 +#define OP_ADC \
  56.787 +	{ \
  56.788 +		__asm mov ebx, base \
  56.789 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.790 +		__asm bt word ptr C_FLAG, 0 \
  56.791 +		__asm adc ebx, value \
  56.792 +		__asm mov eax, dest \
  56.793 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.794 +	}
  56.795 +
  56.796 +#define OP_ADCS \
  56.797 +	{ \
  56.798 +		__asm mov ebx, base \
  56.799 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.800 +		__asm bt word ptr C_FLAG, 0 \
  56.801 +		__asm adc ebx, value \
  56.802 +		__asm mov eax, dest \
  56.803 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.804 +		__asm sets byte ptr N_FLAG \
  56.805 +		__asm setz byte ptr Z_FLAG \
  56.806 +		__asm setc byte ptr C_FLAG \
  56.807 +		__asm seto byte ptr V_FLAG \
  56.808 +	}
  56.809 +
  56.810 +#define OP_SBC \
  56.811 +	{ \
  56.812 +		__asm mov ebx, base \
  56.813 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.814 +		__asm mov eax, value \
  56.815 +		__asm bt word ptr C_FLAG, 0 \
  56.816 +		__asm cmc \
  56.817 +		__asm sbb ebx, eax \
  56.818 +		__asm mov eax, dest \
  56.819 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.820 +	}
  56.821 +
  56.822 +#define OP_SBCS \
  56.823 +	{ \
  56.824 +		__asm mov ebx, base \
  56.825 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  56.826 +		__asm mov eax, value \
  56.827 +		__asm bt word ptr C_FLAG, 0 \
  56.828 +		__asm cmc \
  56.829 +		__asm sbb ebx, eax \
  56.830 +		__asm mov eax, dest \
  56.831 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.832 +		__asm sets byte ptr N_FLAG \
  56.833 +		__asm setz byte ptr Z_FLAG \
  56.834 +		__asm setnc byte ptr C_FLAG \
  56.835 +		__asm seto byte ptr V_FLAG \
  56.836 +	}
  56.837 +#define OP_RSC \
  56.838 +	{ \
  56.839 +		__asm mov ebx, value \
  56.840 +		__asm mov eax, base \
  56.841 +		__asm mov eax, dword ptr[OFFSET reg + 4 * eax] \
  56.842 +		__asm bt word ptr C_FLAG, 0 \
  56.843 +		__asm cmc \
  56.844 +		__asm sbb ebx, eax \
  56.845 +		__asm mov eax, dest \
  56.846 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.847 +	}
  56.848 +
  56.849 +#define OP_RSCS \
  56.850 +	{ \
  56.851 +		__asm mov ebx, value \
  56.852 +		__asm mov eax, base \
  56.853 +		__asm mov eax, dword ptr[OFFSET reg + 4 * eax] \
  56.854 +		__asm bt word ptr C_FLAG, 0 \
  56.855 +		__asm cmc \
  56.856 +		__asm sbb ebx, eax \
  56.857 +		__asm mov eax, dest \
  56.858 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  56.859 +		__asm sets byte ptr N_FLAG \
  56.860 +		__asm setz byte ptr Z_FLAG \
  56.861 +		__asm setnc byte ptr C_FLAG \
  56.862 +		__asm seto byte ptr V_FLAG \
  56.863 +	}
  56.864 +#define OP_CMP \
  56.865 +	{ \
  56.866 +		__asm mov eax, base \
  56.867 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
  56.868 +		__asm sub ebx, value \
  56.869 +		__asm sets byte ptr N_FLAG \
  56.870 +		__asm setz byte ptr Z_FLAG \
  56.871 +		__asm setnc byte ptr C_FLAG \
  56.872 +		__asm seto byte ptr V_FLAG \
  56.873 +	}
  56.874 +
  56.875 +#define OP_CMN \
  56.876 +	{ \
  56.877 +		__asm mov eax, base \
  56.878 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
  56.879 +		__asm add ebx, value \
  56.880 +		__asm sets byte ptr N_FLAG \
  56.881 +		__asm setz byte ptr Z_FLAG \
  56.882 +		__asm setc byte ptr C_FLAG \
  56.883 +		__asm seto byte ptr V_FLAG \
  56.884 +	}
  56.885 +#define LOGICAL_LSL_REG \
  56.886 +    __asm mov eax, opcode \
  56.887 +    __asm and eax, 0x0f \
  56.888 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.889 +    __asm mov cl, byte ptr shift \
  56.890 +    __asm shl eax, cl \
  56.891 +    __asm mov value, eax \
  56.892 +    __asm setc byte ptr C_OUT
  56.893 +
  56.894 +#define LOGICAL_LSR_REG \
  56.895 +    __asm mov eax, opcode \
  56.896 +    __asm and eax, 0x0f \
  56.897 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.898 +    __asm mov cl, byte ptr shift \
  56.899 +    __asm shr eax, cl \
  56.900 +    __asm mov value, eax \
  56.901 +    __asm setc byte ptr C_OUT
  56.902 +
  56.903 +#define LOGICAL_ASR_REG \
  56.904 +    __asm mov eax, opcode \
  56.905 +    __asm and eax, 0x0f \
  56.906 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.907 +    __asm mov cl, byte ptr shift \
  56.908 +    __asm sar eax, cl \
  56.909 +    __asm mov value, eax \
  56.910 +    __asm setc byte ptr C_OUT
  56.911 +
  56.912 +#define LOGICAL_ROR_REG \
  56.913 +    __asm mov eax, opcode \
  56.914 +    __asm and eax, 0x0F \
  56.915 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.916 +    __asm mov cl, byte ptr shift \
  56.917 +    __asm ror eax, cl \
  56.918 +    __asm mov value, eax \
  56.919 +    __asm setc byte ptr C_OUT
  56.920 +
  56.921 +#define LOGICAL_RRX_REG \
  56.922 +    __asm mov eax, opcode \
  56.923 +    __asm and eax, 0x0F \
  56.924 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.925 +    __asm bt word ptr C_OUT, 0 \
  56.926 +    __asm rcr eax, 1 \
  56.927 +    __asm mov value, eax \
  56.928 +    __asm setc byte ptr C_OUT
  56.929 +
  56.930 +#define LOGICAL_ROR_IMM \
  56.931 +    __asm mov eax, opcode \
  56.932 +    __asm and eax, 0xff \
  56.933 +    __asm mov cl, byte ptr shift \
  56.934 +    __asm ror eax, cl \
  56.935 +    __asm mov value, eax \
  56.936 +    __asm setc byte ptr C_OUT
  56.937 +#define ARITHMETIC_LSL_REG \
  56.938 +    __asm mov eax, opcode \
  56.939 +    __asm and eax, 0x0f \
  56.940 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.941 +    __asm mov cl, byte ptr shift \
  56.942 +    __asm shl eax, cl \
  56.943 +    __asm mov value, eax
  56.944 +
  56.945 +#define ARITHMETIC_LSR_REG \
  56.946 +    __asm mov eax, opcode \
  56.947 +    __asm and eax, 0x0f \
  56.948 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.949 +    __asm mov cl, byte ptr shift \
  56.950 +    __asm shr eax, cl \
  56.951 +    __asm mov value, eax
  56.952 +
  56.953 +#define ARITHMETIC_ASR_REG \
  56.954 +    __asm mov eax, opcode \
  56.955 +    __asm and eax, 0x0f \
  56.956 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.957 +    __asm mov cl, byte ptr shift \
  56.958 +    __asm sar eax, cl \
  56.959 +    __asm mov value, eax
  56.960 +
  56.961 +#define ARITHMETIC_ROR_REG \
  56.962 +    __asm mov eax, opcode \
  56.963 +    __asm and eax, 0x0F \
  56.964 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.965 +    __asm mov cl, byte ptr shift \
  56.966 +    __asm ror eax, cl \
  56.967 +    __asm mov value, eax
  56.968 +
  56.969 +#define ARITHMETIC_RRX_REG \
  56.970 +    __asm mov eax, opcode \
  56.971 +    __asm and eax, 0x0F \
  56.972 +    __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  56.973 +    __asm bt word ptr C_FLAG, 0 \
  56.974 +    __asm rcr eax, 1 \
  56.975 +    __asm mov value, eax
  56.976 +
  56.977 +#define ARITHMETIC_ROR_IMM \
  56.978 +    __asm mov eax, opcode \
  56.979 +    __asm and eax, 0xff \
  56.980 +    __asm mov cl, byte ptr shift \
  56.981 +    __asm ror eax, cl \
  56.982 +    __asm mov value, eax
  56.983 +#define ROR_IMM_MSR \
  56.984 +	{ \
  56.985 +		__asm mov eax, opcode \
  56.986 +		          __asm and eax, 0xff \
  56.987 +		__asm mov cl, byte ptr shift \
  56.988 +		__asm ror eax, CL \
  56.989 +		__asm mov value, eax \
  56.990 +	}
  56.991 +#define ROR_VALUE \
  56.992 +	{ \
  56.993 +		__asm mov cl, byte ptr shift \
  56.994 +		__asm ror dword ptr value, cl \
  56.995 +	}
  56.996 +#define RCR_VALUE \
  56.997 +	{ \
  56.998 +		__asm mov cl, byte ptr shift \
  56.999 +		__asm bt word ptr C_FLAG, 0 \
 56.1000 +		__asm rcr dword ptr value, 1 \
 56.1001 +	}
 56.1002 +#endif
 56.1003 +#endif
 56.1004 +
 56.1005 +#define OP_TST \
 56.1006 +    u32 res = reg[base].I & value; \
 56.1007 +    N_FLAG	= (res & 0x80000000) ? true : false; \
 56.1008 +    Z_FLAG	= (res) ? false : true; \
 56.1009 +    C_FLAG	= C_OUT;
 56.1010 +
 56.1011 +#define OP_TEQ \
 56.1012 +    u32 res = reg[base].I ^ value; \
 56.1013 +    N_FLAG	= (res & 0x80000000) ? true : false; \
 56.1014 +    Z_FLAG	= (res) ? false : true; \
 56.1015 +    C_FLAG	= C_OUT;
 56.1016 +
 56.1017 +#define OP_ORR \
 56.1018 +    reg[dest].I = reg[base].I | value;
 56.1019 +
 56.1020 +#define OP_ORRS \
 56.1021 +    reg[dest].I = reg[base].I | value; \
 56.1022 +    N_FLAG		= (reg[dest].I & 0x80000000) ? true : false; \
 56.1023 +    Z_FLAG		= (reg[dest].I) ? false : true; \
 56.1024 +    C_FLAG		= C_OUT;
 56.1025 +
 56.1026 +#define OP_MOV \
 56.1027 +    reg[dest].I = value;
 56.1028 +
 56.1029 +#define OP_MOVS \
 56.1030 +    reg[dest].I = value; \
 56.1031 +    N_FLAG		= (reg[dest].I & 0x80000000) ? true : false; \
 56.1032 +    Z_FLAG		= (reg[dest].I) ? false : true; \
 56.1033 +    C_FLAG		= C_OUT;
 56.1034 +
 56.1035 +#define OP_BIC \
 56.1036 +    reg[dest].I = reg[base].I & (~value);
 56.1037 +
 56.1038 +#define OP_BICS \
 56.1039 +    reg[dest].I = reg[base].I & (~value); \
 56.1040 +    N_FLAG		= (reg[dest].I & 0x80000000) ? true : false; \
 56.1041 +    Z_FLAG		= (reg[dest].I) ? false : true; \
 56.1042 +    C_FLAG		= C_OUT;
 56.1043 +
 56.1044 +#define OP_MVN \
 56.1045 +    reg[dest].I = ~value;
 56.1046 +
 56.1047 +#define OP_MVNS \
 56.1048 +    reg[dest].I = ~value; \
 56.1049 +    N_FLAG		= (reg[dest].I & 0x80000000) ? true : false; \
 56.1050 +    Z_FLAG		= (reg[dest].I) ? false : true; \
 56.1051 +    C_FLAG		= C_OUT;
 56.1052 +
 56.1053 +#define CASE_16(BASE) \
 56.1054 +case BASE: \
 56.1055 +case BASE + 1: \
 56.1056 +case BASE + 2: \
 56.1057 +case BASE + 3: \
 56.1058 +case BASE + 4: \
 56.1059 +case BASE + 5: \
 56.1060 +case BASE + 6: \
 56.1061 +case BASE + 7: \
 56.1062 +case BASE + 8: \
 56.1063 +case BASE + 9: \
 56.1064 +case BASE + 10: \
 56.1065 +case BASE + 11: \
 56.1066 +case BASE + 12: \
 56.1067 +case BASE + 13: \
 56.1068 +case BASE + 14: \
 56.1069 +case BASE + 15:
 56.1070 +
 56.1071 +#define CASE_256(BASE) \
 56.1072 +    CASE_16(BASE) \
 56.1073 +    CASE_16(BASE + 0x10) \
 56.1074 +    CASE_16(BASE + 0x20) \
 56.1075 +    CASE_16(BASE + 0x30) \
 56.1076 +    CASE_16(BASE + 0x40) \
 56.1077 +    CASE_16(BASE + 0x50) \
 56.1078 +    CASE_16(BASE + 0x60) \
 56.1079 +    CASE_16(BASE + 0x70) \
 56.1080 +    CASE_16(BASE + 0x80) \
 56.1081 +    CASE_16(BASE + 0x90) \
 56.1082 +    CASE_16(BASE + 0xa0) \
 56.1083 +    CASE_16(BASE + 0xb0) \
 56.1084 +    CASE_16(BASE + 0xc0) \
 56.1085 +    CASE_16(BASE + 0xd0) \
 56.1086 +    CASE_16(BASE + 0xe0) \
 56.1087 +    CASE_16(BASE + 0xf0)
 56.1088 +
 56.1089 +#define LOGICAL_DATA_OPCODE(OPCODE, OPCODE2, BASE) \
 56.1090 +case BASE: \
 56.1091 +case BASE + 8: \
 56.1092 +{ \
 56.1093 +	/* OP Rd,Rb,Rm LSL # */ \
 56.1094 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1095 +	int	 shift = (opcode >> 7) & 0x1F; \
 56.1096 +	int	 dest  = (opcode >> 12) & 15; \
 56.1097 +	bool C_OUT = C_FLAG; \
 56.1098 +	u32	 value; \
 56.1099 +      \
 56.1100 +	if (shift) { \
 56.1101 +		LOGICAL_LSL_REG \
 56.1102 +	} else { \
 56.1103 +		value = reg[opcode & 0x0F].I; \
 56.1104 +	} \
 56.1105 +	if (dest == 15) { \
 56.1106 +		OPCODE2 \
 56.1107 +		/* todo */ \
 56.1108 +		if (opcode & 0x00100000) { \
 56.1109 +			clockTicks++; \
 56.1110 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1111 +		} \
 56.1112 +		if (armState) { \
 56.1113 +			reg[15].I &= 0xFFFFFFFC; \
 56.1114 +			armNextPC  = reg[15].I; \
 56.1115 +			reg[15].I += 4; \
 56.1116 +		} else { \
 56.1117 +			reg[15].I &= 0xFFFFFFFE; \
 56.1118 +			armNextPC  = reg[15].I; \
 56.1119 +			reg[15].I += 2; \
 56.1120 +		} \
 56.1121 +	} else { \
 56.1122 +		OPCODE \
 56.1123 +	} \
 56.1124 +} \
 56.1125 +break; \
 56.1126 +case BASE + 2: \
 56.1127 +case BASE + 10: \
 56.1128 +{ \
 56.1129 +	/* OP Rd,Rb,Rm LSR # */ \
 56.1130 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1131 +	int	 shift = (opcode >> 7) & 0x1F; \
 56.1132 +	int	 dest  = (opcode >> 12) & 15; \
 56.1133 +	bool C_OUT = C_FLAG; \
 56.1134 +	u32	 value; \
 56.1135 +	if (shift) { \
 56.1136 +		LOGICAL_LSR_REG \
 56.1137 +	} else { \
 56.1138 +		value = 0; \
 56.1139 +		C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false; \
 56.1140 +	} \
 56.1141 +      \
 56.1142 +	if (dest == 15) { \
 56.1143 +		OPCODE2 \
 56.1144 +		/* todo */ \
 56.1145 +		if (opcode & 0x00100000) { \
 56.1146 +			clockTicks++; \
 56.1147 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1148 +		} \
 56.1149 +		if (armState) { \
 56.1150 +			reg[15].I &= 0xFFFFFFFC; \
 56.1151 +			armNextPC  = reg[15].I; \
 56.1152 +			reg[15].I += 4; \
 56.1153 +		} else { \
 56.1154 +			reg[15].I &= 0xFFFFFFFE; \
 56.1155 +			armNextPC  = reg[15].I; \
 56.1156 +			reg[15].I += 2; \
 56.1157 +		} \
 56.1158 +	} else { \
 56.1159 +		OPCODE \
 56.1160 +	} \
 56.1161 +} \
 56.1162 +break; \
 56.1163 +case BASE + 4: \
 56.1164 +case BASE + 12: \
 56.1165 +{ \
 56.1166 +	/* OP Rd,Rb,Rm ASR # */ \
 56.1167 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1168 +	int	 shift = (opcode >> 7) & 0x1F; \
 56.1169 +	int	 dest  = (opcode >> 12) & 15; \
 56.1170 +	bool C_OUT = C_FLAG; \
 56.1171 +	u32	 value; \
 56.1172 +	if (shift) { \
 56.1173 +		LOGICAL_ASR_REG \
 56.1174 +	} else { \
 56.1175 +		if (reg[opcode & 0x0F].I & 0x80000000) { \
 56.1176 +			value = 0xFFFFFFFF; \
 56.1177 +			C_OUT = true; \
 56.1178 +		} else { \
 56.1179 +			value = 0; \
 56.1180 +			C_OUT = false; \
 56.1181 +		}                   \
 56.1182 +	} \
 56.1183 +      \
 56.1184 +	if (dest == 15) { \
 56.1185 +		OPCODE2 \
 56.1186 +		/* todo */ \
 56.1187 +		if (opcode & 0x00100000) { \
 56.1188 +			clockTicks++; \
 56.1189 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1190 +		} \
 56.1191 +		if (armState) { \
 56.1192 +			reg[15].I &= 0xFFFFFFFC; \
 56.1193 +			armNextPC  = reg[15].I; \
 56.1194 +			reg[15].I += 4; \
 56.1195 +		} else { \
 56.1196 +			reg[15].I &= 0xFFFFFFFE; \
 56.1197 +			armNextPC  = reg[15].I; \
 56.1198 +			reg[15].I += 2; \
 56.1199 +		} \
 56.1200 +	} else { \
 56.1201 +		OPCODE \
 56.1202 +	} \
 56.1203 +} \
 56.1204 +break; \
 56.1205 +case BASE + 6: \
 56.1206 +case BASE + 14: \
 56.1207 +{ \
 56.1208 +	/* OP Rd,Rb,Rm ROR # */ \
 56.1209 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1210 +	int	 shift = (opcode >> 7) & 0x1F; \
 56.1211 +	int	 dest  = (opcode >> 12) & 15; \
 56.1212 +	bool C_OUT = C_FLAG; \
 56.1213 +	u32	 value; \
 56.1214 +	if (shift) { \
 56.1215 +		LOGICAL_ROR_REG \
 56.1216 +	} else { \
 56.1217 +		LOGICAL_RRX_REG \
 56.1218 +	} \
 56.1219 +	if (dest == 15) { \
 56.1220 +		OPCODE2 \
 56.1221 +		/* todo */ \
 56.1222 +		if (opcode & 0x00100000) { \
 56.1223 +			clockTicks++; \
 56.1224 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1225 +		} \
 56.1226 +		if (armState) { \
 56.1227 +			reg[15].I &= 0xFFFFFFFC; \
 56.1228 +			armNextPC  = reg[15].I; \
 56.1229 +			reg[15].I += 4; \
 56.1230 +		} else { \
 56.1231 +			reg[15].I &= 0xFFFFFFFE; \
 56.1232 +			armNextPC  = reg[15].I; \
 56.1233 +			reg[15].I += 2; \
 56.1234 +		} \
 56.1235 +	} else { \
 56.1236 +		OPCODE \
 56.1237 +	} \
 56.1238 +} \
 56.1239 +break; \
 56.1240 +case BASE + 1: \
 56.1241 +{ \
 56.1242 +	/* OP Rd,Rb,Rm LSL Rs */ \
 56.1243 +	clockTicks++; \
 56.1244 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1245 +	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1246 +	int	 dest  = (opcode >> 12) & 15; \
 56.1247 +	bool C_OUT = C_FLAG; \
 56.1248 +	u32	 value; \
 56.1249 +	if (shift) { \
 56.1250 +		if (shift == 32) { \
 56.1251 +			value = 0; \
 56.1252 +			C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false); \
 56.1253 +		} else if (shift < 32) { \
 56.1254 +			LOGICAL_LSL_REG \
 56.1255 +		} else { \
 56.1256 +			value = 0; \
 56.1257 +			C_OUT = false; \
 56.1258 +		} \
 56.1259 +	} else { \
 56.1260 +		value = reg[opcode & 0x0F].I; \
 56.1261 +	} \
 56.1262 +	if (dest == 15) { \
 56.1263 +		OPCODE2 \
 56.1264 +		/* todo */ \
 56.1265 +		if (opcode & 0x00100000) { \
 56.1266 +			clockTicks++; \
 56.1267 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1268 +		} \
 56.1269 +		if (armState) { \
 56.1270 +			reg[15].I &= 0xFFFFFFFC; \
 56.1271 +			armNextPC  = reg[15].I; \
 56.1272 +			reg[15].I += 4; \
 56.1273 +		} else { \
 56.1274 +			reg[15].I &= 0xFFFFFFFE; \
 56.1275 +			armNextPC  = reg[15].I; \
 56.1276 +			reg[15].I += 2; \
 56.1277 +		} \
 56.1278 +	} else { \
 56.1279 +		OPCODE \
 56.1280 +	} \
 56.1281 +} \
 56.1282 +break; \
 56.1283 +case BASE + 3: \
 56.1284 +{ \
 56.1285 +	/* OP Rd,Rb,Rm LSR Rs */ \
 56.1286 +	clockTicks++; \
 56.1287 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1288 +	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1289 +	int	 dest  = (opcode >> 12) & 15; \
 56.1290 +	bool C_OUT = C_FLAG; \
 56.1291 +	u32	 value; \
 56.1292 +	if (shift) { \
 56.1293 +		if (shift == 32) { \
 56.1294 +			value = 0; \
 56.1295 +			C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false); \
 56.1296 +		} else if (shift < 32) { \
 56.1297 +			LOGICAL_LSR_REG \
 56.1298 +		} else { \
 56.1299 +			value = 0; \
 56.1300 +			C_OUT = false; \
 56.1301 +		} \
 56.1302 +	} else { \
 56.1303 +		value = reg[opcode & 0x0F].I; \
 56.1304 +	} \
 56.1305 +	if (dest == 15) { \
 56.1306 +		OPCODE2 \
 56.1307 +		/* todo */ \
 56.1308 +		if (opcode & 0x00100000) { \
 56.1309 +			clockTicks++; \
 56.1310 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1311 +		} \
 56.1312 +		if (armState) { \
 56.1313 +			reg[15].I &= 0xFFFFFFFC; \
 56.1314 +			armNextPC  = reg[15].I; \
 56.1315 +			reg[15].I += 4; \
 56.1316 +		} else { \
 56.1317 +			reg[15].I &= 0xFFFFFFFE; \
 56.1318 +			armNextPC  = reg[15].I; \
 56.1319 +			reg[15].I += 2; \
 56.1320 +		} \
 56.1321 +	} else { \
 56.1322 +		OPCODE \
 56.1323 +	} \
 56.1324 +} \
 56.1325 +break; \
 56.1326 +case BASE + 5: \
 56.1327 +{ \
 56.1328 +	/* OP Rd,Rb,Rm ASR Rs */ \
 56.1329 +	clockTicks++; \
 56.1330 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1331 +	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1332 +	int	 dest  = (opcode >> 12) & 15; \
 56.1333 +	bool C_OUT = C_FLAG; \
 56.1334 +	u32	 value; \
 56.1335 +	if (shift < 32) { \
 56.1336 +		if (shift) { \
 56.1337 +			LOGICAL_ASR_REG \
 56.1338 +		} else { \
 56.1339 +			value = reg[opcode & 0x0F].I; \
 56.1340 +		} \
 56.1341 +	} else { \
 56.1342 +		if (reg[opcode & 0x0F].I & 0x80000000) { \
 56.1343 +			value = 0xFFFFFFFF; \
 56.1344 +			C_OUT = true; \
 56.1345 +		} else { \
 56.1346 +			value = 0; \
 56.1347 +			C_OUT = false; \
 56.1348 +		} \
 56.1349 +	} \
 56.1350 +	if (dest == 15) { \
 56.1351 +		OPCODE2 \
 56.1352 +		/* todo */ \
 56.1353 +		if (opcode & 0x00100000) { \
 56.1354 +			clockTicks++; \
 56.1355 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1356 +		} \
 56.1357 +		if (armState) { \
 56.1358 +			reg[15].I &= 0xFFFFFFFC; \
 56.1359 +			armNextPC  = reg[15].I; \
 56.1360 +			reg[15].I += 4; \
 56.1361 +		} else { \
 56.1362 +			reg[15].I &= 0xFFFFFFFE; \
 56.1363 +			armNextPC  = reg[15].I; \
 56.1364 +			reg[15].I += 2; \
 56.1365 +		} \
 56.1366 +	} else { \
 56.1367 +		OPCODE \
 56.1368 +	} \
 56.1369 +} \
 56.1370 +break; \
 56.1371 +case BASE + 7: \
 56.1372 +{ \
 56.1373 +	/* OP Rd,Rb,Rm ROR Rs */ \
 56.1374 +	clockTicks++; \
 56.1375 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1376 +	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1377 +	int	 dest  = (opcode >> 12) & 15; \
 56.1378 +	bool C_OUT = C_FLAG; \
 56.1379 +	u32	 value; \
 56.1380 +	if (shift) { \
 56.1381 +		shift &= 0x1f; \
 56.1382 +		if (shift) { \
 56.1383 +			LOGICAL_ROR_REG \
 56.1384 +		} else { \
 56.1385 +			value = reg[opcode & 0x0F].I; \
 56.1386 +			C_OUT = (value & 0x80000000 ? true : false); \
 56.1387 +		} \
 56.1388 +	} else { \
 56.1389 +		value = reg[opcode & 0x0F].I; \
 56.1390 +		C_OUT = (value & 0x80000000 ? true : false); \
 56.1391 +	} \
 56.1392 +	if (dest == 15) { \
 56.1393 +		OPCODE2 \
 56.1394 +		/* todo */ \
 56.1395 +		if (opcode & 0x00100000) { \
 56.1396 +			clockTicks++; \
 56.1397 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1398 +		} \
 56.1399 +		if (armState) { \
 56.1400 +			reg[15].I &= 0xFFFFFFFC; \
 56.1401 +			armNextPC  = reg[15].I; \
 56.1402 +			reg[15].I += 4; \
 56.1403 +		} else { \
 56.1404 +			reg[15].I &= 0xFFFFFFFE; \
 56.1405 +			armNextPC  = reg[15].I; \
 56.1406 +			reg[15].I += 2; \
 56.1407 +		} \
 56.1408 +	} else { \
 56.1409 +		OPCODE \
 56.1410 +	} \
 56.1411 +} \
 56.1412 +break; \
 56.1413 +case BASE + 0x200: \
 56.1414 +case BASE + 0x201: \
 56.1415 +case BASE + 0x202: \
 56.1416 +case BASE + 0x203: \
 56.1417 +case BASE + 0x204: \
 56.1418 +case BASE + 0x205: \
 56.1419 +case BASE + 0x206: \
 56.1420 +case BASE + 0x207: \
 56.1421 +case BASE + 0x208: \
 56.1422 +case BASE + 0x209: \
 56.1423 +case BASE + 0x20a: \
 56.1424 +case BASE + 0x20b: \
 56.1425 +case BASE + 0x20c: \
 56.1426 +case BASE + 0x20d: \
 56.1427 +case BASE + 0x20e: \
 56.1428 +case BASE + 0x20f: \
 56.1429 +{ \
 56.1430 +	int	 shift = (opcode & 0xF00) >> 7; \
 56.1431 +	int	 base  = (opcode >> 16) & 0x0F; \
 56.1432 +	int	 dest  = (opcode >> 12) & 0x0F; \
 56.1433 +	bool C_OUT = C_FLAG; \
 56.1434 +	u32	 value; \
 56.1435 +	if (shift) { \
 56.1436 +		LOGICAL_ROR_IMM \
 56.1437 +	} else { \
 56.1438 +		value = opcode & 0xff; \
 56.1439 +	} \
 56.1440 +	if (dest == 15) { \
 56.1441 +		OPCODE2 \
 56.1442 +		/* todo */ \
 56.1443 +		if (opcode & 0x00100000) { \
 56.1444 +			clockTicks++; \
 56.1445 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1446 +		} \
 56.1447 +		if (armState) { \
 56.1448 +			reg[15].I &= 0xFFFFFFFC; \
 56.1449 +			armNextPC  = reg[15].I; \
 56.1450 +			reg[15].I += 4; \
 56.1451 +		} else { \
 56.1452 +			reg[15].I &= 0xFFFFFFFE; \
 56.1453 +			armNextPC  = reg[15].I; \
 56.1454 +			reg[15].I += 2; \
 56.1455 +		} \
 56.1456 +	} else { \
 56.1457 +		OPCODE \
 56.1458 +	} \
 56.1459 +} \
 56.1460 +break;
 56.1461 +
 56.1462 +#define LOGICAL_DATA_OPCODE_WITHOUT_base(OPCODE, OPCODE2, BASE) \
 56.1463 +case BASE: \
 56.1464 +case BASE + 8: \
 56.1465 +{ \
 56.1466 +	/* OP Rd,Rb,Rm LSL # */ \
 56.1467 +	int	 shift = (opcode >> 7) & 0x1F; \
 56.1468 +	int	 dest  = (opcode >> 12) & 15; \
 56.1469 +	bool C_OUT = C_FLAG; \
 56.1470 +	u32	 value; \
 56.1471 +      \
 56.1472 +	if (shift) { \
 56.1473 +		LOGICAL_LSL_REG \
 56.1474 +	} else { \
 56.1475 +		value = reg[opcode & 0x0F].I; \
 56.1476 +	} \
 56.1477 +	if (dest == 15) { \
 56.1478 +		OPCODE2 \
 56.1479 +		/* todo */ \
 56.1480 +		if (opcode & 0x00100000) { \
 56.1481 +			clockTicks++; \
 56.1482 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1483 +		} \
 56.1484 +		if (armState) { \
 56.1485 +			reg[15].I &= 0xFFFFFFFC; \
 56.1486 +			armNextPC  = reg[15].I; \
 56.1487 +			reg[15].I += 4; \
 56.1488 +		} else { \
 56.1489 +			reg[15].I &= 0xFFFFFFFE; \
 56.1490 +			armNextPC  = reg[15].I; \
 56.1491 +			reg[15].I += 2; \
 56.1492 +		} \
 56.1493 +	} else { \
 56.1494 +		OPCODE \
 56.1495 +	} \
 56.1496 +} \
 56.1497 +break; \
 56.1498 +case BASE + 2: \
 56.1499 +case BASE + 10: \
 56.1500 +{ \
 56.1501 +	/* OP Rd,Rb,Rm LSR # */ \
 56.1502 +	int	 shift = (opcode >> 7) & 0x1F; \
 56.1503 +	int	 dest  = (opcode >> 12) & 15; \
 56.1504 +	bool C_OUT = C_FLAG; \
 56.1505 +	u32	 value; \
 56.1506 +	if (shift) { \
 56.1507 +		LOGICAL_LSR_REG \
 56.1508 +	} else { \
 56.1509 +		value = 0; \
 56.1510 +		C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false; \
 56.1511 +	} \
 56.1512 +      \
 56.1513 +	if (dest == 15) { \
 56.1514 +		OPCODE2 \
 56.1515 +		/* todo */ \
 56.1516 +		if (opcode & 0x00100000) { \
 56.1517 +			clockTicks++; \
 56.1518 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1519 +		} \
 56.1520 +		if (armState) { \
 56.1521 +			reg[15].I &= 0xFFFFFFFC; \
 56.1522 +			armNextPC  = reg[15].I; \
 56.1523 +			reg[15].I += 4; \
 56.1524 +		} else { \
 56.1525 +			reg[15].I &= 0xFFFFFFFE; \
 56.1526 +			armNextPC  = reg[15].I; \
 56.1527 +			reg[15].I += 2; \
 56.1528 +		} \
 56.1529 +	} else { \
 56.1530 +		OPCODE \
 56.1531 +	} \
 56.1532 +} \
 56.1533 +break; \
 56.1534 +case BASE + 4: \
 56.1535 +case BASE + 12: \
 56.1536 +{ \
 56.1537 +	/* OP Rd,Rb,Rm ASR # */ \
 56.1538 +	int	 shift = (opcode >> 7) & 0x1F; \
 56.1539 +	int	 dest  = (opcode >> 12) & 15; \
 56.1540 +	bool C_OUT = C_FLAG; \
 56.1541 +	u32	 value; \
 56.1542 +	if (shift) { \
 56.1543 +		LOGICAL_ASR_REG \
 56.1544 +	} else { \
 56.1545 +		if (reg[opcode & 0x0F].I & 0x80000000) { \
 56.1546 +			value = 0xFFFFFFFF; \
 56.1547 +			C_OUT = true; \
 56.1548 +		} else { \
 56.1549 +			value = 0; \
 56.1550 +			C_OUT = false; \
 56.1551 +		}                   \
 56.1552 +	} \
 56.1553 +      \
 56.1554 +	if (dest == 15) { \
 56.1555 +		OPCODE2 \
 56.1556 +		/* todo */ \
 56.1557 +		if (opcode & 0x00100000) { \
 56.1558 +			clockTicks++; \
 56.1559 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1560 +		} \
 56.1561 +		if (armState) { \
 56.1562 +			reg[15].I &= 0xFFFFFFFC; \
 56.1563 +			armNextPC  = reg[15].I; \
 56.1564 +			reg[15].I += 4; \
 56.1565 +		} else { \
 56.1566 +			reg[15].I &= 0xFFFFFFFE; \
 56.1567 +			armNextPC  = reg[15].I; \
 56.1568 +			reg[15].I += 2; \
 56.1569 +		} \
 56.1570 +	} else { \
 56.1571 +		OPCODE \
 56.1572 +	} \
 56.1573 +} \
 56.1574 +break; \
 56.1575 +case BASE + 6: \
 56.1576 +case BASE + 14: \
 56.1577 +{ \
 56.1578 +	/* OP Rd,Rb,Rm ROR # */ \
 56.1579 +	int	 shift = (opcode >> 7) & 0x1F; \
 56.1580 +	int	 dest  = (opcode >> 12) & 15; \
 56.1581 +	bool C_OUT = C_FLAG; \
 56.1582 +	u32	 value; \
 56.1583 +	if (shift) { \
 56.1584 +		LOGICAL_ROR_REG \
 56.1585 +	} else { \
 56.1586 +		LOGICAL_RRX_REG \
 56.1587 +	} \
 56.1588 +	if (dest == 15) { \
 56.1589 +		OPCODE2 \
 56.1590 +		/* todo */ \
 56.1591 +		if (opcode & 0x00100000) { \
 56.1592 +			clockTicks++; \
 56.1593 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1594 +		} \
 56.1595 +		if (armState) { \
 56.1596 +			reg[15].I &= 0xFFFFFFFC; \
 56.1597 +			armNextPC  = reg[15].I; \
 56.1598 +			reg[15].I += 4; \
 56.1599 +		} else { \
 56.1600 +			reg[15].I &= 0xFFFFFFFE; \
 56.1601 +			armNextPC  = reg[15].I; \
 56.1602 +			reg[15].I += 2; \
 56.1603 +		} \
 56.1604 +	} else { \
 56.1605 +		OPCODE \
 56.1606 +	} \
 56.1607 +} \
 56.1608 +break; \
 56.1609 +case BASE + 1: \
 56.1610 +{ \
 56.1611 +	/* OP Rd,Rb,Rm LSL Rs */ \
 56.1612 +	clockTicks++; \
 56.1613 +	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1614 +	int	 dest  = (opcode >> 12) & 15; \
 56.1615 +	bool C_OUT = C_FLAG; \
 56.1616 +	u32	 value; \
 56.1617 +	if (shift) { \
 56.1618 +		if (shift == 32) { \
 56.1619 +			value = 0; \
 56.1620 +			C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false); \
 56.1621 +		} else if (shift < 32) { \
 56.1622 +			LOGICAL_LSL_REG \
 56.1623 +		} else { \
 56.1624 +			value = 0; \
 56.1625 +			C_OUT = false; \
 56.1626 +		} \
 56.1627 +	} else { \
 56.1628 +		value = reg[opcode & 0x0F].I; \
 56.1629 +	} \
 56.1630 +	if (dest == 15) { \
 56.1631 +		OPCODE2 \
 56.1632 +		/* todo */ \
 56.1633 +		if (opcode & 0x00100000) { \
 56.1634 +			clockTicks++; \
 56.1635 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1636 +		} \
 56.1637 +		if (armState) { \
 56.1638 +			reg[15].I &= 0xFFFFFFFC; \
 56.1639 +			armNextPC  = reg[15].I; \
 56.1640 +			reg[15].I += 4; \
 56.1641 +		} else { \
 56.1642 +			reg[15].I &= 0xFFFFFFFE; \
 56.1643 +			armNextPC  = reg[15].I; \
 56.1644 +			reg[15].I += 2; \
 56.1645 +		} \
 56.1646 +	} else { \
 56.1647 +		OPCODE \
 56.1648 +	} \
 56.1649 +} \
 56.1650 +break; \
 56.1651 +case BASE + 3: \
 56.1652 +{ \
 56.1653 +	/* OP Rd,Rb,Rm LSR Rs */ \
 56.1654 +	clockTicks++; \
 56.1655 +	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1656 +	int	 dest  = (opcode >> 12) & 15; \
 56.1657 +	bool C_OUT = C_FLAG; \
 56.1658 +	u32	 value; \
 56.1659 +	if (shift) { \
 56.1660 +		if (shift == 32) { \
 56.1661 +			value = 0; \
 56.1662 +			C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false); \
 56.1663 +		} else if (shift < 32) { \
 56.1664 +			LOGICAL_LSR_REG \
 56.1665 +		} else { \
 56.1666 +			value = 0; \
 56.1667 +			C_OUT = false; \
 56.1668 +		} \
 56.1669 +	} else { \
 56.1670 +		value = reg[opcode & 0x0F].I; \
 56.1671 +	} \
 56.1672 +	if (dest == 15) { \
 56.1673 +		OPCODE2 \
 56.1674 +		/* todo */ \
 56.1675 +		if (opcode & 0x00100000) { \
 56.1676 +			clockTicks++; \
 56.1677 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1678 +		} \
 56.1679 +		if (armState) { \
 56.1680 +			reg[15].I &= 0xFFFFFFFC; \
 56.1681 +			armNextPC  = reg[15].I; \
 56.1682 +			reg[15].I += 4; \
 56.1683 +		} else { \
 56.1684 +			reg[15].I &= 0xFFFFFFFE; \
 56.1685 +			armNextPC  = reg[15].I; \
 56.1686 +			reg[15].I += 2; \
 56.1687 +		} \
 56.1688 +	} else { \
 56.1689 +		OPCODE \
 56.1690 +	} \
 56.1691 +} \
 56.1692 +break; \
 56.1693 +case BASE + 5: \
 56.1694 +{ \
 56.1695 +	/* OP Rd,Rb,Rm ASR Rs */ \
 56.1696 +	clockTicks++; \
 56.1697 +	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1698 +	int	 dest  = (opcode >> 12) & 15; \
 56.1699 +	bool C_OUT = C_FLAG; \
 56.1700 +	u32	 value; \
 56.1701 +	if (shift < 32) { \
 56.1702 +		if (shift) { \
 56.1703 +			LOGICAL_ASR_REG \
 56.1704 +		} else { \
 56.1705 +			value = reg[opcode & 0x0F].I; \
 56.1706 +		} \
 56.1707 +	} else { \
 56.1708 +		if (reg[opcode & 0x0F].I & 0x80000000) { \
 56.1709 +			value = 0xFFFFFFFF; \
 56.1710 +			C_OUT = true; \
 56.1711 +		} else { \
 56.1712 +			value = 0; \
 56.1713 +			C_OUT = false; \
 56.1714 +		} \
 56.1715 +	} \
 56.1716 +	if (dest == 15) { \
 56.1717 +		OPCODE2 \
 56.1718 +		/* todo */ \
 56.1719 +		if (opcode & 0x00100000) { \
 56.1720 +			clockTicks++; \
 56.1721 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1722 +		} \
 56.1723 +		if (armState) { \
 56.1724 +			reg[15].I &= 0xFFFFFFFC; \
 56.1725 +			armNextPC  = reg[15].I; \
 56.1726 +			reg[15].I += 4; \
 56.1727 +		} else { \
 56.1728 +			reg[15].I &= 0xFFFFFFFE; \
 56.1729 +			armNextPC  = reg[15].I; \
 56.1730 +			reg[15].I += 2; \
 56.1731 +		} \
 56.1732 +	} else { \
 56.1733 +		OPCODE \
 56.1734 +	} \
 56.1735 +} \
 56.1736 +break; \
 56.1737 +case BASE + 7: \
 56.1738 +{ \
 56.1739 +	/* OP Rd,Rb,Rm ROR Rs */ \
 56.1740 +	clockTicks++; \
 56.1741 +	int	 shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1742 +	int	 dest  = (opcode >> 12) & 15; \
 56.1743 +	bool C_OUT = C_FLAG; \
 56.1744 +	u32	 value; \
 56.1745 +	if (shift) { \
 56.1746 +		shift &= 0x1f; \
 56.1747 +		if (shift) { \
 56.1748 +			LOGICAL_ROR_REG \
 56.1749 +		} else { \
 56.1750 +			value = reg[opcode & 0x0F].I; \
 56.1751 +			C_OUT = (value & 0x80000000 ? true : false); \
 56.1752 +		} \
 56.1753 +	} else { \
 56.1754 +		value = reg[opcode & 0x0F].I; \
 56.1755 +		C_OUT = (value & 0x80000000 ? true : false); \
 56.1756 +	} \
 56.1757 +	if (dest == 15) { \
 56.1758 +		OPCODE2 \
 56.1759 +		/* todo */ \
 56.1760 +		if (opcode & 0x00100000) { \
 56.1761 +			clockTicks++; \
 56.1762 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1763 +		} \
 56.1764 +		if (armState) { \
 56.1765 +			reg[15].I &= 0xFFFFFFFC; \
 56.1766 +			armNextPC  = reg[15].I; \
 56.1767 +			reg[15].I += 4; \
 56.1768 +		} else { \
 56.1769 +			reg[15].I &= 0xFFFFFFFE; \
 56.1770 +			armNextPC  = reg[15].I; \
 56.1771 +			reg[15].I += 2; \
 56.1772 +		} \
 56.1773 +	} else { \
 56.1774 +		OPCODE \
 56.1775 +	} \
 56.1776 +} \
 56.1777 +break; \
 56.1778 +case BASE + 0x200: \
 56.1779 +case BASE + 0x201: \
 56.1780 +case BASE + 0x202: \
 56.1781 +case BASE + 0x203: \
 56.1782 +case BASE + 0x204: \
 56.1783 +case BASE + 0x205: \
 56.1784 +case BASE + 0x206: \
 56.1785 +case BASE + 0x207: \
 56.1786 +case BASE + 0x208: \
 56.1787 +case BASE + 0x209: \
 56.1788 +case BASE + 0x20a: \
 56.1789 +case BASE + 0x20b: \
 56.1790 +case BASE + 0x20c: \
 56.1791 +case BASE + 0x20d: \
 56.1792 +case BASE + 0x20e: \
 56.1793 +case BASE + 0x20f: \
 56.1794 +{ \
 56.1795 +	int	 shift = (opcode & 0xF00) >> 7; \
 56.1796 +	int	 dest  = (opcode >> 12) & 0x0F; \
 56.1797 +	bool C_OUT = C_FLAG; \
 56.1798 +	u32	 value; \
 56.1799 +	if (shift) { \
 56.1800 +		LOGICAL_ROR_IMM \
 56.1801 +	} else { \
 56.1802 +		value = opcode & 0xff; \
 56.1803 +	} \
 56.1804 +	if (dest == 15) { \
 56.1805 +		OPCODE2 \
 56.1806 +		/* todo */ \
 56.1807 +		if (opcode & 0x00100000) { \
 56.1808 +			clockTicks++; \
 56.1809 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1810 +		} \
 56.1811 +		if (armState) { \
 56.1812 +			reg[15].I &= 0xFFFFFFFC; \
 56.1813 +			armNextPC  = reg[15].I; \
 56.1814 +			reg[15].I += 4; \
 56.1815 +		} else { \
 56.1816 +			reg[15].I &= 0xFFFFFFFE; \
 56.1817 +			armNextPC  = reg[15].I; \
 56.1818 +			reg[15].I += 2; \
 56.1819 +		} \
 56.1820 +	} else { \
 56.1821 +		OPCODE \
 56.1822 +	} \
 56.1823 +} \
 56.1824 +break;
 56.1825 +
 56.1826 +#define ARITHMETIC_DATA_OPCODE(OPCODE, OPCODE2, BASE) \
 56.1827 +case BASE: \
 56.1828 +case BASE + 8: \
 56.1829 +{ \
 56.1830 +	/* OP Rd,Rb,Rm LSL # */ \
 56.1831 +	int base  = (opcode >> 16) & 0x0F; \
 56.1832 +	int shift = (opcode >> 7) & 0x1F; \
 56.1833 +	int dest  = (opcode >> 12) & 15; \
 56.1834 +	u32 value; \
 56.1835 +	if (shift) { \
 56.1836 +		ARITHMETIC_LSL_REG \
 56.1837 +	} else { \
 56.1838 +		value = reg[opcode & 0x0F].I; \
 56.1839 +	} \
 56.1840 +	if (dest == 15) { \
 56.1841 +		OPCODE2 \
 56.1842 +		/* todo */ \
 56.1843 +		if (opcode & 0x00100000) { \
 56.1844 +			clockTicks++; \
 56.1845 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1846 +		} \
 56.1847 +		if (armState) { \
 56.1848 +			reg[15].I &= 0xFFFFFFFC; \
 56.1849 +			armNextPC  = reg[15].I; \
 56.1850 +			reg[15].I += 4; \
 56.1851 +		} else { \
 56.1852 +			reg[15].I &= 0xFFFFFFFE; \
 56.1853 +			armNextPC  = reg[15].I; \
 56.1854 +			reg[15].I += 2; \
 56.1855 +		} \
 56.1856 +	} else { \
 56.1857 +		OPCODE \
 56.1858 +	} \
 56.1859 +} \
 56.1860 +break; \
 56.1861 +case BASE + 2: \
 56.1862 +case BASE + 10: \
 56.1863 +{ \
 56.1864 +	/* OP Rd,Rb,Rm LSR # */ \
 56.1865 +	int base  = (opcode >> 16) & 0x0F; \
 56.1866 +	int shift = (opcode >> 7) & 0x1F; \
 56.1867 +	int dest  = (opcode >> 12) & 15; \
 56.1868 +	u32 value; \
 56.1869 +	if (shift) { \
 56.1870 +		ARITHMETIC_LSR_REG \
 56.1871 +	} else { \
 56.1872 +		value = 0; \
 56.1873 +	} \
 56.1874 +	if (dest == 15) { \
 56.1875 +		OPCODE2 \
 56.1876 +		/* todo */ \
 56.1877 +		if (opcode & 0x00100000) { \
 56.1878 +			clockTicks++; \
 56.1879 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1880 +		} \
 56.1881 +		if (armState) { \
 56.1882 +			reg[15].I &= 0xFFFFFFFC; \
 56.1883 +			armNextPC  = reg[15].I; \
 56.1884 +			reg[15].I += 4; \
 56.1885 +		} else { \
 56.1886 +			reg[15].I &= 0xFFFFFFFE; \
 56.1887 +			armNextPC  = reg[15].I; \
 56.1888 +			reg[15].I += 2; \
 56.1889 +		} \
 56.1890 +	} else { \
 56.1891 +		OPCODE \
 56.1892 +	} \
 56.1893 +} \
 56.1894 +break; \
 56.1895 +case BASE + 4: \
 56.1896 +case BASE + 12: \
 56.1897 +{ \
 56.1898 +	/* OP Rd,Rb,Rm ASR # */ \
 56.1899 +	int base  = (opcode >> 16) & 0x0F; \
 56.1900 +	int shift = (opcode >> 7) & 0x1F; \
 56.1901 +	int dest  = (opcode >> 12) & 15; \
 56.1902 +	u32 value; \
 56.1903 +	if (shift) { \
 56.1904 +		ARITHMETIC_ASR_REG \
 56.1905 +	} else { \
 56.1906 +		if (reg[opcode & 0x0F].I & 0x80000000) { \
 56.1907 +			value = 0xFFFFFFFF; \
 56.1908 +		} else value = 0; \
 56.1909 +	} \
 56.1910 +	if (dest == 15) { \
 56.1911 +		OPCODE2 \
 56.1912 +		/* todo */ \
 56.1913 +		if (opcode & 0x00100000) { \
 56.1914 +			clockTicks++; \
 56.1915 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1916 +		} \
 56.1917 +		if (armState) { \
 56.1918 +			reg[15].I &= 0xFFFFFFFC; \
 56.1919 +			armNextPC  = reg[15].I; \
 56.1920 +			reg[15].I += 4; \
 56.1921 +		} else { \
 56.1922 +			reg[15].I &= 0xFFFFFFFE; \
 56.1923 +			armNextPC  = reg[15].I; \
 56.1924 +			reg[15].I += 2; \
 56.1925 +		} \
 56.1926 +	} else { \
 56.1927 +		OPCODE \
 56.1928 +	} \
 56.1929 +} \
 56.1930 +break; \
 56.1931 +case BASE + 6: \
 56.1932 +case BASE + 14: \
 56.1933 +{ \
 56.1934 +	/* OP Rd,Rb,Rm ROR # */ \
 56.1935 +	int base  = (opcode >> 16) & 0x0F; \
 56.1936 +	int shift = (opcode >> 7) & 0x1F; \
 56.1937 +	int dest  = (opcode >> 12) & 15; \
 56.1938 +	u32 value; \
 56.1939 +	if (shift) { \
 56.1940 +		ARITHMETIC_ROR_REG \
 56.1941 +	} else { \
 56.1942 +		ARITHMETIC_RRX_REG \
 56.1943 +	} \
 56.1944 +	if (dest == 15) { \
 56.1945 +		OPCODE2 \
 56.1946 +		/* todo */ \
 56.1947 +		if (opcode & 0x00100000) { \
 56.1948 +			clockTicks++; \
 56.1949 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1950 +		} \
 56.1951 +		if (armState) { \
 56.1952 +			reg[15].I &= 0xFFFFFFFC; \
 56.1953 +			armNextPC  = reg[15].I; \
 56.1954 +			reg[15].I += 4; \
 56.1955 +		} else { \
 56.1956 +			reg[15].I &= 0xFFFFFFFE; \
 56.1957 +			armNextPC  = reg[15].I; \
 56.1958 +			reg[15].I += 2; \
 56.1959 +		} \
 56.1960 +	} else { \
 56.1961 +		OPCODE \
 56.1962 +	} \
 56.1963 +} \
 56.1964 +break; \
 56.1965 +case BASE + 1: \
 56.1966 +{ \
 56.1967 +	/* OP Rd,Rb,Rm LSL Rs */ \
 56.1968 +	clockTicks++; \
 56.1969 +	int base  = (opcode >> 16) & 0x0F; \
 56.1970 +	int shift = reg[(opcode >> 8) & 15].B.B0; \
 56.1971 +	int dest  = (opcode >> 12) & 15; \
 56.1972 +	u32 value; \
 56.1973 +	if (shift) { \
 56.1974 +		if (shift == 32) { \
 56.1975 +			value = 0; \
 56.1976 +		} else if (shift < 32) { \
 56.1977 +			ARITHMETIC_LSL_REG \
 56.1978 +		} else value = 0; \
 56.1979 +	} else { \
 56.1980 +		value = reg[opcode & 0x0F].I; \
 56.1981 +	} \
 56.1982 +	if (dest == 15) { \
 56.1983 +		OPCODE2 \
 56.1984 +		/* todo */ \
 56.1985 +		if (opcode & 0x00100000) { \
 56.1986 +			clockTicks++; \
 56.1987 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.1988 +		} \
 56.1989 +		if (armState) { \
 56.1990 +			reg[15].I &= 0xFFFFFFFC; \
 56.1991 +			armNextPC  = reg[15].I; \
 56.1992 +			reg[15].I += 4; \
 56.1993 +		} else { \
 56.1994 +			reg[15].I &= 0xFFFFFFFE; \
 56.1995 +			armNextPC  = reg[15].I; \
 56.1996 +			reg[15].I += 2; \
 56.1997 +		} \
 56.1998 +	} else { \
 56.1999 +		OPCODE \
 56.2000 +	} \
 56.2001 +} \
 56.2002 +break; \
 56.2003 +case BASE + 3: \
 56.2004 +{ \
 56.2005 +	/* OP Rd,Rb,Rm LSR Rs */ \
 56.2006 +	clockTicks++; \
 56.2007 +	int base  = (opcode >> 16) & 0x0F; \
 56.2008 +	int shift = reg[(opcode >> 8) & 15].B.B0; \
 56.2009 +	int dest  = (opcode >> 12) & 15; \
 56.2010 +	u32 value; \
 56.2011 +	if (shift) { \
 56.2012 +		if (shift == 32) { \
 56.2013 +			value = 0; \
 56.2014 +		} else if (shift < 32) { \
 56.2015 +			ARITHMETIC_LSR_REG \
 56.2016 +		} else value = 0; \
 56.2017 +	} else { \
 56.2018 +		value = reg[opcode & 0x0F].I; \
 56.2019 +	} \
 56.2020 +	if (dest == 15) { \
 56.2021 +		OPCODE2 \
 56.2022 +		/* todo */ \
 56.2023 +		if (opcode & 0x00100000) { \
 56.2024 +			clockTicks++; \
 56.2025 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.2026 +		} \
 56.2027 +		if (armState) { \
 56.2028 +			reg[15].I &= 0xFFFFFFFC; \
 56.2029 +			armNextPC  = reg[15].I; \
 56.2030 +			reg[15].I += 4; \
 56.2031 +		} else { \
 56.2032 +			reg[15].I &= 0xFFFFFFFE; \
 56.2033 +			armNextPC  = reg[15].I; \
 56.2034 +			reg[15].I += 2; \
 56.2035 +		} \
 56.2036 +	} else { \
 56.2037 +		OPCODE \
 56.2038 +	} \
 56.2039 +} \
 56.2040 +break; \
 56.2041 +case BASE + 5: \
 56.2042 +{ \
 56.2043 +	/* OP Rd,Rb,Rm ASR Rs */ \
 56.2044 +	clockTicks++; \
 56.2045 +	int base  = (opcode >> 16) & 0x0F; \
 56.2046 +	int shift = reg[(opcode >> 8) & 15].B.B0; \
 56.2047 +	int dest  = (opcode >> 12) & 15; \
 56.2048 +	u32 value; \
 56.2049 +	if (shift < 32) { \
 56.2050 +		if (shift) { \
 56.2051 +			ARITHMETIC_ASR_REG \
 56.2052 +		} else { \
 56.2053 +			value = reg[opcode & 0x0F].I; \
 56.2054 +		} \
 56.2055 +	} else { \
 56.2056 +		if (reg[opcode & 0x0F].I & 0x80000000) { \
 56.2057 +			value = 0xFFFFFFFF; \
 56.2058 +		} else value = 0; \
 56.2059 +	} \
 56.2060 +	if (dest == 15) { \
 56.2061 +		OPCODE2 \
 56.2062 +		/* todo */ \
 56.2063 +		if (opcode & 0x00100000) { \
 56.2064 +			clockTicks++; \
 56.2065 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.2066 +		} \
 56.2067 +		if (armState) { \
 56.2068 +			reg[15].I &= 0xFFFFFFFC; \
 56.2069 +			armNextPC  = reg[15].I; \
 56.2070 +			reg[15].I += 4; \
 56.2071 +		} else { \
 56.2072 +			reg[15].I &= 0xFFFFFFFE; \
 56.2073 +			armNextPC  = reg[15].I; \
 56.2074 +			reg[15].I += 2; \
 56.2075 +		} \
 56.2076 +	} else { \
 56.2077 +		OPCODE \
 56.2078 +	} \
 56.2079 +} \
 56.2080 +break; \
 56.2081 +case BASE + 7: \
 56.2082 +{ \
 56.2083 +	/* OP Rd,Rb,Rm ROR Rs */ \
 56.2084 +	clockTicks++; \
 56.2085 +	int base  = (opcode >> 16) & 0x0F; \
 56.2086 +	int shift = reg[(opcode >> 8) & 15].B.B0; \
 56.2087 +	int dest  = (opcode >> 12) & 15; \
 56.2088 +	u32 value; \
 56.2089 +	if (shift) { \
 56.2090 +		shift &= 0x1f; \
 56.2091 +		if (shift) { \
 56.2092 +			ARITHMETIC_ROR_REG \
 56.2093 +		} else { \
 56.2094 +			value = reg[opcode & 0x0F].I; \
 56.2095 +		} \
 56.2096 +	} else { \
 56.2097 +		value = reg[opcode & 0x0F].I; \
 56.2098 +	} \
 56.2099 +	if (dest == 15) { \
 56.2100 +		OPCODE2 \
 56.2101 +		/* todo */ \
 56.2102 +		if (opcode & 0x00100000) { \
 56.2103 +			clockTicks++; \
 56.2104 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.2105 +		} \
 56.2106 +		if (armState) { \
 56.2107 +			reg[15].I &= 0xFFFFFFFC; \
 56.2108 +			armNextPC  = reg[15].I; \
 56.2109 +			reg[15].I += 4; \
 56.2110 +		} else { \
 56.2111 +			reg[15].I &= 0xFFFFFFFE; \
 56.2112 +			armNextPC  = reg[15].I; \
 56.2113 +			reg[15].I += 2; \
 56.2114 +		} \
 56.2115 +	} else { \
 56.2116 +		OPCODE \
 56.2117 +	} \
 56.2118 +} \
 56.2119 +break; \
 56.2120 +case BASE + 0x200: \
 56.2121 +case BASE + 0x201: \
 56.2122 +case BASE + 0x202: \
 56.2123 +case BASE + 0x203: \
 56.2124 +case BASE + 0x204: \
 56.2125 +case BASE + 0x205: \
 56.2126 +case BASE + 0x206: \
 56.2127 +case BASE + 0x207: \
 56.2128 +case BASE + 0x208: \
 56.2129 +case BASE + 0x209: \
 56.2130 +case BASE + 0x20a: \
 56.2131 +case BASE + 0x20b: \
 56.2132 +case BASE + 0x20c: \
 56.2133 +case BASE + 0x20d: \
 56.2134 +case BASE + 0x20e: \
 56.2135 +case BASE + 0x20f: \
 56.2136 +{ \
 56.2137 +	int shift = (opcode & 0xF00) >> 7; \
 56.2138 +	int base  = (opcode >> 16) & 0x0F; \
 56.2139 +	int dest  = (opcode >> 12) & 0x0F; \
 56.2140 +	u32 value; \
 56.2141 +	{ \
 56.2142 +		ARITHMETIC_ROR_IMM \
 56.2143 +	} \
 56.2144 +	if (dest == 15) { \
 56.2145 +		OPCODE2 \
 56.2146 +		/* todo */ \
 56.2147 +		if (opcode & 0x00100000) { \
 56.2148 +			clockTicks++; \
 56.2149 +			CPUSwitchMode(reg[17].I & 0x1f, false); \
 56.2150 +		} \
 56.2151 +		if (armState) { \
 56.2152 +			reg[15].I &= 0xFFFFFFFC; \
 56.2153 +			armNextPC  = reg[15].I; \
 56.2154 +			reg[15].I += 4; \
 56.2155 +		} else { \
 56.2156 +			reg[15].I &= 0xFFFFFFFE; \
 56.2157 +			armNextPC  = reg[15].I; \
 56.2158 +			reg[15].I += 2; \
 56.2159 +		} \
 56.2160 +	} else { \
 56.2161 +		OPCODE \
 56.2162 +	} \
 56.2163 +} \
 56.2164 +break;
 56.2165 +
 56.2166 +u32 opcode = CPUReadMemoryQuick(armNextPC);
 56.2167 +
 56.2168 +clockTicks = memoryWaitFetch32[(armNextPC >> 24) & 15];
 56.2169 +
 56.2170 +#ifndef FINAL_VERSION
 56.2171 +if (armNextPC == stop)
 56.2172 +{
 56.2173 +	armNextPC++;
 56.2174 +}
 56.2175 +#endif
 56.2176 +
 56.2177 +armNextPC  = reg[15].I;
 56.2178 +reg[15].I += 4;
 56.2179 +int cond = opcode >> 28;
 56.2180 +// suggested optimization for frequent cases
 56.2181 +bool cond_res;
 56.2182 +if (cond == 0x0e)
 56.2183 +{
 56.2184 +	cond_res = true;
 56.2185 +}
 56.2186 +else
 56.2187 +{
 56.2188 +	switch (cond)
 56.2189 +	{
 56.2190 +	case 0x00: // EQ
 56.2191 +		cond_res = Z_FLAG;
 56.2192 +		break;
 56.2193 +	case 0x01: // NE
 56.2194 +		cond_res = !Z_FLAG;
 56.2195 +		break;
 56.2196 +	case 0x02: // CS
 56.2197 +		cond_res = C_FLAG;
 56.2198 +		break;
 56.2199 +	case 0x03: // CC
 56.2200 +		cond_res = !C_FLAG;
 56.2201 +		break;
 56.2202 +	case 0x04: // MI
 56.2203 +		cond_res = N_FLAG;
 56.2204 +		break;
 56.2205 +	case 0x05: // PL
 56.2206 +		cond_res = !N_FLAG;
 56.2207 +		break;
 56.2208 +	case 0x06: // VS
 56.2209 +		cond_res = V_FLAG;
 56.2210 +		break;
 56.2211 +	case 0x07: // VC
 56.2212 +		cond_res = !V_FLAG;
 56.2213 +		break;
 56.2214 +	case 0x08: // HI
 56.2215 +		cond_res = C_FLAG && !Z_FLAG;
 56.2216 +		break;
 56.2217 +	case 0x09: // LS
 56.2218 +		cond_res = !C_FLAG || Z_FLAG;
 56.2219 +		break;
 56.2220 +	case 0x0A: // GE
 56.2221 +		cond_res = N_FLAG == V_FLAG;
 56.2222 +		break;
 56.2223 +	case 0x0B: // LT
 56.2224 +		cond_res = N_FLAG != V_FLAG;
 56.2225 +		break;
 56.2226 +	case 0x0C: // GT
 56.2227 +		cond_res = !Z_FLAG && (N_FLAG == V_FLAG);
 56.2228 +		break;
 56.2229 +	case 0x0D: // LE
 56.2230 +		cond_res = Z_FLAG || (N_FLAG != V_FLAG);
 56.2231 +		break;
 56.2232 +	case 0x0E:
 56.2233 +		cond_res = true;
 56.2234 +		break;
 56.2235 +	case 0x0F:
 56.2236 +	default:
 56.2237 +		// ???
 56.2238 +		cond_res = false;
 56.2239 +		break;
 56.2240 +	}
 56.2241 +}
 56.2242 +
 56.2243 +if (cond_res)
 56.2244 +{
 56.2245 +	switch (((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x0F))
 56.2246 +	{
 56.2247 +		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_AND,  OP_AND, 0x000);
 56.2248 +		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_ANDS, OP_AND, 0x010);
 56.2249 +	case 0x009:
 56.2250 +	{
 56.2251 +		// MUL Rd, Rm, Rs
 56.2252 +		int dest = (opcode >> 16) & 0x0F;
 56.2253 +		int mult = (opcode & 0x0F);
 56.2254 +		u32 rs	 = reg[(opcode >> 8) & 0x0F].I;
 56.2255 +		reg[dest].I = reg[mult].I * rs;
 56.2256 +		if (((s32)rs) < 0)
 56.2257 +			rs = ~rs;
 56.2258 +		if ((rs & 0xFFFFFF00) == 0)
 56.2259 +			clockTicks += 2;
 56.2260 +		else if ((rs & 0xFFFF0000) == 0)
 56.2261 +			clockTicks += 3;
 56.2262 +		else if ((rs & 0xFF000000) == 0)
 56.2263 +			clockTicks += 4;
 56.2264 +		else
 56.2265 +			clockTicks += 5;
 56.2266 +	}
 56.2267 +	break;
 56.2268 +	case 0x019:
 56.2269 +	{
 56.2270 +		// MULS Rd, Rm, Rs
 56.2271 +		int dest = (opcode >> 16) & 0x0F;
 56.2272 +		int mult = (opcode & 0x0F);
 56.2273 +		u32 rs	 = reg[(opcode >> 8) & 0x0F].I;
 56.2274 +		reg[dest].I = reg[mult].I * rs;
 56.2275 +		N_FLAG		= (reg[dest].I & 0x80000000) ? true : false;
 56.2276 +		Z_FLAG		= (reg[dest].I) ? false : true;
 56.2277 +		if (((s32)rs) < 0)
 56.2278 +			rs = ~rs;
 56.2279 +		if ((rs & 0xFFFFFF00) == 0)
 56.2280 +			clockTicks += 2;
 56.2281 +		else if ((rs & 0xFFFF0000) == 0)
 56.2282 +			clockTicks += 3;
 56.2283 +		else if ((rs & 0xFF000000) == 0)
 56.2284 +			clockTicks += 4;
 56.2285 +		else
 56.2286 +			clockTicks += 5;
 56.2287 +	}
 56.2288 +	break;
 56.2289 +	case 0x00b:
 56.2290 +	case 0x02b:
 56.2291 +	{
 56.2292 +		// STRH Rd, [Rn], -Rm
 56.2293 +		int base	= (opcode >> 16) & 0x0F;
 56.2294 +		int dest	= (opcode >> 12) & 0x0F;
 56.2295 +		u32 address = reg[base].I;
 56.2296 +		int offset	= reg[opcode & 0x0F].I;
 56.2297 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2298 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2299 +		address	   -= offset;
 56.2300 +		reg[base].I = address;
 56.2301 +	}
 56.2302 +	break;
 56.2303 +	case 0x04b:
 56.2304 +	case 0x06b:
 56.2305 +	{
 56.2306 +		// STRH Rd, [Rn], #-offset
 56.2307 +		int base	= (opcode >> 16) & 0x0F;
 56.2308 +		int dest	= (opcode >> 12) & 0x0F;
 56.2309 +		u32 address = reg[base].I;
 56.2310 +		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
 56.2311 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2312 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2313 +		address	   -= offset;
 56.2314 +		reg[base].I = address;
 56.2315 +	}
 56.2316 +	break;
 56.2317 +	case 0x08b:
 56.2318 +	case 0x0ab:
 56.2319 +	{
 56.2320 +		// STRH Rd, [Rn], Rm
 56.2321 +		int base	= (opcode >> 16) & 0x0F;
 56.2322 +		int dest	= (opcode >> 12) & 0x0F;
 56.2323 +		u32 address = reg[base].I;
 56.2324 +		int offset	= reg[opcode & 0x0F].I;
 56.2325 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2326 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2327 +		address	   += offset;
 56.2328 +		reg[base].I = address;
 56.2329 +	}
 56.2330 +	break;
 56.2331 +	case 0x0cb:
 56.2332 +	case 0x0eb:
 56.2333 +	{
 56.2334 +		// STRH Rd, [Rn], #offset
 56.2335 +		int base	= (opcode >> 16) & 0x0F;
 56.2336 +		int dest	= (opcode >> 12) & 0x0F;
 56.2337 +		u32 address = reg[base].I;
 56.2338 +		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
 56.2339 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2340 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2341 +		address	   += offset;
 56.2342 +		reg[base].I = address;
 56.2343 +	}
 56.2344 +	break;
 56.2345 +	case 0x10b:
 56.2346 +	{
 56.2347 +		// STRH Rd, [Rn, -Rm]
 56.2348 +		int base	= (opcode >> 16) & 0x0F;
 56.2349 +		int dest	= (opcode >> 12) & 0x0F;
 56.2350 +		u32 address = reg[base].I - reg[opcode & 0x0F].I;
 56.2351 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2352 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2353 +	}
 56.2354 +	break;
 56.2355 +	case 0x12b:
 56.2356 +	{
 56.2357 +		// STRH Rd, [Rn, -Rm]!
 56.2358 +		int base	= (opcode >> 16) & 0x0F;
 56.2359 +		int dest	= (opcode >> 12) & 0x0F;
 56.2360 +		u32 address = reg[base].I - reg[opcode & 0x0F].I;
 56.2361 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2362 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2363 +		reg[base].I = address;
 56.2364 +	}
 56.2365 +	break;
 56.2366 +	case 0x14b:
 56.2367 +	{
 56.2368 +		// STRH Rd, [Rn, -#offset]
 56.2369 +		int base	= (opcode >> 16) & 0x0F;
 56.2370 +		int dest	= (opcode >> 12) & 0x0F;
 56.2371 +		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2372 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2373 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2374 +	}
 56.2375 +	break;
 56.2376 +	case 0x16b:
 56.2377 +	{
 56.2378 +		// STRH Rd, [Rn, -#offset]!
 56.2379 +		int base	= (opcode >> 16) & 0x0F;
 56.2380 +		int dest	= (opcode >> 12) & 0x0F;
 56.2381 +		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2382 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2383 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2384 +		reg[base].I = address;
 56.2385 +	}
 56.2386 +	break;
 56.2387 +	case 0x18b:
 56.2388 +	{
 56.2389 +		// STRH Rd, [Rn, Rm]
 56.2390 +		int base	= (opcode >> 16) & 0x0F;
 56.2391 +		int dest	= (opcode >> 12) & 0x0F;
 56.2392 +		u32 address = reg[base].I + reg[opcode & 0x0F].I;
 56.2393 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2394 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2395 +	}
 56.2396 +	break;
 56.2397 +	case 0x1ab:
 56.2398 +	{
 56.2399 +		// STRH Rd, [Rn, Rm]!
 56.2400 +		int base	= (opcode >> 16) & 0x0F;
 56.2401 +		int dest	= (opcode >> 12) & 0x0F;
 56.2402 +		u32 address = reg[base].I + reg[opcode & 0x0F].I;
 56.2403 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2404 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2405 +		reg[base].I = address;
 56.2406 +	}
 56.2407 +	break;
 56.2408 +	case 0x1cb:
 56.2409 +	{
 56.2410 +		// STRH Rd, [Rn, #offset]
 56.2411 +		int base	= (opcode >> 16) & 0x0F;
 56.2412 +		int dest	= (opcode >> 12) & 0x0F;
 56.2413 +		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2414 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2415 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2416 +	}
 56.2417 +	break;
 56.2418 +	case 0x1eb:
 56.2419 +	{
 56.2420 +		// STRH Rd, [Rn, #offset]!
 56.2421 +		int base	= (opcode >> 16) & 0x0F;
 56.2422 +		int dest	= (opcode >> 12) & 0x0F;
 56.2423 +		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2424 +		clockTicks += 4 + CPUUpdateTicksAccess16(address);
 56.2425 +		CPUWriteHalfWord(address, reg[dest].W.W0);
 56.2426 +		reg[base].I = address;
 56.2427 +	}
 56.2428 +	break;
 56.2429 +	case 0x01b:
 56.2430 +	case 0x03b:
 56.2431 +	{
 56.2432 +		// LDRH Rd, [Rn], -Rm
 56.2433 +		int base	= (opcode >> 16) & 0x0F;
 56.2434 +		int dest	= (opcode >> 12) & 0x0F;
 56.2435 +		u32 address = reg[base].I;
 56.2436 +		int offset	= reg[opcode & 0x0F].I;
 56.2437 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2438 +		reg[dest].I = CPUReadHalfWord(address);
 56.2439 +		if (dest != base)
 56.2440 +		{
 56.2441 +			address	   -= offset;
 56.2442 +			reg[base].I = address;
 56.2443 +		}
 56.2444 +	}
 56.2445 +	break;
 56.2446 +	case 0x05b:
 56.2447 +	case 0x07b:
 56.2448 +	{
 56.2449 +		// LDRH Rd, [Rn], #-offset
 56.2450 +		int base	= (opcode >> 16) & 0x0F;
 56.2451 +		int dest	= (opcode >> 12) & 0x0F;
 56.2452 +		u32 address = reg[base].I;
 56.2453 +		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
 56.2454 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2455 +		reg[dest].I = CPUReadHalfWord(address);
 56.2456 +		if (dest != base)
 56.2457 +		{
 56.2458 +			address	   -= offset;
 56.2459 +			reg[base].I = address;
 56.2460 +		}
 56.2461 +	}
 56.2462 +	break;
 56.2463 +	case 0x09b:
 56.2464 +	case 0x0bb:
 56.2465 +	{
 56.2466 +		// LDRH Rd, [Rn], Rm
 56.2467 +		int base	= (opcode >> 16) & 0x0F;
 56.2468 +		int dest	= (opcode >> 12) & 0x0F;
 56.2469 +		u32 address = reg[base].I;
 56.2470 +		int offset	= reg[opcode & 0x0F].I;
 56.2471 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2472 +		reg[dest].I = CPUReadHalfWord(address);
 56.2473 +		if (dest != base)
 56.2474 +		{
 56.2475 +			address	   += offset;
 56.2476 +			reg[base].I = address;
 56.2477 +		}
 56.2478 +	}
 56.2479 +	break;
 56.2480 +	case 0x0db:
 56.2481 +	case 0x0fb:
 56.2482 +	{
 56.2483 +		// LDRH Rd, [Rn], #offset
 56.2484 +		int base	= (opcode >> 16) & 0x0F;
 56.2485 +		int dest	= (opcode >> 12) & 0x0F;
 56.2486 +		u32 address = reg[base].I;
 56.2487 +		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
 56.2488 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2489 +		reg[dest].I = CPUReadHalfWord(address);
 56.2490 +		if (dest != base)
 56.2491 +		{
 56.2492 +			address	   += offset;
 56.2493 +			reg[base].I = address;
 56.2494 +		}
 56.2495 +	}
 56.2496 +	break;
 56.2497 +	case 0x11b:
 56.2498 +	{
 56.2499 +		// LDRH Rd, [Rn, -Rm]
 56.2500 +		int base	= (opcode >> 16) & 0x0F;
 56.2501 +		int dest	= (opcode >> 12) & 0x0F;
 56.2502 +		u32 address = reg[base].I - reg[opcode & 0x0F].I;
 56.2503 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2504 +		reg[dest].I = CPUReadHalfWord(address);
 56.2505 +	}
 56.2506 +	break;
 56.2507 +	case 0x13b:
 56.2508 +	{
 56.2509 +		// LDRH Rd, [Rn, -Rm]!
 56.2510 +		int base	= (opcode >> 16) & 0x0F;
 56.2511 +		int dest	= (opcode >> 12) & 0x0F;
 56.2512 +		u32 address = reg[base].I - reg[opcode & 0x0F].I;
 56.2513 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2514 +		reg[dest].I = CPUReadHalfWord(address);
 56.2515 +		if (dest != base)
 56.2516 +			reg[base].I = address;
 56.2517 +	}
 56.2518 +	break;
 56.2519 +	case 0x15b:
 56.2520 +	{
 56.2521 +		// LDRH Rd, [Rn, -#offset]
 56.2522 +		int base	= (opcode >> 16) & 0x0F;
 56.2523 +		int dest	= (opcode >> 12) & 0x0F;
 56.2524 +		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2525 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2526 +		reg[dest].I = CPUReadHalfWord(address);
 56.2527 +	}
 56.2528 +	break;
 56.2529 +	case 0x17b:
 56.2530 +	{
 56.2531 +		// LDRH Rd, [Rn, -#offset]!
 56.2532 +		int base	= (opcode >> 16) & 0x0F;
 56.2533 +		int dest	= (opcode >> 12) & 0x0F;
 56.2534 +		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2535 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2536 +		reg[dest].I = CPUReadHalfWord(address);
 56.2537 +		if (dest != base)
 56.2538 +			reg[base].I = address;
 56.2539 +	}
 56.2540 +	break;
 56.2541 +	case 0x19b:
 56.2542 +	{
 56.2543 +		// LDRH Rd, [Rn, Rm]
 56.2544 +		int base	= (opcode >> 16) & 0x0F;
 56.2545 +		int dest	= (opcode >> 12) & 0x0F;
 56.2546 +		u32 address = reg[base].I + reg[opcode & 0x0F].I;
 56.2547 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2548 +		reg[dest].I = CPUReadHalfWord(address);
 56.2549 +	}
 56.2550 +	break;
 56.2551 +	case 0x1bb:
 56.2552 +	{
 56.2553 +		// LDRH Rd, [Rn, Rm]!
 56.2554 +		int base	= (opcode >> 16) & 0x0F;
 56.2555 +		int dest	= (opcode >> 12) & 0x0F;
 56.2556 +		u32 address = reg[base].I + reg[opcode & 0x0F].I;
 56.2557 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2558 +		reg[dest].I = CPUReadHalfWord(address);
 56.2559 +		if (dest != base)
 56.2560 +			reg[base].I = address;
 56.2561 +	}
 56.2562 +	break;
 56.2563 +	case 0x1db:
 56.2564 +	{
 56.2565 +		// LDRH Rd, [Rn, #offset]
 56.2566 +		int base	= (opcode >> 16) & 0x0F;
 56.2567 +		int dest	= (opcode >> 12) & 0x0F;
 56.2568 +		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2569 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2570 +		reg[dest].I = CPUReadHalfWord(address);
 56.2571 +	}
 56.2572 +	break;
 56.2573 +	case 0x1fb:
 56.2574 +	{
 56.2575 +		// LDRH Rd, [Rn, #offset]!
 56.2576 +		int base	= (opcode >> 16) & 0x0F;
 56.2577 +		int dest	= (opcode >> 12) & 0x0F;
 56.2578 +		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2579 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2580 +		reg[dest].I = CPUReadHalfWord(address);
 56.2581 +		if (dest != base)
 56.2582 +			reg[base].I = address;
 56.2583 +	}
 56.2584 +	break;
 56.2585 +	case 0x01d:
 56.2586 +	case 0x03d:
 56.2587 +	{
 56.2588 +		// LDRSB Rd, [Rn], -Rm
 56.2589 +		int base	= (opcode >> 16) & 0x0F;
 56.2590 +		int dest	= (opcode >> 12) & 0x0F;
 56.2591 +		u32 address = reg[base].I;
 56.2592 +		int offset	= reg[opcode & 0x0F].I;
 56.2593 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2594 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2595 +		if (dest != base)
 56.2596 +		{
 56.2597 +			address	   -= offset;
 56.2598 +			reg[base].I = address;
 56.2599 +		}
 56.2600 +	}
 56.2601 +	break;
 56.2602 +	case 0x05d:
 56.2603 +	case 0x07d:
 56.2604 +	{
 56.2605 +		// LDRSB Rd, [Rn], #-offset
 56.2606 +		int base	= (opcode >> 16) & 0x0F;
 56.2607 +		int dest	= (opcode >> 12) & 0x0F;
 56.2608 +		u32 address = reg[base].I;
 56.2609 +		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
 56.2610 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2611 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2612 +		if (dest != base)
 56.2613 +		{
 56.2614 +			address	   -= offset;
 56.2615 +			reg[base].I = address;
 56.2616 +		}
 56.2617 +	}
 56.2618 +	break;
 56.2619 +	case 0x09d:
 56.2620 +	case 0x0bd:
 56.2621 +	{
 56.2622 +		// LDRSB Rd, [Rn], Rm
 56.2623 +		int base	= (opcode >> 16) & 0x0F;
 56.2624 +		int dest	= (opcode >> 12) & 0x0F;
 56.2625 +		u32 address = reg[base].I;
 56.2626 +		int offset	= reg[opcode & 0x0F].I;
 56.2627 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2628 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2629 +		if (dest != base)
 56.2630 +		{
 56.2631 +			address	   += offset;
 56.2632 +			reg[base].I = address;
 56.2633 +		}
 56.2634 +	}
 56.2635 +	break;
 56.2636 +	case 0x0dd:
 56.2637 +	case 0x0fd:
 56.2638 +	{
 56.2639 +		// LDRSB Rd, [Rn], #offset
 56.2640 +		int base	= (opcode >> 16) & 0x0F;
 56.2641 +		int dest	= (opcode >> 12) & 0x0F;
 56.2642 +		u32 address = reg[base].I;
 56.2643 +		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
 56.2644 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2645 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2646 +		if (dest != base)
 56.2647 +		{
 56.2648 +			address	   += offset;
 56.2649 +			reg[base].I = address;
 56.2650 +		}
 56.2651 +	}
 56.2652 +	break;
 56.2653 +	case 0x11d:
 56.2654 +	{
 56.2655 +		// LDRSB Rd, [Rn, -Rm]
 56.2656 +		int base	= (opcode >> 16) & 0x0F;
 56.2657 +		int dest	= (opcode >> 12) & 0x0F;
 56.2658 +		u32 address = reg[base].I - reg[opcode & 0x0F].I;
 56.2659 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2660 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2661 +	}
 56.2662 +	break;
 56.2663 +	case 0x13d:
 56.2664 +	{
 56.2665 +		// LDRSB Rd, [Rn, -Rm]!
 56.2666 +		int base	= (opcode >> 16) & 0x0F;
 56.2667 +		int dest	= (opcode >> 12) & 0x0F;
 56.2668 +		u32 address = reg[base].I - reg[opcode & 0x0F].I;
 56.2669 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2670 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2671 +		if (dest != base)
 56.2672 +			reg[base].I = address;
 56.2673 +	}
 56.2674 +	break;
 56.2675 +	case 0x15d:
 56.2676 +	{
 56.2677 +		// LDRSB Rd, [Rn, -#offset]
 56.2678 +		int base	= (opcode >> 16) & 0x0F;
 56.2679 +		int dest	= (opcode >> 12) & 0x0F;
 56.2680 +		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2681 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2682 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2683 +	}
 56.2684 +	break;
 56.2685 +	case 0x17d:
 56.2686 +	{
 56.2687 +		// LDRSB Rd, [Rn, -#offset]!
 56.2688 +		int base	= (opcode >> 16) & 0x0F;
 56.2689 +		int dest	= (opcode >> 12) & 0x0F;
 56.2690 +		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2691 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2692 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2693 +		if (dest != base)
 56.2694 +			reg[base].I = address;
 56.2695 +	}
 56.2696 +	break;
 56.2697 +	case 0x19d:
 56.2698 +	{
 56.2699 +		// LDRSB Rd, [Rn, Rm]
 56.2700 +		int base	= (opcode >> 16) & 0x0F;
 56.2701 +		int dest	= (opcode >> 12) & 0x0F;
 56.2702 +		u32 address = reg[base].I + reg[opcode & 0x0F].I;
 56.2703 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2704 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2705 +	}
 56.2706 +	break;
 56.2707 +	case 0x1bd:
 56.2708 +	{
 56.2709 +		// LDRSB Rd, [Rn, Rm]!
 56.2710 +		int base	= (opcode >> 16) & 0x0F;
 56.2711 +		int dest	= (opcode >> 12) & 0x0F;
 56.2712 +		u32 address = reg[base].I + reg[opcode & 0x0F].I;
 56.2713 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2714 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2715 +		if (dest != base)
 56.2716 +			reg[base].I = address;
 56.2717 +	}
 56.2718 +	break;
 56.2719 +	case 0x1dd:
 56.2720 +	{
 56.2721 +		// LDRSB Rd, [Rn, #offset]
 56.2722 +		int base	= (opcode >> 16) & 0x0F;
 56.2723 +		int dest	= (opcode >> 12) & 0x0F;
 56.2724 +		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2725 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2726 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2727 +	}
 56.2728 +	break;
 56.2729 +	case 0x1fd:
 56.2730 +	{
 56.2731 +		// LDRSB Rd, [Rn, #offset]!
 56.2732 +		int base	= (opcode >> 16) & 0x0F;
 56.2733 +		int dest	= (opcode >> 12) & 0x0F;
 56.2734 +		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2735 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2736 +		reg[dest].I = (s8)CPUReadByte(address);
 56.2737 +		if (dest != base)
 56.2738 +			reg[base].I = address;
 56.2739 +	}
 56.2740 +	break;
 56.2741 +	case 0x01f:
 56.2742 +	case 0x03f:
 56.2743 +	{
 56.2744 +		// LDRSH Rd, [Rn], -Rm
 56.2745 +		int base	= (opcode >> 16) & 0x0F;
 56.2746 +		int dest	= (opcode >> 12) & 0x0F;
 56.2747 +		u32 address = reg[base].I;
 56.2748 +		int offset	= reg[opcode & 0x0F].I;
 56.2749 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2750 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2751 +		if (dest != base)
 56.2752 +		{
 56.2753 +			address	   -= offset;
 56.2754 +			reg[base].I = address;
 56.2755 +		}
 56.2756 +	}
 56.2757 +	break;
 56.2758 +	case 0x05f:
 56.2759 +	case 0x07f:
 56.2760 +	{
 56.2761 +		// LDRSH Rd, [Rn], #-offset
 56.2762 +		int base	= (opcode >> 16) & 0x0F;
 56.2763 +		int dest	= (opcode >> 12) & 0x0F;
 56.2764 +		u32 address = reg[base].I;
 56.2765 +		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
 56.2766 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2767 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2768 +		if (dest != base)
 56.2769 +		{
 56.2770 +			address	   -= offset;
 56.2771 +			reg[base].I = address;
 56.2772 +		}
 56.2773 +	}
 56.2774 +	break;
 56.2775 +	case 0x09f:
 56.2776 +	case 0x0bf:
 56.2777 +	{
 56.2778 +		// LDRSH Rd, [Rn], Rm
 56.2779 +		int base	= (opcode >> 16) & 0x0F;
 56.2780 +		int dest	= (opcode >> 12) & 0x0F;
 56.2781 +		u32 address = reg[base].I;
 56.2782 +		int offset	= reg[opcode & 0x0F].I;
 56.2783 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2784 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2785 +		if (dest != base)
 56.2786 +		{
 56.2787 +			address	   += offset;
 56.2788 +			reg[base].I = address;
 56.2789 +		}
 56.2790 +	}
 56.2791 +	break;
 56.2792 +	case 0x0df:
 56.2793 +	case 0x0ff:
 56.2794 +	{
 56.2795 +		// LDRSH Rd, [Rn], #offset
 56.2796 +		int base	= (opcode >> 16) & 0x0F;
 56.2797 +		int dest	= (opcode >> 12) & 0x0F;
 56.2798 +		u32 address = reg[base].I;
 56.2799 +		int offset	= (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
 56.2800 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2801 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2802 +		if (dest != base)
 56.2803 +		{
 56.2804 +			address	   += offset;
 56.2805 +			reg[base].I = address;
 56.2806 +		}
 56.2807 +	}
 56.2808 +	break;
 56.2809 +	case 0x11f:
 56.2810 +	{
 56.2811 +		// LDRSH Rd, [Rn, -Rm]
 56.2812 +		int base	= (opcode >> 16) & 0x0F;
 56.2813 +		int dest	= (opcode >> 12) & 0x0F;
 56.2814 +		u32 address = reg[base].I - reg[opcode & 0x0F].I;
 56.2815 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2816 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2817 +	}
 56.2818 +	break;
 56.2819 +	case 0x13f:
 56.2820 +	{
 56.2821 +		// LDRSH Rd, [Rn, -Rm]!
 56.2822 +		int base	= (opcode >> 16) & 0x0F;
 56.2823 +		int dest	= (opcode >> 12) & 0x0F;
 56.2824 +		u32 address = reg[base].I - reg[opcode & 0x0F].I;
 56.2825 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2826 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2827 +		if (dest != base)
 56.2828 +			reg[base].I = address;
 56.2829 +	}
 56.2830 +	break;
 56.2831 +	case 0x15f:
 56.2832 +	{
 56.2833 +		// LDRSH Rd, [Rn, -#offset]
 56.2834 +		int base	= (opcode >> 16) & 0x0F;
 56.2835 +		int dest	= (opcode >> 12) & 0x0F;
 56.2836 +		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2837 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2838 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2839 +	}
 56.2840 +	break;
 56.2841 +	case 0x17f:
 56.2842 +	{
 56.2843 +		// LDRSH Rd, [Rn, -#offset]!
 56.2844 +		int base	= (opcode >> 16) & 0x0F;
 56.2845 +		int dest	= (opcode >> 12) & 0x0F;
 56.2846 +		u32 address = reg[base].I - ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2847 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2848 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2849 +		if (dest != base)
 56.2850 +			reg[base].I = address;
 56.2851 +	}
 56.2852 +	break;
 56.2853 +	case 0x19f:
 56.2854 +	{
 56.2855 +		// LDRSH Rd, [Rn, Rm]
 56.2856 +		int base	= (opcode >> 16) & 0x0F;
 56.2857 +		int dest	= (opcode >> 12) & 0x0F;
 56.2858 +		u32 address = reg[base].I + reg[opcode & 0x0F].I;
 56.2859 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2860 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2861 +	}
 56.2862 +	break;
 56.2863 +	case 0x1bf:
 56.2864 +	{
 56.2865 +		// LDRSH Rd, [Rn, Rm]!
 56.2866 +		int base	= (opcode >> 16) & 0x0F;
 56.2867 +		int dest	= (opcode >> 12) & 0x0F;
 56.2868 +		u32 address = reg[base].I + reg[opcode & 0x0F].I;
 56.2869 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2870 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2871 +		if (dest != base)
 56.2872 +			reg[base].I = address;
 56.2873 +	}
 56.2874 +	break;
 56.2875 +	case 0x1df:
 56.2876 +	{
 56.2877 +		// LDRSH Rd, [Rn, #offset]
 56.2878 +		int base	= (opcode >> 16) & 0x0F;
 56.2879 +		int dest	= (opcode >> 12) & 0x0F;
 56.2880 +		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2881 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2882 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2883 +	}
 56.2884 +	break;
 56.2885 +	case 0x1ff:
 56.2886 +	{
 56.2887 +		// LDRSH Rd, [Rn, #offset]!
 56.2888 +		int base	= (opcode >> 16) & 0x0F;
 56.2889 +		int dest	= (opcode >> 12) & 0x0F;
 56.2890 +		u32 address = reg[base].I + ((opcode & 0x0F) | ((opcode >> 4) & 0xF0));
 56.2891 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.2892 +		reg[dest].I = (s16)CPUReadHalfWordSigned(address);
 56.2893 +		if (dest != base)
 56.2894 +			reg[base].I = address;
 56.2895 +	}
 56.2896 +	break;
 56.2897 +		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_EOR,  OP_EOR, 0x020);
 56.2898 +		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_EORS, OP_EOR, 0x030);
 56.2899 +	case 0x029:
 56.2900 +	{
 56.2901 +		// MLA Rd, Rm, Rs, Rn
 56.2902 +		int dest = (opcode >> 16) & 0x0F;
 56.2903 +		int mult = (opcode & 0x0F);
 56.2904 +		u32 rs	 = reg[(opcode >> 8) & 0x0F].I;
 56.2905 +		reg[dest].I = reg[mult].I * rs + reg[(opcode >> 12) & 0x0f].I;
 56.2906 +		if (((s32)rs) < 0)
 56.2907 +			rs = ~rs;
 56.2908 +		if ((rs & 0xFFFFFF00) == 0)
 56.2909 +			clockTicks += 3;
 56.2910 +		else if ((rs & 0xFFFF0000) == 0)
 56.2911 +			clockTicks += 4;
 56.2912 +		else if ((rs & 0xFF000000) == 0)
 56.2913 +			clockTicks += 5;
 56.2914 +		else
 56.2915 +			clockTicks += 6;
 56.2916 +	}
 56.2917 +	break;
 56.2918 +	case 0x039:
 56.2919 +	{
 56.2920 +		// MLAS Rd, Rm, Rs, Rn
 56.2921 +		int dest = (opcode >> 16) & 0x0F;
 56.2922 +		int mult = (opcode & 0x0F);
 56.2923 +		u32 rs	 = reg[(opcode >> 8) & 0x0F].I;
 56.2924 +		reg[dest].I = reg[mult].I * rs + reg[(opcode >> 12) & 0x0f].I;
 56.2925 +		N_FLAG		= (reg[dest].I & 0x80000000) ? true : false;
 56.2926 +		Z_FLAG		= (reg[dest].I) ? false : true;
 56.2927 +		if (((s32)rs) < 0)
 56.2928 +			rs = ~rs;
 56.2929 +		if ((rs & 0xFFFFFF00) == 0)
 56.2930 +			clockTicks += 3;
 56.2931 +		else if ((rs & 0xFFFF0000) == 0)
 56.2932 +			clockTicks += 4;
 56.2933 +		else if ((rs & 0xFF000000) == 0)
 56.2934 +			clockTicks += 5;
 56.2935 +		else
 56.2936 +			clockTicks += 6;
 56.2937 +	}
 56.2938 +	break;
 56.2939 +		ARITHMETIC_DATA_OPCODE(OP_SUB,  OP_SUB, 0x040);
 56.2940 +		ARITHMETIC_DATA_OPCODE(OP_SUBS, OP_SUB, 0x050);
 56.2941 +		ARITHMETIC_DATA_OPCODE(OP_RSB,  OP_RSB, 0x060);
 56.2942 +		ARITHMETIC_DATA_OPCODE(OP_RSBS, OP_RSB, 0x070);
 56.2943 +		ARITHMETIC_DATA_OPCODE(OP_ADD,  OP_ADD, 0x080);
 56.2944 +		ARITHMETIC_DATA_OPCODE(OP_ADDS, OP_ADD, 0x090);
 56.2945 +	case 0x089:
 56.2946 +	{
 56.2947 +		// UMULL RdLo, RdHi, Rn, Rs
 56.2948 +		u32 umult	= reg[(opcode & 0x0F)].I;
 56.2949 +		u32 usource = reg[(opcode >> 8) & 0x0F].I;
 56.2950 +		int destLo	= (opcode >> 12) & 0x0F;
 56.2951 +		int destHi	= (opcode >> 16) & 0x0F;
 56.2952 +		u64 uTemp	= ((u64)umult) * ((u64)usource);
 56.2953 +		reg[destLo].I = (u32)(uTemp & 0xFFFFFFFF);
 56.2954 +		reg[destHi].I = (u32)(uTemp >> 32);
 56.2955 +		if ((usource & 0xFFFFFF00) == 0)
 56.2956 +			clockTicks += 2;
 56.2957 +		else if ((usource & 0xFFFF0000) == 0)
 56.2958 +			clockTicks += 3;
 56.2959 +		else if ((usource & 0xFF000000) == 0)
 56.2960 +			clockTicks += 4;
 56.2961 +		else
 56.2962 +			clockTicks += 5;
 56.2963 +	}
 56.2964 +	break;
 56.2965 +	case 0x099:
 56.2966 +	{
 56.2967 +		// UMULLS RdLo, RdHi, Rn, Rs
 56.2968 +		u32 umult	= reg[(opcode & 0x0F)].I;
 56.2969 +		u32 usource = reg[(opcode >> 8) & 0x0F].I;
 56.2970 +		int destLo	= (opcode >> 12) & 0x0F;
 56.2971 +		int destHi	= (opcode >> 16) & 0x0F;
 56.2972 +		u64 uTemp	= ((u64)umult) * ((u64)usource);
 56.2973 +		reg[destLo].I = (u32)(uTemp & 0xFFFFFFFF);
 56.2974 +		reg[destHi].I = (u32)(uTemp >> 32);
 56.2975 +		Z_FLAG		  = (uTemp) ? false : true;
 56.2976 +		N_FLAG		  = (reg[destHi].I & 0x80000000) ? true : false;
 56.2977 +		if ((usource & 0xFFFFFF00) == 0)
 56.2978 +			clockTicks += 2;
 56.2979 +		else if ((usource & 0xFFFF0000) == 0)
 56.2980 +			clockTicks += 3;
 56.2981 +		else if ((usource & 0xFF000000) == 0)
 56.2982 +			clockTicks += 4;
 56.2983 +		else
 56.2984 +			clockTicks += 5;
 56.2985 +	}
 56.2986 +	break;
 56.2987 +		ARITHMETIC_DATA_OPCODE(OP_ADC,  OP_ADC, 0x0a0);
 56.2988 +		ARITHMETIC_DATA_OPCODE(OP_ADCS, OP_ADC, 0x0b0);
 56.2989 +	case 0x0a9:
 56.2990 +	{
 56.2991 +		// UMLAL RdLo, RdHi, Rn, Rs
 56.2992 +		u32 umult	= reg[(opcode & 0x0F)].I;
 56.2993 +		u32 usource = reg[(opcode >> 8) & 0x0F].I;
 56.2994 +		int destLo	= (opcode >> 12) & 0x0F;
 56.2995 +		int destHi	= (opcode >> 16) & 0x0F;
 56.2996 +		u64 uTemp	= (u64)reg[destHi].I;
 56.2997 +		uTemp		<<= 32;
 56.2998 +		uTemp		 |= (u64)reg[destLo].I;
 56.2999 +		uTemp		 += ((u64)umult) * ((u64)usource);
 56.3000 +		reg[destLo].I = (u32)(uTemp & 0xFFFFFFFF);
 56.3001 +		reg[destHi].I = (u32)(uTemp >> 32);
 56.3002 +		if ((usource & 0xFFFFFF00) == 0)
 56.3003 +			clockTicks += 3;
 56.3004 +		else if ((usource & 0xFFFF0000) == 0)
 56.3005 +			clockTicks += 4;
 56.3006 +		else if ((usource & 0xFF000000) == 0)
 56.3007 +			clockTicks += 5;
 56.3008 +		else
 56.3009 +			clockTicks += 6;
 56.3010 +	}
 56.3011 +	break;
 56.3012 +	case 0x0b9:
 56.3013 +	{
 56.3014 +		// UMLALS RdLo, RdHi, Rn, Rs
 56.3015 +		u32 umult	= reg[(opcode & 0x0F)].I;
 56.3016 +		u32 usource = reg[(opcode >> 8) & 0x0F].I;
 56.3017 +		int destLo	= (opcode >> 12) & 0x0F;
 56.3018 +		int destHi	= (opcode >> 16) & 0x0F;
 56.3019 +		u64 uTemp	= (u64)reg[destHi].I;
 56.3020 +		uTemp		<<= 32;
 56.3021 +		uTemp		 |= (u64)reg[destLo].I;
 56.3022 +		uTemp		 += ((u64)umult) * ((u64)usource);
 56.3023 +		reg[destLo].I = (u32)(uTemp & 0xFFFFFFFF);
 56.3024 +		reg[destHi].I = (u32)(uTemp >> 32);
 56.3025 +		Z_FLAG		  = (uTemp) ? false : true;
 56.3026 +		N_FLAG		  = (reg[destHi].I & 0x80000000) ? true : false;
 56.3027 +		if ((usource & 0xFFFFFF00) == 0)
 56.3028 +			clockTicks += 3;
 56.3029 +		else if ((usource & 0xFFFF0000) == 0)
 56.3030 +			clockTicks += 4;
 56.3031 +		else if ((usource & 0xFF000000) == 0)
 56.3032 +			clockTicks += 5;
 56.3033 +		else
 56.3034 +			clockTicks += 6;
 56.3035 +	}
 56.3036 +	break;
 56.3037 +		ARITHMETIC_DATA_OPCODE(OP_SBC,  OP_SBC, 0x0c0);
 56.3038 +		ARITHMETIC_DATA_OPCODE(OP_SBCS, OP_SBC, 0x0d0);
 56.3039 +	case 0x0c9:
 56.3040 +	{
 56.3041 +		// SMULL RdLo, RdHi, Rm, Rs
 56.3042 +		int destLo = (opcode >> 12) & 0x0F;
 56.3043 +		int destHi = (opcode >> 16) & 0x0F;
 56.3044 +		u32 rs	   = reg[(opcode >> 8) & 0x0F].I;
 56.3045 +		s64 m	   = (s32)reg[(opcode & 0x0F)].I;
 56.3046 +		s64 s	   = (s32)rs;
 56.3047 +		s64 sTemp  = m * s;
 56.3048 +		reg[destLo].I = (u32)(sTemp & 0xFFFFFFFF);
 56.3049 +		reg[destHi].I = (u32)(sTemp >> 32);
 56.3050 +		if (((s32)rs) < 0)
 56.3051 +			rs = ~rs;
 56.3052 +		if ((rs & 0xFFFFFF00) == 0)
 56.3053 +			clockTicks += 2;
 56.3054 +		else if ((rs & 0xFFFF0000) == 0)
 56.3055 +			clockTicks += 3;
 56.3056 +		else if ((rs & 0xFF000000) == 0)
 56.3057 +			clockTicks += 4;
 56.3058 +		else
 56.3059 +			clockTicks += 5;
 56.3060 +	}
 56.3061 +	break;
 56.3062 +	case 0x0d9:
 56.3063 +	{
 56.3064 +		// SMULLS RdLo, RdHi, Rm, Rs
 56.3065 +		int destLo = (opcode >> 12) & 0x0F;
 56.3066 +		int destHi = (opcode >> 16) & 0x0F;
 56.3067 +		u32 rs	   = reg[(opcode >> 8) & 0x0F].I;
 56.3068 +		s64 m	   = (s32)reg[(opcode & 0x0F)].I;
 56.3069 +		s64 s	   = (s32)rs;
 56.3070 +		s64 sTemp  = m * s;
 56.3071 +		reg[destLo].I = (u32)(sTemp & 0xFFFFFFFF);
 56.3072 +		reg[destHi].I = (u32)(sTemp >> 32);
 56.3073 +		Z_FLAG		  = (sTemp) ? false : true;
 56.3074 +		N_FLAG		  = (sTemp < 0) ? true : false;
 56.3075 +		if (((s32)rs) < 0)
 56.3076 +			rs = ~rs;
 56.3077 +		if ((rs & 0xFFFFFF00) == 0)
 56.3078 +			clockTicks += 2;
 56.3079 +		else if ((rs & 0xFFFF0000) == 0)
 56.3080 +			clockTicks += 3;
 56.3081 +		else if ((rs & 0xFF000000) == 0)
 56.3082 +			clockTicks += 4;
 56.3083 +		else
 56.3084 +			clockTicks += 5;
 56.3085 +	}
 56.3086 +	break;
 56.3087 +		ARITHMETIC_DATA_OPCODE(OP_RSC,  OP_RSC, 0x0e0);
 56.3088 +		ARITHMETIC_DATA_OPCODE(OP_RSCS, OP_RSC, 0x0f0);
 56.3089 +	case 0x0e9:
 56.3090 +	{
 56.3091 +		// SMLAL RdLo, RdHi, Rm, Rs
 56.3092 +		int destLo = (opcode >> 12) & 0x0F;
 56.3093 +		int destHi = (opcode >> 16) & 0x0F;
 56.3094 +		u32 rs	   = reg[(opcode >> 8) & 0x0F].I;
 56.3095 +		s64 m	   = (s32)reg[(opcode & 0x0F)].I;
 56.3096 +		s64 s	   = (s32)rs;
 56.3097 +		s64 sTemp  = (u64)reg[destHi].I;
 56.3098 +		sTemp		<<= 32;
 56.3099 +		sTemp		 |= (u64)reg[destLo].I;
 56.3100 +		sTemp		 += m * s;
 56.3101 +		reg[destLo].I = (u32)(sTemp & 0xFFFFFFFF);
 56.3102 +		reg[destHi].I = (u32)(sTemp >> 32);
 56.3103 +		if (((s32)rs) < 0)
 56.3104 +			rs = ~rs;
 56.3105 +		if ((rs & 0xFFFFFF00) == 0)
 56.3106 +			clockTicks += 3;
 56.3107 +		else if ((rs & 0xFFFF0000) == 0)
 56.3108 +			clockTicks += 4;
 56.3109 +		else if ((rs & 0xFF000000) == 0)
 56.3110 +			clockTicks += 5;
 56.3111 +		else
 56.3112 +			clockTicks += 6;
 56.3113 +	}
 56.3114 +	break;
 56.3115 +	case 0x0f9:
 56.3116 +	{
 56.3117 +		// SMLALS RdLo, RdHi, Rm, Rs
 56.3118 +		int destLo = (opcode >> 12) & 0x0F;
 56.3119 +		int destHi = (opcode >> 16) & 0x0F;
 56.3120 +		u32 rs	   = reg[(opcode >> 8) & 0x0F].I;
 56.3121 +		s64 m	   = (s32)reg[(opcode & 0x0F)].I;
 56.3122 +		s64 s	   = (s32)rs;
 56.3123 +		s64 sTemp  = (u64)reg[destHi].I;
 56.3124 +		sTemp		<<= 32;
 56.3125 +		sTemp		 |= (u64)reg[destLo].I;
 56.3126 +		sTemp		 += m * s;
 56.3127 +		reg[destLo].I = (u32)(sTemp & 0xFFFFFFFF);
 56.3128 +		reg[destHi].I = (u32)(sTemp >> 32);
 56.3129 +		Z_FLAG		  = (sTemp) ? false : true;
 56.3130 +		N_FLAG		  = (sTemp < 0) ? true : false;
 56.3131 +		if (((s32)rs) < 0)
 56.3132 +			rs = ~rs;
 56.3133 +		if ((rs & 0xFFFFFF00) == 0)
 56.3134 +			clockTicks += 3;
 56.3135 +		else if ((rs & 0xFFFF0000) == 0)
 56.3136 +			clockTicks += 4;
 56.3137 +		else if ((rs & 0xFF000000) == 0)
 56.3138 +			clockTicks += 5;
 56.3139 +		else
 56.3140 +			clockTicks += 6;
 56.3141 +	}
 56.3142 +	break;
 56.3143 +		LOGICAL_DATA_OPCODE(OP_TST, OP_TST, 0x110);
 56.3144 +	case 0x100:
 56.3145 +		// MRS Rd, CPSR
 56.3146 +		// TODO: check if right instruction....
 56.3147 +		CPUUpdateCPSR();
 56.3148 +		reg[(opcode >> 12) & 0x0F].I = reg[16].I;
 56.3149 +		break;
 56.3150 +	case 0x109:
 56.3151 +	{
 56.3152 +		// SWP Rd, Rm, [Rn]
 56.3153 +		u32 address = reg[(opcode >> 16) & 15].I;
 56.3154 +		u32 temp	= CPUReadMemory(address);
 56.3155 +		CPUWriteMemory(address, reg[opcode & 15].I);
 56.3156 +		reg[(opcode >> 12) & 15].I = temp;
 56.3157 +	}
 56.3158 +	break;
 56.3159 +		LOGICAL_DATA_OPCODE(OP_TEQ, OP_TEQ, 0x130);
 56.3160 +	case 0x120:
 56.3161 +	{
 56.3162 +		// MSR CPSR_fields, Rm
 56.3163 +		CPUUpdateCPSR();
 56.3164 +		u32 value	 = reg[opcode & 15].I;
 56.3165 +		u32 newValue = reg[16].I;
 56.3166 +		if (armMode > 0x10)
 56.3167 +		{
 56.3168 +			if (opcode & 0x00010000)
 56.3169 +				newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF);
 56.3170 +			if (opcode & 0x00020000)
 56.3171 +				newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00);
 56.3172 +			if (opcode & 0x00040000)
 56.3173 +				newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000);
 56.3174 +		}
 56.3175 +		if (opcode & 0x00080000)
 56.3176 +			newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000);
 56.3177 +		newValue |= 0x10;
 56.3178 +		CPUSwitchMode(newValue & 0x1f, false);
 56.3179 +		reg[16].I = newValue;
 56.3180 +		CPUUpdateFlags();
 56.3181 +	}
 56.3182 +	break;
 56.3183 +	case 0x121:
 56.3184 +	{
 56.3185 +		// BX Rm
 56.3186 +		// TODO: check if right instruction...
 56.3187 +		clockTicks += 3;
 56.3188 +		int base = opcode & 0x0F;
 56.3189 +		armState = reg[base].I & 1 ? false : true;
 56.3190 +		if (armState)
 56.3191 +		{
 56.3192 +			reg[15].I  = reg[base].I & 0xFFFFFFFC;
 56.3193 +			armNextPC  = reg[15].I;
 56.3194 +			reg[15].I += 4;
 56.3195 +		}
 56.3196 +		else
 56.3197 +		{
 56.3198 +			reg[15].I  = reg[base].I & 0xFFFFFFFE;
 56.3199 +			armNextPC  = reg[15].I;
 56.3200 +			reg[15].I += 2;
 56.3201 +		}
 56.3202 +	}
 56.3203 +	break;
 56.3204 +		ARITHMETIC_DATA_OPCODE(OP_CMP, OP_CMP, 0x150);
 56.3205 +	case 0x140:
 56.3206 +		// MRS Rd, SPSR
 56.3207 +		// TODO: check if right instruction...
 56.3208 +		reg[(opcode >> 12) & 0x0F].I = reg[17].I;
 56.3209 +		break;
 56.3210 +	case 0x149:
 56.3211 +	{
 56.3212 +		// SWPB Rd, Rm, [Rn]
 56.3213 +		u32 address = reg[(opcode >> 16) & 15].I;
 56.3214 +		u32 temp	= CPUReadByte(address);
 56.3215 +		CPUWriteByte(address, reg[opcode & 15].B.B0);
 56.3216 +		reg[(opcode >> 12) & 15].I = temp;
 56.3217 +	}
 56.3218 +	break;
 56.3219 +		ARITHMETIC_DATA_OPCODE(OP_CMN, OP_CMN, 0x170);
 56.3220 +	case 0x160:
 56.3221 +	{
 56.3222 +		// MSR SPSR_fields, Rm
 56.3223 +		u32 value = reg[opcode & 15].I;
 56.3224 +		if (armMode > 0x10 && armMode < 0x1f)
 56.3225 +		{
 56.3226 +			if (opcode & 0x00010000)
 56.3227 +				reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF);
 56.3228 +			if (opcode & 0x00020000)
 56.3229 +				reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00);
 56.3230 +			if (opcode & 0x00040000)
 56.3231 +				reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000);
 56.3232 +			if (opcode & 0x00080000)
 56.3233 +				reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000);
 56.3234 +		}
 56.3235 +	}
 56.3236 +	break;
 56.3237 +		LOGICAL_DATA_OPCODE(OP_ORR,  OP_ORR, 0x180);
 56.3238 +		LOGICAL_DATA_OPCODE(OP_ORRS, OP_ORR, 0x190);
 56.3239 +		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MOV,  OP_MOV, 0x1a0);
 56.3240 +		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MOVS, OP_MOV, 0x1b0);
 56.3241 +		LOGICAL_DATA_OPCODE(OP_BIC,  OP_BIC, 0x1c0);
 56.3242 +		LOGICAL_DATA_OPCODE(OP_BICS, OP_BIC, 0x1d0);
 56.3243 +		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MVN,  OP_MVN, 0x1e0);
 56.3244 +		LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MVNS, OP_MVN, 0x1f0);
 56.3245 +#ifdef BKPT_SUPPORT
 56.3246 +	case 0x127:
 56.3247 +	case 0x7ff: // for GDB support
 56.3248 +		extern void (*dbgSignal)(int, int);
 56.3249 +		reg[15].I -= 4;
 56.3250 +		armNextPC -= 4;
 56.3251 +		dbgSignal(5, (opcode & 0x0f) | ((opcode >> 4) & 0xfff0));
 56.3252 +		return;
 56.3253 +#endif
 56.3254 +	case 0x320:
 56.3255 +	case 0x321:
 56.3256 +	case 0x322:
 56.3257 +	case 0x323:
 56.3258 +	case 0x324:
 56.3259 +	case 0x325:
 56.3260 +	case 0x326:
 56.3261 +	case 0x327:
 56.3262 +	case 0x328:
 56.3263 +	case 0x329:
 56.3264 +	case 0x32a:
 56.3265 +	case 0x32b:
 56.3266 +	case 0x32c:
 56.3267 +	case 0x32d:
 56.3268 +	case 0x32e:
 56.3269 +	case 0x32f:
 56.3270 +	{
 56.3271 +		// MSR CPSR_fields, #
 56.3272 +		CPUUpdateCPSR();
 56.3273 +		u32 value = opcode & 0xFF;
 56.3274 +		int shift = (opcode & 0xF00) >> 7;
 56.3275 +		if (shift)
 56.3276 +		{
 56.3277 +			ROR_IMM_MSR;
 56.3278 +		}
 56.3279 +		u32 newValue = reg[16].I;
 56.3280 +		if (armMode > 0x10)
 56.3281 +		{
 56.3282 +			if (opcode & 0x00010000)
 56.3283 +				newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF);
 56.3284 +			if (opcode & 0x00020000)
 56.3285 +				newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00);
 56.3286 +			if (opcode & 0x00040000)
 56.3287 +				newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000);
 56.3288 +		}
 56.3289 +		if (opcode & 0x00080000)
 56.3290 +			newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000);
 56.3291 +
 56.3292 +		newValue |= 0x10;
 56.3293 +
 56.3294 +		CPUSwitchMode(newValue & 0x1f, false);
 56.3295 +		reg[16].I = newValue;
 56.3296 +		CPUUpdateFlags();
 56.3297 +	}
 56.3298 +	break;
 56.3299 +	case 0x360:
 56.3300 +	case 0x361:
 56.3301 +	case 0x362:
 56.3302 +	case 0x363:
 56.3303 +	case 0x364:
 56.3304 +	case 0x365:
 56.3305 +	case 0x366:
 56.3306 +	case 0x367:
 56.3307 +	case 0x368:
 56.3308 +	case 0x369:
 56.3309 +	case 0x36a:
 56.3310 +	case 0x36b:
 56.3311 +	case 0x36c:
 56.3312 +	case 0x36d:
 56.3313 +	case 0x36e:
 56.3314 +	case 0x36f:
 56.3315 +	{
 56.3316 +		// MSR SPSR_fields, #
 56.3317 +		if (armMode > 0x10 && armMode < 0x1f)
 56.3318 +		{
 56.3319 +			u32 value = opcode & 0xFF;
 56.3320 +			int shift = (opcode & 0xF00) >> 7;
 56.3321 +			if (shift)
 56.3322 +			{
 56.3323 +				ROR_IMM_MSR;
 56.3324 +			}
 56.3325 +			if (opcode & 0x00010000)
 56.3326 +				reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF);
 56.3327 +			if (opcode & 0x00020000)
 56.3328 +				reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00);
 56.3329 +			if (opcode & 0x00040000)
 56.3330 +				reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000);
 56.3331 +			if (opcode & 0x00080000)
 56.3332 +				reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000);
 56.3333 +		}
 56.3334 +	}
 56.3335 +	break;
 56.3336 +		CASE_16(0x400)
 56.3337 +		// T versions shouldn't be different on GBA
 56.3338 +		CASE_16(0x420)
 56.3339 +		{
 56.3340 +			// STR Rd, [Rn], -#
 56.3341 +			int offset	= opcode & 0xFFF;
 56.3342 +			int dest	= (opcode >> 12) & 15;
 56.3343 +			int base	= (opcode >> 16) & 15;
 56.3344 +			u32 address = reg[base].I;
 56.3345 +			CPUWriteMemory(address, reg[dest].I);
 56.3346 +			reg[base].I = address - offset;
 56.3347 +			clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3348 +		}
 56.3349 +		break;
 56.3350 +		CASE_16(0x480)
 56.3351 +		// T versions shouldn't be different on GBA
 56.3352 +		CASE_16(0x4a0)
 56.3353 +		{
 56.3354 +			// STR Rd, [Rn], #
 56.3355 +			int offset	= opcode & 0xFFF;
 56.3356 +			int dest	= (opcode >> 12) & 15;
 56.3357 +			int base	= (opcode >> 16) & 15;
 56.3358 +			u32 address = reg[base].I;
 56.3359 +			CPUWriteMemory(address, reg[dest].I);
 56.3360 +			reg[base].I = address + offset;
 56.3361 +			clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3362 +		}
 56.3363 +		break;
 56.3364 +		CASE_16(0x500)
 56.3365 +		{
 56.3366 +			// STR Rd, [Rn, -#]
 56.3367 +			int offset	= opcode & 0xFFF;
 56.3368 +			int dest	= (opcode >> 12) & 15;
 56.3369 +			int base	= (opcode >> 16) & 15;
 56.3370 +			u32 address = reg[base].I - offset;
 56.3371 +			CPUWriteMemory(address, reg[dest].I);
 56.3372 +			clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3373 +		}
 56.3374 +		break;
 56.3375 +		CASE_16(0x520)
 56.3376 +		{
 56.3377 +			// STR Rd, [Rn, -#]!
 56.3378 +			int offset	= opcode & 0xFFF;
 56.3379 +			int dest	= (opcode >> 12) & 15;
 56.3380 +			int base	= (opcode >> 16) & 15;
 56.3381 +			u32 address = reg[base].I - offset;
 56.3382 +			reg[base].I = address;
 56.3383 +			CPUWriteMemory(address, reg[dest].I);
 56.3384 +			clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3385 +		}
 56.3386 +		break;
 56.3387 +		CASE_16(0x580)
 56.3388 +		{
 56.3389 +			// STR Rd, [Rn, #]
 56.3390 +			int offset	= opcode & 0xFFF;
 56.3391 +			int dest	= (opcode >> 12) & 15;
 56.3392 +			int base	= (opcode >> 16) & 15;
 56.3393 +			u32 address = reg[base].I + offset;
 56.3394 +			CPUWriteMemory(address, reg[dest].I);
 56.3395 +			clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3396 +		}
 56.3397 +		break;
 56.3398 +		CASE_16(0x5a0)
 56.3399 +		{
 56.3400 +			// STR Rd, [Rn, #]!
 56.3401 +			int offset	= opcode & 0xFFF;
 56.3402 +			int dest	= (opcode >> 12) & 15;
 56.3403 +			int base	= (opcode >> 16) & 15;
 56.3404 +			u32 address = reg[base].I + offset;
 56.3405 +			reg[base].I = address;
 56.3406 +			CPUWriteMemory(address, reg[dest].I);
 56.3407 +			clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3408 +		}
 56.3409 +		break;
 56.3410 +		CASE_16(0x410)
 56.3411 +		{
 56.3412 +			// LDR Rd, [Rn], -#
 56.3413 +			int offset	= opcode & 0xFFF;
 56.3414 +			int dest	= (opcode >> 12) & 15;
 56.3415 +			int base	= (opcode >> 16) & 15;
 56.3416 +			u32 address = reg[base].I;
 56.3417 +			reg[dest].I = CPUReadMemory(address);
 56.3418 +			if (dest != base)
 56.3419 +				reg[base].I -= offset;
 56.3420 +			clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.3421 +			if (dest == 15)
 56.3422 +			{
 56.3423 +				clockTicks += 2;
 56.3424 +				reg[15].I  &= 0xFFFFFFFC;
 56.3425 +				armNextPC	= reg[15].I;
 56.3426 +				reg[15].I  += 4;
 56.3427 +			}
 56.3428 +		}
 56.3429 +		break;
 56.3430 +		CASE_16(0x430)
 56.3431 +		{
 56.3432 +			// LDRT Rd, [Rn], -#
 56.3433 +			int offset	= opcode & 0xFFF;
 56.3434 +			int dest	= (opcode >> 12) & 15;
 56.3435 +			int base	= (opcode >> 16) & 15;
 56.3436 +			u32 address = reg[base].I;
 56.3437 +			reg[dest].I = CPUReadMemory(address);
 56.3438 +			if (dest != base)
 56.3439 +				reg[base].I -= offset;
 56.3440 +			clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.3441 +		}
 56.3442 +		break;
 56.3443 +		CASE_16(0x490)
 56.3444 +		{
 56.3445 +			// LDR Rd, [Rn], #
 56.3446 +			int offset	= opcode & 0xFFF;
 56.3447 +			int dest	= (opcode >> 12) & 15;
 56.3448 +			int base	= (opcode >> 16) & 15;
 56.3449 +			u32 address = reg[base].I;
 56.3450 +			reg[dest].I = CPUReadMemory(address);
 56.3451 +			if (dest != base)
 56.3452 +				reg[base].I += offset;
 56.3453 +			clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.3454 +			if (dest == 15)
 56.3455 +			{
 56.3456 +				clockTicks += 2;
 56.3457 +				reg[15].I  &= 0xFFFFFFFC;
 56.3458 +				armNextPC	= reg[15].I;
 56.3459 +				reg[15].I  += 4;
 56.3460 +			}
 56.3461 +		}
 56.3462 +		break;
 56.3463 +		CASE_16(0x4b0)
 56.3464 +		{
 56.3465 +			// LDRT Rd, [Rn], #
 56.3466 +			int offset	= opcode & 0xFFF;
 56.3467 +			int dest	= (opcode >> 12) & 15;
 56.3468 +			int base	= (opcode >> 16) & 15;
 56.3469 +			u32 address = reg[base].I;
 56.3470 +			reg[dest].I = CPUReadMemory(address);
 56.3471 +			if (dest != base)
 56.3472 +				reg[base].I += offset;
 56.3473 +			clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.3474 +		}
 56.3475 +		break;
 56.3476 +		CASE_16(0x510)
 56.3477 +		{
 56.3478 +			// LDR Rd, [Rn, -#]
 56.3479 +			int offset	= opcode & 0xFFF;
 56.3480 +			int dest	= (opcode >> 12) & 15;
 56.3481 +			int base	= (opcode >> 16) & 15;
 56.3482 +			u32 address = reg[base].I - offset;
 56.3483 +			reg[dest].I = CPUReadMemory(address);
 56.3484 +			clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.3485 +			if (dest == 15)
 56.3486 +			{
 56.3487 +				clockTicks += 2;
 56.3488 +				reg[15].I  &= 0xFFFFFFFC;
 56.3489 +				armNextPC	= reg[15].I;
 56.3490 +				reg[15].I  += 4;
 56.3491 +			}
 56.3492 +		}
 56.3493 +		break;
 56.3494 +		CASE_16(0x530)
 56.3495 +		{
 56.3496 +			// LDR Rd, [Rn, -#]!
 56.3497 +			int offset	= opcode & 0xFFF;
 56.3498 +			int dest	= (opcode >> 12) & 15;
 56.3499 +			int base	= (opcode >> 16) & 15;
 56.3500 +			u32 address = reg[base].I - offset;
 56.3501 +			reg[dest].I = CPUReadMemory(address);
 56.3502 +			if (dest != base)
 56.3503 +				reg[base].I = address;
 56.3504 +			clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.3505 +			if (dest == 15)
 56.3506 +			{
 56.3507 +				clockTicks += 2;
 56.3508 +				reg[15].I  &= 0xFFFFFFFC;
 56.3509 +				armNextPC	= reg[15].I;
 56.3510 +				reg[15].I  += 4;
 56.3511 +			}
 56.3512 +		}
 56.3513 +		break;
 56.3514 +		CASE_16(0x590)
 56.3515 +		{
 56.3516 +			// LDR Rd, [Rn, #]
 56.3517 +			int offset	= opcode & 0xFFF;
 56.3518 +			int dest	= (opcode >> 12) & 15;
 56.3519 +			int base	= (opcode >> 16) & 15;
 56.3520 +			u32 address = reg[base].I + offset;
 56.3521 +			reg[dest].I = CPUReadMemory(address);
 56.3522 +			clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.3523 +			if (dest == 15)
 56.3524 +			{
 56.3525 +				clockTicks += 2;
 56.3526 +				reg[15].I  &= 0xFFFFFFFC;
 56.3527 +				armNextPC	= reg[15].I;
 56.3528 +				reg[15].I  += 4;
 56.3529 +			}
 56.3530 +		}
 56.3531 +		break;
 56.3532 +		CASE_16(0x5b0)
 56.3533 +		{
 56.3534 +			// LDR Rd, [Rn, #]!
 56.3535 +			int offset	= opcode & 0xFFF;
 56.3536 +			int dest	= (opcode >> 12) & 15;
 56.3537 +			int base	= (opcode >> 16) & 15;
 56.3538 +			u32 address = reg[base].I + offset;
 56.3539 +			reg[dest].I = CPUReadMemory(address);
 56.3540 +			if (dest != base)
 56.3541 +				reg[base].I = address;
 56.3542 +			clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.3543 +			if (dest == 15)
 56.3544 +			{
 56.3545 +				clockTicks += 2;
 56.3546 +				reg[15].I  &= 0xFFFFFFFC;
 56.3547 +				armNextPC	= reg[15].I;
 56.3548 +				reg[15].I  += 4;
 56.3549 +			}
 56.3550 +		}
 56.3551 +		break;
 56.3552 +		CASE_16(0x440)
 56.3553 +		// T versions shouldn't be different on GBA
 56.3554 +		CASE_16(0x460)
 56.3555 +		{
 56.3556 +			// STRB Rd, [Rn], -#
 56.3557 +			int offset	= opcode & 0xFFF;
 56.3558 +			int dest	= (opcode >> 12) & 15;
 56.3559 +			int base	= (opcode >> 16) & 15;
 56.3560 +			u32 address = reg[base].I;
 56.3561 +			CPUWriteByte(address, reg[dest].B.B0);
 56.3562 +			reg[base].I = address - offset;
 56.3563 +			clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.3564 +		}
 56.3565 +		break;
 56.3566 +		CASE_16(0x4c0)
 56.3567 +		// T versions shouldn't be different on GBA
 56.3568 +		CASE_16(0x4e0)
 56.3569 +		// STRB Rd, [Rn], #
 56.3570 +		{
 56.3571 +			int offset	= opcode & 0xFFF;
 56.3572 +			int dest	= (opcode >> 12) & 15;
 56.3573 +			int base	= (opcode >> 16) & 15;
 56.3574 +			u32 address = reg[base].I;
 56.3575 +			CPUWriteByte(address, reg[dest].B.B0);
 56.3576 +			reg[base].I = address + offset;
 56.3577 +			clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.3578 +		}
 56.3579 +		break;
 56.3580 +		CASE_16(0x540)
 56.3581 +		{
 56.3582 +			// STRB Rd, [Rn, -#]
 56.3583 +			int offset	= opcode & 0xFFF;
 56.3584 +			int dest	= (opcode >> 12) & 15;
 56.3585 +			int base	= (opcode >> 16) & 15;
 56.3586 +			u32 address = reg[base].I - offset;
 56.3587 +			CPUWriteByte(address, reg[dest].B.B0);
 56.3588 +			clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.3589 +		}
 56.3590 +		break;
 56.3591 +		CASE_16(0x560)
 56.3592 +		{
 56.3593 +			// STRB Rd, [Rn, -#]!
 56.3594 +			int offset	= opcode & 0xFFF;
 56.3595 +			int dest	= (opcode >> 12) & 15;
 56.3596 +			int base	= (opcode >> 16) & 15;
 56.3597 +			u32 address = reg[base].I - offset;
 56.3598 +			reg[base].I = address;
 56.3599 +			CPUWriteByte(address, reg[dest].B.B0);
 56.3600 +			clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.3601 +		}
 56.3602 +		break;
 56.3603 +		CASE_16(0x5c0)
 56.3604 +		{
 56.3605 +			// STRB Rd, [Rn, #]
 56.3606 +			int offset	= opcode & 0xFFF;
 56.3607 +			int dest	= (opcode >> 12) & 15;
 56.3608 +			int base	= (opcode >> 16) & 15;
 56.3609 +			u32 address = reg[base].I + offset;
 56.3610 +			CPUWriteByte(address, reg[dest].B.B0);
 56.3611 +			clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.3612 +		}
 56.3613 +		break;
 56.3614 +		CASE_16(0x5e0)
 56.3615 +		{
 56.3616 +			// STRB Rd, [Rn, #]!
 56.3617 +			int offset	= opcode & 0xFFF;
 56.3618 +			int dest	= (opcode >> 12) & 15;
 56.3619 +			int base	= (opcode >> 16) & 15;
 56.3620 +			u32 address = reg[base].I + offset;
 56.3621 +			reg[base].I = address;
 56.3622 +			CPUWriteByte(address, reg[dest].I);
 56.3623 +			clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.3624 +		}
 56.3625 +		break;
 56.3626 +		CASE_16(0x450)
 56.3627 +		// T versions shouldn't be different
 56.3628 +		CASE_16(0x470)
 56.3629 +		{
 56.3630 +			// LDRB Rd, [Rn], -#
 56.3631 +			int offset	= opcode & 0xFFF;
 56.3632 +			int dest	= (opcode >> 12) & 15;
 56.3633 +			int base	= (opcode >> 16) & 15;
 56.3634 +			u32 address = reg[base].I;
 56.3635 +			reg[dest].I = CPUReadByte(address);
 56.3636 +			if (dest != base)
 56.3637 +				reg[base].I -= offset;
 56.3638 +			clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.3639 +		}
 56.3640 +		break;
 56.3641 +		CASE_16(0x4d0)
 56.3642 +		CASE_16(0x4f0) // T versions should not be different
 56.3643 +		{
 56.3644 +			// LDRB Rd, [Rn], #
 56.3645 +			int offset	= opcode & 0xFFF;
 56.3646 +			int dest	= (opcode >> 12) & 15;
 56.3647 +			int base	= (opcode >> 16) & 15;
 56.3648 +			u32 address = reg[base].I;
 56.3649 +			reg[dest].I = CPUReadByte(address);
 56.3650 +			if (dest != base)
 56.3651 +				reg[base].I += offset;
 56.3652 +			clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.3653 +		}
 56.3654 +		break;
 56.3655 +		CASE_16(0x550)
 56.3656 +		{
 56.3657 +			// LDRB Rd, [Rn, -#]
 56.3658 +			int offset	= opcode & 0xFFF;
 56.3659 +			int dest	= (opcode >> 12) & 15;
 56.3660 +			int base	= (opcode >> 16) & 15;
 56.3661 +			u32 address = reg[base].I - offset;
 56.3662 +			reg[dest].I = CPUReadByte(address);
 56.3663 +			clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.3664 +		}
 56.3665 +		break;
 56.3666 +		CASE_16(0x570)
 56.3667 +		{
 56.3668 +			// LDRB Rd, [Rn, -#]!
 56.3669 +			int offset	= opcode & 0xFFF;
 56.3670 +			int dest	= (opcode >> 12) & 15;
 56.3671 +			int base	= (opcode >> 16) & 15;
 56.3672 +			u32 address = reg[base].I - offset;
 56.3673 +			reg[dest].I = CPUReadByte(address);
 56.3674 +			if (dest != base)
 56.3675 +				reg[base].I = address;
 56.3676 +			clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.3677 +		}
 56.3678 +		break;
 56.3679 +		CASE_16(0x5d0)
 56.3680 +		{
 56.3681 +			// LDRB Rd, [Rn, #]
 56.3682 +			int offset	= opcode & 0xFFF;
 56.3683 +			int dest	= (opcode >> 12) & 15;
 56.3684 +			int base	= (opcode >> 16) & 15;
 56.3685 +			u32 address = reg[base].I + offset;
 56.3686 +			reg[dest].I = CPUReadByte(address);
 56.3687 +			clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.3688 +		}
 56.3689 +		break;
 56.3690 +		CASE_16(0x5f0)
 56.3691 +		{
 56.3692 +			// LDRB Rd, [Rn, #]!
 56.3693 +			int offset	= opcode & 0xFFF;
 56.3694 +			int dest	= (opcode >> 12) & 15;
 56.3695 +			int base	= (opcode >> 16) & 15;
 56.3696 +			u32 address = reg[base].I + offset;
 56.3697 +			reg[dest].I = CPUReadByte(address);
 56.3698 +			if (dest != base)
 56.3699 +				reg[base].I = address;
 56.3700 +			clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.3701 +		}
 56.3702 +		break;
 56.3703 +	case 0x600:
 56.3704 +	case 0x608:
 56.3705 +	// T versions are the same
 56.3706 +	case 0x620:
 56.3707 +	case 0x628:
 56.3708 +	{
 56.3709 +		// STR Rd, [Rn], -Rm, LSL #
 56.3710 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.3711 +		int dest	= (opcode >> 12) & 15;
 56.3712 +		int base	= (opcode >> 16) & 15;
 56.3713 +		u32 address = reg[base].I;
 56.3714 +		CPUWriteMemory(address, reg[dest].I);
 56.3715 +		reg[base].I = address - offset;
 56.3716 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3717 +	}
 56.3718 +	break;
 56.3719 +	case 0x602:
 56.3720 +	case 0x60a:
 56.3721 +	// T versions are the same
 56.3722 +	case 0x622:
 56.3723 +	case 0x62a:
 56.3724 +	{
 56.3725 +		// STR Rd, [Rn], -Rm, LSR #
 56.3726 +		int shift	= (opcode >> 7) & 31;
 56.3727 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.3728 +		int dest	= (opcode >> 12) & 15;
 56.3729 +		int base	= (opcode >> 16) & 15;
 56.3730 +		u32 address = reg[base].I;
 56.3731 +		CPUWriteMemory(address, reg[dest].I);
 56.3732 +		reg[base].I = address - offset;
 56.3733 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3734 +	}
 56.3735 +	break;
 56.3736 +	case 0x604:
 56.3737 +	case 0x60c:
 56.3738 +	// T versions are the same
 56.3739 +	case 0x624:
 56.3740 +	case 0x62c:
 56.3741 +	{
 56.3742 +		// STR Rd, [Rn], -Rm, ASR #
 56.3743 +		int shift = (opcode >> 7) & 31;
 56.3744 +		int offset;
 56.3745 +		if (shift)
 56.3746 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.3747 +		else if (reg[opcode & 15].I & 0x80000000)
 56.3748 +			offset = 0xFFFFFFFF;
 56.3749 +		else
 56.3750 +			offset = 0;
 56.3751 +		int dest	= (opcode >> 12) & 15;
 56.3752 +		int base	= (opcode >> 16) & 15;
 56.3753 +		u32 address = reg[base].I;
 56.3754 +		CPUWriteMemory(address, reg[dest].I);
 56.3755 +		reg[base].I = address - offset;
 56.3756 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3757 +	}
 56.3758 +	break;
 56.3759 +	case 0x606:
 56.3760 +	case 0x60e:
 56.3761 +	// T versions are the same
 56.3762 +	case 0x626:
 56.3763 +	case 0x62e:
 56.3764 +	{
 56.3765 +		// STR Rd, [Rn], -Rm, ROR #
 56.3766 +		int shift = (opcode >> 7) & 31;
 56.3767 +		u32 value = reg[opcode & 15].I;
 56.3768 +		if (shift)
 56.3769 +		{
 56.3770 +			ROR_VALUE;
 56.3771 +		}
 56.3772 +		else
 56.3773 +		{
 56.3774 +			RCR_VALUE;
 56.3775 +		}
 56.3776 +		int dest	= (opcode >> 12) & 15;
 56.3777 +		int base	= (opcode >> 16) & 15;
 56.3778 +		u32 address = reg[base].I;
 56.3779 +		CPUWriteMemory(address, reg[dest].I);
 56.3780 +		reg[base].I = address - value;
 56.3781 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3782 +	}
 56.3783 +	break;
 56.3784 +	case 0x680:
 56.3785 +	case 0x688:
 56.3786 +	// T versions are the same
 56.3787 +	case 0x6a0:
 56.3788 +	case 0x6a8:
 56.3789 +	{
 56.3790 +		// STR Rd, [Rn], Rm, LSL #
 56.3791 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.3792 +		int dest	= (opcode >> 12) & 15;
 56.3793 +		int base	= (opcode >> 16) & 15;
 56.3794 +		u32 address = reg[base].I;
 56.3795 +		CPUWriteMemory(address, reg[dest].I);
 56.3796 +		reg[base].I = address + offset;
 56.3797 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3798 +	}
 56.3799 +	break;
 56.3800 +	case 0x682:
 56.3801 +	case 0x68a:
 56.3802 +	// T versions are the same
 56.3803 +	case 0x6a2:
 56.3804 +	case 0x6aa:
 56.3805 +	{
 56.3806 +		// STR Rd, [Rn], Rm, LSR #
 56.3807 +		int shift	= (opcode >> 7) & 31;
 56.3808 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.3809 +		int dest	= (opcode >> 12) & 15;
 56.3810 +		int base	= (opcode >> 16) & 15;
 56.3811 +		u32 address = reg[base].I;
 56.3812 +		CPUWriteMemory(address, reg[dest].I);
 56.3813 +		reg[base].I = address + offset;
 56.3814 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3815 +	}
 56.3816 +	break;
 56.3817 +	case 0x684:
 56.3818 +	case 0x68c:
 56.3819 +	// T versions are the same
 56.3820 +	case 0x6a4:
 56.3821 +	case 0x6ac:
 56.3822 +	{
 56.3823 +		// STR Rd, [Rn], Rm, ASR #
 56.3824 +		int shift = (opcode >> 7) & 31;
 56.3825 +		int offset;
 56.3826 +		if (shift)
 56.3827 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.3828 +		else if (reg[opcode & 15].I & 0x80000000)
 56.3829 +			offset = 0xFFFFFFFF;
 56.3830 +		else
 56.3831 +			offset = 0;
 56.3832 +		int dest	= (opcode >> 12) & 15;
 56.3833 +		int base	= (opcode >> 16) & 15;
 56.3834 +		u32 address = reg[base].I;
 56.3835 +		CPUWriteMemory(address, reg[dest].I);
 56.3836 +		reg[base].I = address + offset;
 56.3837 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3838 +	}
 56.3839 +	break;
 56.3840 +	case 0x686:
 56.3841 +	case 0x68e:
 56.3842 +	// T versions are the same
 56.3843 +	case 0x6a6:
 56.3844 +	case 0x6ae:
 56.3845 +	{
 56.3846 +		// STR Rd, [Rn], Rm, ROR #
 56.3847 +		int shift = (opcode >> 7) & 31;
 56.3848 +		u32 value = reg[opcode & 15].I;
 56.3849 +		if (shift)
 56.3850 +		{
 56.3851 +			ROR_VALUE;
 56.3852 +		}
 56.3853 +		else
 56.3854 +		{
 56.3855 +			RCR_VALUE;
 56.3856 +		}
 56.3857 +		int dest	= (opcode >> 12) & 15;
 56.3858 +		int base	= (opcode >> 16) & 15;
 56.3859 +		u32 address = reg[base].I;
 56.3860 +		CPUWriteMemory(address, reg[dest].I);
 56.3861 +		reg[base].I = address + value;
 56.3862 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3863 +	}
 56.3864 +	break;
 56.3865 +	case 0x700:
 56.3866 +	case 0x708:
 56.3867 +	{
 56.3868 +		// STR Rd, [Rn, -Rm, LSL #]
 56.3869 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.3870 +		int dest	= (opcode >> 12) & 15;
 56.3871 +		int base	= (opcode >> 16) & 15;
 56.3872 +		u32 address = reg[base].I - offset;
 56.3873 +		CPUWriteMemory(address, reg[dest].I);
 56.3874 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3875 +	}
 56.3876 +	break;
 56.3877 +	case 0x702:
 56.3878 +	case 0x70a:
 56.3879 +	{
 56.3880 +		// STR Rd, [Rn, -Rm, LSR #]
 56.3881 +		int shift	= (opcode >> 7) & 31;
 56.3882 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.3883 +		int dest	= (opcode >> 12) & 15;
 56.3884 +		int base	= (opcode >> 16) & 15;
 56.3885 +		u32 address = reg[base].I - offset;
 56.3886 +		CPUWriteMemory(address, reg[dest].I);
 56.3887 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3888 +	}
 56.3889 +	break;
 56.3890 +	case 0x704:
 56.3891 +	case 0x70c:
 56.3892 +	{
 56.3893 +		// STR Rd, [Rn, -Rm, ASR #]
 56.3894 +		int shift = (opcode >> 7) & 31;
 56.3895 +		int offset;
 56.3896 +		if (shift)
 56.3897 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.3898 +		else if (reg[opcode & 15].I & 0x80000000)
 56.3899 +			offset = 0xFFFFFFFF;
 56.3900 +		else
 56.3901 +			offset = 0;
 56.3902 +		int dest	= (opcode >> 12) & 15;
 56.3903 +		int base	= (opcode >> 16) & 15;
 56.3904 +		u32 address = reg[base].I - offset;
 56.3905 +		CPUWriteMemory(address, reg[dest].I);
 56.3906 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3907 +	}
 56.3908 +	break;
 56.3909 +	case 0x706:
 56.3910 +	case 0x70e:
 56.3911 +	{
 56.3912 +		// STR Rd, [Rn, -Rm, ROR #]
 56.3913 +		int shift = (opcode >> 7) & 31;
 56.3914 +		u32 value = reg[opcode & 15].I;
 56.3915 +		if (shift)
 56.3916 +		{
 56.3917 +			ROR_VALUE;
 56.3918 +		}
 56.3919 +		else
 56.3920 +		{
 56.3921 +			RCR_VALUE;
 56.3922 +		}
 56.3923 +		int dest	= (opcode >> 12) & 15;
 56.3924 +		int base	= (opcode >> 16) & 15;
 56.3925 +		u32 address = reg[base].I - value;
 56.3926 +		CPUWriteMemory(address, reg[dest].I);
 56.3927 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3928 +	}
 56.3929 +	break;
 56.3930 +	case 0x720:
 56.3931 +	case 0x728:
 56.3932 +	{
 56.3933 +		// STR Rd, [Rn, -Rm, LSL #]!
 56.3934 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.3935 +		int dest	= (opcode >> 12) & 15;
 56.3936 +		int base	= (opcode >> 16) & 15;
 56.3937 +		u32 address = reg[base].I - offset;
 56.3938 +		reg[base].I = address;
 56.3939 +		CPUWriteMemory(address, reg[dest].I);
 56.3940 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3941 +	}
 56.3942 +	break;
 56.3943 +	case 0x722:
 56.3944 +	case 0x72a:
 56.3945 +	{
 56.3946 +		// STR Rd, [Rn, -Rm, LSR #]!
 56.3947 +		int shift	= (opcode >> 7) & 31;
 56.3948 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.3949 +		int dest	= (opcode >> 12) & 15;
 56.3950 +		int base	= (opcode >> 16) & 15;
 56.3951 +		u32 address = reg[base].I - offset;
 56.3952 +		reg[base].I = address;
 56.3953 +		CPUWriteMemory(address, reg[dest].I);
 56.3954 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3955 +	}
 56.3956 +	break;
 56.3957 +	case 0x724:
 56.3958 +	case 0x72c:
 56.3959 +	{
 56.3960 +		// STR Rd, [Rn, -Rm, ASR #]!
 56.3961 +		int shift = (opcode >> 7) & 31;
 56.3962 +		int offset;
 56.3963 +		if (shift)
 56.3964 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.3965 +		else if (reg[opcode & 15].I & 0x80000000)
 56.3966 +			offset = 0xFFFFFFFF;
 56.3967 +		else
 56.3968 +			offset = 0;
 56.3969 +		int dest	= (opcode >> 12) & 15;
 56.3970 +		int base	= (opcode >> 16) & 15;
 56.3971 +		u32 address = reg[base].I - offset;
 56.3972 +		reg[base].I = address;
 56.3973 +		CPUWriteMemory(address, reg[dest].I);
 56.3974 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3975 +	}
 56.3976 +	break;
 56.3977 +	case 0x726:
 56.3978 +	case 0x72e:
 56.3979 +	{
 56.3980 +		// STR Rd, [Rn, -Rm, ROR #]!
 56.3981 +		int shift = (opcode >> 7) & 31;
 56.3982 +		u32 value = reg[opcode & 15].I;
 56.3983 +		if (shift)
 56.3984 +		{
 56.3985 +			ROR_VALUE;
 56.3986 +		}
 56.3987 +		else
 56.3988 +		{
 56.3989 +			RCR_VALUE;
 56.3990 +		}
 56.3991 +		int dest	= (opcode >> 12) & 15;
 56.3992 +		int base	= (opcode >> 16) & 15;
 56.3993 +		u32 address = reg[base].I - value;
 56.3994 +		reg[base].I = address;
 56.3995 +		CPUWriteMemory(address, reg[dest].I);
 56.3996 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.3997 +	}
 56.3998 +	break;
 56.3999 +	case 0x780:
 56.4000 +	case 0x788:
 56.4001 +	{
 56.4002 +		// STR Rd, [Rn, Rm, LSL #]
 56.4003 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4004 +		int dest	= (opcode >> 12) & 15;
 56.4005 +		int base	= (opcode >> 16) & 15;
 56.4006 +		u32 address = reg[base].I + offset;
 56.4007 +		CPUWriteMemory(address, reg[dest].I);
 56.4008 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.4009 +	}
 56.4010 +	break;
 56.4011 +	case 0x782:
 56.4012 +	case 0x78a:
 56.4013 +	{
 56.4014 +		// STR Rd, [Rn, Rm, LSR #]
 56.4015 +		int shift	= (opcode >> 7) & 31;
 56.4016 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4017 +		int dest	= (opcode >> 12) & 15;
 56.4018 +		int base	= (opcode >> 16) & 15;
 56.4019 +		u32 address = reg[base].I + offset;
 56.4020 +		CPUWriteMemory(address, reg[dest].I);
 56.4021 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.4022 +	}
 56.4023 +	break;
 56.4024 +	case 0x784:
 56.4025 +	case 0x78c:
 56.4026 +	{
 56.4027 +		// STR Rd, [Rn, Rm, ASR #]
 56.4028 +		int shift = (opcode >> 7) & 31;
 56.4029 +		int offset;
 56.4030 +		if (shift)
 56.4031 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4032 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4033 +			offset = 0xFFFFFFFF;
 56.4034 +		else
 56.4035 +			offset = 0;
 56.4036 +		int dest	= (opcode >> 12) & 15;
 56.4037 +		int base	= (opcode >> 16) & 15;
 56.4038 +		u32 address = reg[base].I + offset;
 56.4039 +		CPUWriteMemory(address, reg[dest].I);
 56.4040 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.4041 +	}
 56.4042 +	break;
 56.4043 +	case 0x786:
 56.4044 +	case 0x78e:
 56.4045 +	{
 56.4046 +		// STR Rd, [Rn, Rm, ROR #]
 56.4047 +		int shift = (opcode >> 7) & 31;
 56.4048 +		u32 value = reg[opcode & 15].I;
 56.4049 +		if (shift)
 56.4050 +		{
 56.4051 +			ROR_VALUE;
 56.4052 +		}
 56.4053 +		else
 56.4054 +		{
 56.4055 +			RCR_VALUE;
 56.4056 +		}
 56.4057 +		int dest	= (opcode >> 12) & 15;
 56.4058 +		int base	= (opcode >> 16) & 15;
 56.4059 +		u32 address = reg[base].I + value;
 56.4060 +		CPUWriteMemory(address, reg[dest].I);
 56.4061 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.4062 +	}
 56.4063 +	break;
 56.4064 +	case 0x7a0:
 56.4065 +	case 0x7a8:
 56.4066 +	{
 56.4067 +		// STR Rd, [Rn, Rm, LSL #]!
 56.4068 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4069 +		int dest	= (opcode >> 12) & 15;
 56.4070 +		int base	= (opcode >> 16) & 15;
 56.4071 +		u32 address = reg[base].I + offset;
 56.4072 +		reg[base].I = address;
 56.4073 +		CPUWriteMemory(address, reg[dest].I);
 56.4074 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.4075 +	}
 56.4076 +	break;
 56.4077 +	case 0x7a2:
 56.4078 +	case 0x7aa:
 56.4079 +	{
 56.4080 +		// STR Rd, [Rn, Rm, LSR #]!
 56.4081 +		int shift	= (opcode >> 7) & 31;
 56.4082 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4083 +		int dest	= (opcode >> 12) & 15;
 56.4084 +		int base	= (opcode >> 16) & 15;
 56.4085 +		u32 address = reg[base].I + offset;
 56.4086 +		reg[base].I = address;
 56.4087 +		CPUWriteMemory(address, reg[dest].I);
 56.4088 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.4089 +	}
 56.4090 +	break;
 56.4091 +	case 0x7a4:
 56.4092 +	case 0x7ac:
 56.4093 +	{
 56.4094 +		// STR Rd, [Rn, Rm, ASR #]!
 56.4095 +		int shift = (opcode >> 7) & 31;
 56.4096 +		int offset;
 56.4097 +		if (shift)
 56.4098 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4099 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4100 +			offset = 0xFFFFFFFF;
 56.4101 +		else
 56.4102 +			offset = 0;
 56.4103 +		int dest	= (opcode >> 12) & 15;
 56.4104 +		int base	= (opcode >> 16) & 15;
 56.4105 +		u32 address = reg[base].I + offset;
 56.4106 +		reg[base].I = address;
 56.4107 +		CPUWriteMemory(address, reg[dest].I);
 56.4108 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.4109 +	}
 56.4110 +	break;
 56.4111 +	case 0x7a6:
 56.4112 +	case 0x7ae:
 56.4113 +	{
 56.4114 +		// STR Rd, [Rn, Rm, ROR #]!
 56.4115 +		int shift = (opcode >> 7) & 31;
 56.4116 +		u32 value = reg[opcode & 15].I;
 56.4117 +		if (shift)
 56.4118 +		{
 56.4119 +			ROR_VALUE;
 56.4120 +		}
 56.4121 +		else
 56.4122 +		{
 56.4123 +			RCR_VALUE;
 56.4124 +		}
 56.4125 +		int dest	= (opcode >> 12) & 15;
 56.4126 +		int base	= (opcode >> 16) & 15;
 56.4127 +		u32 address = reg[base].I + value;
 56.4128 +		reg[base].I = address;
 56.4129 +		CPUWriteMemory(address, reg[dest].I);
 56.4130 +		clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.4131 +	}
 56.4132 +	break;
 56.4133 +	case 0x610:
 56.4134 +	case 0x618:
 56.4135 +	// T versions are the same
 56.4136 +	case 0x630:
 56.4137 +	case 0x638:
 56.4138 +	{
 56.4139 +		// LDR Rd, [Rn], -Rm, LSL #
 56.4140 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4141 +		int dest	= (opcode >> 12) & 15;
 56.4142 +		int base	= (opcode >> 16) & 15;
 56.4143 +		u32 address = reg[base].I;
 56.4144 +		reg[dest].I = CPUReadMemory(address);
 56.4145 +		if (dest != base)
 56.4146 +			reg[base].I = address - offset;
 56.4147 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4148 +		if (dest == 15)
 56.4149 +		{
 56.4150 +			clockTicks += 2;
 56.4151 +			reg[15].I  &= 0xFFFFFFFC;
 56.4152 +			armNextPC	= reg[15].I;
 56.4153 +			reg[15].I  += 4;
 56.4154 +		}
 56.4155 +	}
 56.4156 +	break;
 56.4157 +	case 0x612:
 56.4158 +	case 0x61a:
 56.4159 +	// T versions are the same
 56.4160 +	case 0x632:
 56.4161 +	case 0x63a:
 56.4162 +	{
 56.4163 +		// LDR Rd, [Rn], -Rm, LSR #
 56.4164 +		int shift	= (opcode >> 7) & 31;
 56.4165 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4166 +		int dest	= (opcode >> 12) & 15;
 56.4167 +		int base	= (opcode >> 16) & 15;
 56.4168 +		u32 address = reg[base].I;
 56.4169 +		reg[dest].I = CPUReadMemory(address);
 56.4170 +		if (dest != base)
 56.4171 +			reg[base].I = address - offset;
 56.4172 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4173 +		if (dest == 15)
 56.4174 +		{
 56.4175 +			clockTicks += 2;
 56.4176 +			reg[15].I  &= 0xFFFFFFFC;
 56.4177 +			armNextPC	= reg[15].I;
 56.4178 +			reg[15].I  += 4;
 56.4179 +		}
 56.4180 +	}
 56.4181 +	break;
 56.4182 +	case 0x614:
 56.4183 +	case 0x61c:
 56.4184 +	// T versions are the same
 56.4185 +	case 0x634:
 56.4186 +	case 0x63c:
 56.4187 +	{
 56.4188 +		// LDR Rd, [Rn], -Rm, ASR #
 56.4189 +		int shift = (opcode >> 7) & 31;
 56.4190 +		int offset;
 56.4191 +		if (shift)
 56.4192 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4193 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4194 +			offset = 0xFFFFFFFF;
 56.4195 +		else
 56.4196 +			offset = 0;
 56.4197 +		int dest	= (opcode >> 12) & 15;
 56.4198 +		int base	= (opcode >> 16) & 15;
 56.4199 +		u32 address = reg[base].I;
 56.4200 +		reg[dest].I = CPUReadMemory(address);
 56.4201 +		if (dest != base)
 56.4202 +			reg[base].I = address - offset;
 56.4203 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4204 +		if (dest == 15)
 56.4205 +		{
 56.4206 +			clockTicks += 2;
 56.4207 +			reg[15].I  &= 0xFFFFFFFC;
 56.4208 +			armNextPC	= reg[15].I;
 56.4209 +			reg[15].I  += 4;
 56.4210 +		}
 56.4211 +	}
 56.4212 +	break;
 56.4213 +	case 0x616:
 56.4214 +	case 0x61e:
 56.4215 +	// T versions are the same
 56.4216 +	case 0x636:
 56.4217 +	case 0x63e:
 56.4218 +	{
 56.4219 +		// LDR Rd, [Rn], -Rm, ROR #
 56.4220 +		int shift = (opcode >> 7) & 31;
 56.4221 +		u32 value = reg[opcode & 15].I;
 56.4222 +		if (shift)
 56.4223 +		{
 56.4224 +			ROR_VALUE;
 56.4225 +		}
 56.4226 +		else
 56.4227 +		{
 56.4228 +			RCR_VALUE;
 56.4229 +		}
 56.4230 +		int dest	= (opcode >> 12) & 15;
 56.4231 +		int base	= (opcode >> 16) & 15;
 56.4232 +		u32 address = reg[base].I;
 56.4233 +		reg[dest].I = CPUReadMemory(address);
 56.4234 +		if (dest != base)
 56.4235 +			reg[base].I = address - value;
 56.4236 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4237 +		if (dest == 15)
 56.4238 +		{
 56.4239 +			clockTicks += 2;
 56.4240 +			reg[15].I  &= 0xFFFFFFFC;
 56.4241 +			armNextPC	= reg[15].I;
 56.4242 +			reg[15].I  += 4;
 56.4243 +		}
 56.4244 +	}
 56.4245 +	break;
 56.4246 +	case 0x690:
 56.4247 +	case 0x698:
 56.4248 +	// T versions are the same
 56.4249 +	case 0x6b0:
 56.4250 +	case 0x6b8:
 56.4251 +	{
 56.4252 +		// LDR Rd, [Rn], Rm, LSL #
 56.4253 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4254 +		int dest	= (opcode >> 12) & 15;
 56.4255 +		int base	= (opcode >> 16) & 15;
 56.4256 +		u32 address = reg[base].I;
 56.4257 +		reg[dest].I = CPUReadMemory(address);
 56.4258 +		if (dest != base)
 56.4259 +			reg[base].I = address + offset;
 56.4260 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4261 +		if (dest == 15)
 56.4262 +		{
 56.4263 +			clockTicks += 2;
 56.4264 +			reg[15].I  &= 0xFFFFFFFC;
 56.4265 +			armNextPC	= reg[15].I;
 56.4266 +			reg[15].I  += 4;
 56.4267 +		}
 56.4268 +	}
 56.4269 +	break;
 56.4270 +	case 0x692:
 56.4271 +	case 0x69a:
 56.4272 +	// T versions are the same
 56.4273 +	case 0x6b2:
 56.4274 +	case 0x6ba:
 56.4275 +	{
 56.4276 +		// LDR Rd, [Rn], Rm, LSR #
 56.4277 +		int shift	= (opcode >> 7) & 31;
 56.4278 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4279 +		int dest	= (opcode >> 12) & 15;
 56.4280 +		int base	= (opcode >> 16) & 15;
 56.4281 +		u32 address = reg[base].I;
 56.4282 +		reg[dest].I = CPUReadMemory(address);
 56.4283 +		if (dest != base)
 56.4284 +			reg[base].I = address + offset;
 56.4285 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4286 +		if (dest == 15)
 56.4287 +		{
 56.4288 +			clockTicks += 2;
 56.4289 +			reg[15].I  &= 0xFFFFFFFC;
 56.4290 +			armNextPC	= reg[15].I;
 56.4291 +			reg[15].I  += 4;
 56.4292 +		}
 56.4293 +	}
 56.4294 +	break;
 56.4295 +	case 0x694:
 56.4296 +	case 0x69c:
 56.4297 +	// T versions are the same
 56.4298 +	case 0x6b4:
 56.4299 +	case 0x6bc:
 56.4300 +	{
 56.4301 +		// LDR Rd, [Rn], Rm, ASR #
 56.4302 +		int shift = (opcode >> 7) & 31;
 56.4303 +		int offset;
 56.4304 +		if (shift)
 56.4305 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4306 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4307 +			offset = 0xFFFFFFFF;
 56.4308 +		else
 56.4309 +			offset = 0;
 56.4310 +		int dest	= (opcode >> 12) & 15;
 56.4311 +		int base	= (opcode >> 16) & 15;
 56.4312 +		u32 address = reg[base].I;
 56.4313 +		reg[dest].I = CPUReadMemory(address);
 56.4314 +		if (dest != base)
 56.4315 +			reg[base].I = address + offset;
 56.4316 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4317 +		if (dest == 15)
 56.4318 +		{
 56.4319 +			clockTicks += 2;
 56.4320 +			reg[15].I  &= 0xFFFFFFFC;
 56.4321 +			armNextPC	= reg[15].I;
 56.4322 +			reg[15].I  += 4;
 56.4323 +		}
 56.4324 +	}
 56.4325 +	break;
 56.4326 +	case 0x696:
 56.4327 +	case 0x69e:
 56.4328 +	// T versions are the same
 56.4329 +	case 0x6b6:
 56.4330 +	case 0x6be:
 56.4331 +	{
 56.4332 +		// LDR Rd, [Rn], Rm, ROR #
 56.4333 +		int shift = (opcode >> 7) & 31;
 56.4334 +		u32 value = reg[opcode & 15].I;
 56.4335 +		if (shift)
 56.4336 +		{
 56.4337 +			ROR_VALUE;
 56.4338 +		}
 56.4339 +		else
 56.4340 +		{
 56.4341 +			RCR_VALUE;
 56.4342 +		}
 56.4343 +		int dest	= (opcode >> 12) & 15;
 56.4344 +		int base	= (opcode >> 16) & 15;
 56.4345 +		u32 address = reg[base].I;
 56.4346 +		reg[dest].I = CPUReadMemory(address);
 56.4347 +		if (dest != base)
 56.4348 +			reg[base].I = address + value;
 56.4349 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4350 +		if (dest == 15)
 56.4351 +		{
 56.4352 +			clockTicks += 2;
 56.4353 +			reg[15].I  &= 0xFFFFFFFC;
 56.4354 +			armNextPC	= reg[15].I;
 56.4355 +			reg[15].I  += 4;
 56.4356 +		}
 56.4357 +	}
 56.4358 +	break;
 56.4359 +	case 0x710:
 56.4360 +	case 0x718:
 56.4361 +	{
 56.4362 +		// LDR Rd, [Rn, -Rm, LSL #]
 56.4363 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4364 +		int dest	= (opcode >> 12) & 15;
 56.4365 +		int base	= (opcode >> 16) & 15;
 56.4366 +		u32 address = reg[base].I - offset;
 56.4367 +		reg[dest].I = CPUReadMemory(address);
 56.4368 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4369 +		if (dest == 15)
 56.4370 +		{
 56.4371 +			clockTicks += 2;
 56.4372 +			reg[15].I  &= 0xFFFFFFFC;
 56.4373 +			armNextPC	= reg[15].I;
 56.4374 +			reg[15].I  += 4;
 56.4375 +		}
 56.4376 +	}
 56.4377 +	break;
 56.4378 +	case 0x712:
 56.4379 +	case 0x71a:
 56.4380 +	{
 56.4381 +		// LDR Rd, [Rn, -Rm, LSR #]
 56.4382 +		int shift	= (opcode >> 7) & 31;
 56.4383 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4384 +		int dest	= (opcode >> 12) & 15;
 56.4385 +		int base	= (opcode >> 16) & 15;
 56.4386 +		u32 address = reg[base].I - offset;
 56.4387 +		reg[dest].I = CPUReadMemory(address);
 56.4388 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4389 +		if (dest == 15)
 56.4390 +		{
 56.4391 +			clockTicks += 2;
 56.4392 +			reg[15].I  &= 0xFFFFFFFC;
 56.4393 +			armNextPC	= reg[15].I;
 56.4394 +			reg[15].I  += 4;
 56.4395 +		}
 56.4396 +	}
 56.4397 +	break;
 56.4398 +	case 0x714:
 56.4399 +	case 0x71c:
 56.4400 +	{
 56.4401 +		// LDR Rd, [Rn, -Rm, ASR #]
 56.4402 +		int shift = (opcode >> 7) & 31;
 56.4403 +		int offset;
 56.4404 +		if (shift)
 56.4405 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4406 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4407 +			offset = 0xFFFFFFFF;
 56.4408 +		else
 56.4409 +			offset = 0;
 56.4410 +		int dest	= (opcode >> 12) & 15;
 56.4411 +		int base	= (opcode >> 16) & 15;
 56.4412 +		u32 address = reg[base].I - offset;
 56.4413 +		reg[dest].I = CPUReadMemory(address);
 56.4414 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4415 +		if (dest == 15)
 56.4416 +		{
 56.4417 +			clockTicks += 2;
 56.4418 +			reg[15].I  &= 0xFFFFFFFC;
 56.4419 +			armNextPC	= reg[15].I;
 56.4420 +			reg[15].I  += 4;
 56.4421 +		}
 56.4422 +	}
 56.4423 +	break;
 56.4424 +	case 0x716:
 56.4425 +	case 0x71e:
 56.4426 +	{
 56.4427 +		// LDR Rd, [Rn, -Rm, ROR #]
 56.4428 +		int shift = (opcode >> 7) & 31;
 56.4429 +		u32 value = reg[opcode & 15].I;
 56.4430 +		if (shift)
 56.4431 +		{
 56.4432 +			ROR_VALUE;
 56.4433 +		}
 56.4434 +		else
 56.4435 +		{
 56.4436 +			RCR_VALUE;
 56.4437 +		}
 56.4438 +		int dest	= (opcode >> 12) & 15;
 56.4439 +		int base	= (opcode >> 16) & 15;
 56.4440 +		u32 address = reg[base].I - value;
 56.4441 +		reg[dest].I = CPUReadMemory(address);
 56.4442 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4443 +		if (dest == 15)
 56.4444 +		{
 56.4445 +			clockTicks += 2;
 56.4446 +			reg[15].I  &= 0xFFFFFFFC;
 56.4447 +			armNextPC	= reg[15].I;
 56.4448 +			reg[15].I  += 4;
 56.4449 +		}
 56.4450 +	}
 56.4451 +	break;
 56.4452 +	case 0x730:
 56.4453 +	case 0x738:
 56.4454 +	{
 56.4455 +		// LDR Rd, [Rn, -Rm, LSL #]!
 56.4456 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4457 +		int dest	= (opcode >> 12) & 15;
 56.4458 +		int base	= (opcode >> 16) & 15;
 56.4459 +		u32 address = reg[base].I - offset;
 56.4460 +		reg[dest].I = CPUReadMemory(address);
 56.4461 +		if (dest != base)
 56.4462 +			reg[base].I = address;
 56.4463 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4464 +		if (dest == 15)
 56.4465 +		{
 56.4466 +			clockTicks += 2;
 56.4467 +			reg[15].I  &= 0xFFFFFFFC;
 56.4468 +			armNextPC	= reg[15].I;
 56.4469 +			reg[15].I  += 4;
 56.4470 +		}
 56.4471 +	}
 56.4472 +	break;
 56.4473 +	case 0x732:
 56.4474 +	case 0x73a:
 56.4475 +	{
 56.4476 +		// LDR Rd, [Rn, -Rm, LSR #]!
 56.4477 +		int shift	= (opcode >> 7) & 31;
 56.4478 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4479 +		int dest	= (opcode >> 12) & 15;
 56.4480 +		int base	= (opcode >> 16) & 15;
 56.4481 +		u32 address = reg[base].I - offset;
 56.4482 +		reg[dest].I = CPUReadMemory(address);
 56.4483 +		if (dest != base)
 56.4484 +			reg[base].I = address;
 56.4485 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4486 +		if (dest == 15)
 56.4487 +		{
 56.4488 +			clockTicks += 2;
 56.4489 +			reg[15].I  &= 0xFFFFFFFC;
 56.4490 +			armNextPC	= reg[15].I;
 56.4491 +			reg[15].I  += 4;
 56.4492 +		}
 56.4493 +	}
 56.4494 +	break;
 56.4495 +	case 0x734:
 56.4496 +	case 0x73c:
 56.4497 +	{
 56.4498 +		// LDR Rd, [Rn, -Rm, ASR #]!
 56.4499 +		int shift = (opcode >> 7) & 31;
 56.4500 +		int offset;
 56.4501 +		if (shift)
 56.4502 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4503 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4504 +			offset = 0xFFFFFFFF;
 56.4505 +		else
 56.4506 +			offset = 0;
 56.4507 +		int dest	= (opcode >> 12) & 15;
 56.4508 +		int base	= (opcode >> 16) & 15;
 56.4509 +		u32 address = reg[base].I - offset;
 56.4510 +		reg[dest].I = CPUReadMemory(address);
 56.4511 +		if (dest != base)
 56.4512 +			reg[base].I = address;
 56.4513 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4514 +		if (dest == 15)
 56.4515 +		{
 56.4516 +			clockTicks += 2;
 56.4517 +			reg[15].I  &= 0xFFFFFFFC;
 56.4518 +			armNextPC	= reg[15].I;
 56.4519 +			reg[15].I  += 4;
 56.4520 +		}
 56.4521 +	}
 56.4522 +	break;
 56.4523 +	case 0x736:
 56.4524 +	case 0x73e:
 56.4525 +	{
 56.4526 +		// LDR Rd, [Rn, -Rm, ROR #]!
 56.4527 +		int shift = (opcode >> 7) & 31;
 56.4528 +		u32 value = reg[opcode & 15].I;
 56.4529 +		if (shift)
 56.4530 +		{
 56.4531 +			ROR_VALUE;
 56.4532 +		}
 56.4533 +		else
 56.4534 +		{
 56.4535 +			RCR_VALUE;
 56.4536 +		}
 56.4537 +		int dest	= (opcode >> 12) & 15;
 56.4538 +		int base	= (opcode >> 16) & 15;
 56.4539 +		u32 address = reg[base].I - value;
 56.4540 +		reg[dest].I = CPUReadMemory(address);
 56.4541 +		if (dest != base)
 56.4542 +			reg[base].I = address;
 56.4543 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4544 +		if (dest == 15)
 56.4545 +		{
 56.4546 +			clockTicks += 2;
 56.4547 +			reg[15].I  &= 0xFFFFFFFC;
 56.4548 +			armNextPC	= reg[15].I;
 56.4549 +			reg[15].I  += 4;
 56.4550 +		}
 56.4551 +	}
 56.4552 +	break;
 56.4553 +	case 0x790:
 56.4554 +	case 0x798:
 56.4555 +	{
 56.4556 +		// LDR Rd, [Rn, Rm, LSL #]
 56.4557 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4558 +		int dest	= (opcode >> 12) & 15;
 56.4559 +		int base	= (opcode >> 16) & 15;
 56.4560 +		u32 address = reg[base].I + offset;
 56.4561 +		reg[dest].I = CPUReadMemory(address);
 56.4562 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4563 +		if (dest == 15)
 56.4564 +		{
 56.4565 +			clockTicks += 2;
 56.4566 +			reg[15].I  &= 0xFFFFFFFC;
 56.4567 +			armNextPC	= reg[15].I;
 56.4568 +			reg[15].I  += 4;
 56.4569 +		}
 56.4570 +	}
 56.4571 +	break;
 56.4572 +	case 0x792:
 56.4573 +	case 0x79a:
 56.4574 +	{
 56.4575 +		// LDR Rd, [Rn, Rm, LSR #]
 56.4576 +		int shift	= (opcode >> 7) & 31;
 56.4577 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4578 +		int dest	= (opcode >> 12) & 15;
 56.4579 +		int base	= (opcode >> 16) & 15;
 56.4580 +		u32 address = reg[base].I + offset;
 56.4581 +		reg[dest].I = CPUReadMemory(address);
 56.4582 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4583 +		if (dest == 15)
 56.4584 +		{
 56.4585 +			clockTicks += 2;
 56.4586 +			reg[15].I  &= 0xFFFFFFFC;
 56.4587 +			armNextPC	= reg[15].I;
 56.4588 +			reg[15].I  += 4;
 56.4589 +		}
 56.4590 +	}
 56.4591 +	break;
 56.4592 +	case 0x794:
 56.4593 +	case 0x79c:
 56.4594 +	{
 56.4595 +		// LDR Rd, [Rn, Rm, ASR #]
 56.4596 +		int shift = (opcode >> 7) & 31;
 56.4597 +		int offset;
 56.4598 +		if (shift)
 56.4599 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4600 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4601 +			offset = 0xFFFFFFFF;
 56.4602 +		else
 56.4603 +			offset = 0;
 56.4604 +		int dest	= (opcode >> 12) & 15;
 56.4605 +		int base	= (opcode >> 16) & 15;
 56.4606 +		u32 address = reg[base].I + offset;
 56.4607 +		reg[dest].I = CPUReadMemory(address);
 56.4608 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4609 +		if (dest == 15)
 56.4610 +		{
 56.4611 +			clockTicks += 2;
 56.4612 +			reg[15].I  &= 0xFFFFFFFC;
 56.4613 +			armNextPC	= reg[15].I;
 56.4614 +			reg[15].I  += 4;
 56.4615 +		}
 56.4616 +	}
 56.4617 +	break;
 56.4618 +	case 0x796:
 56.4619 +	case 0x79e:
 56.4620 +	{
 56.4621 +		// LDR Rd, [Rn, Rm, ROR #]
 56.4622 +		int shift = (opcode >> 7) & 31;
 56.4623 +		u32 value = reg[opcode & 15].I;
 56.4624 +		if (shift)
 56.4625 +		{
 56.4626 +			ROR_VALUE;
 56.4627 +		}
 56.4628 +		else
 56.4629 +		{
 56.4630 +			RCR_VALUE;
 56.4631 +		}
 56.4632 +		int dest	= (opcode >> 12) & 15;
 56.4633 +		int base	= (opcode >> 16) & 15;
 56.4634 +		u32 address = reg[base].I + value;
 56.4635 +		reg[dest].I = CPUReadMemory(address);
 56.4636 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4637 +		if (dest == 15)
 56.4638 +		{
 56.4639 +			clockTicks += 2;
 56.4640 +			reg[15].I  &= 0xFFFFFFFC;
 56.4641 +			armNextPC	= reg[15].I;
 56.4642 +			reg[15].I  += 4;
 56.4643 +		}
 56.4644 +	}
 56.4645 +	break;
 56.4646 +	case 0x7b0:
 56.4647 +	case 0x7b8:
 56.4648 +	{
 56.4649 +		// LDR Rd, [Rn, Rm, LSL #]!
 56.4650 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4651 +		int dest	= (opcode >> 12) & 15;
 56.4652 +		int base	= (opcode >> 16) & 15;
 56.4653 +		u32 address = reg[base].I + offset;
 56.4654 +		reg[dest].I = CPUReadMemory(address);
 56.4655 +		if (dest != base)
 56.4656 +			reg[base].I = address;
 56.4657 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4658 +		if (dest == 15)
 56.4659 +		{
 56.4660 +			clockTicks += 2;
 56.4661 +			reg[15].I  &= 0xFFFFFFFC;
 56.4662 +			armNextPC	= reg[15].I;
 56.4663 +			reg[15].I  += 4;
 56.4664 +		}
 56.4665 +	}
 56.4666 +	break;
 56.4667 +	case 0x7b2:
 56.4668 +	case 0x7ba:
 56.4669 +	{
 56.4670 +		// LDR Rd, [Rn, Rm, LSR #]!
 56.4671 +		int shift	= (opcode >> 7) & 31;
 56.4672 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4673 +		int dest	= (opcode >> 12) & 15;
 56.4674 +		int base	= (opcode >> 16) & 15;
 56.4675 +		u32 address = reg[base].I + offset;
 56.4676 +		reg[dest].I = CPUReadMemory(address);
 56.4677 +		if (dest != base)
 56.4678 +			reg[base].I = address;
 56.4679 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4680 +		if (dest == 15)
 56.4681 +		{
 56.4682 +			clockTicks += 2;
 56.4683 +			reg[15].I  &= 0xFFFFFFFC;
 56.4684 +			armNextPC	= reg[15].I;
 56.4685 +			reg[15].I  += 4;
 56.4686 +		}
 56.4687 +	}
 56.4688 +	break;
 56.4689 +	case 0x7b4:
 56.4690 +	case 0x7bc:
 56.4691 +	{
 56.4692 +		// LDR Rd, [Rn, Rm, ASR #]!
 56.4693 +		int shift = (opcode >> 7) & 31;
 56.4694 +		int offset;
 56.4695 +		if (shift)
 56.4696 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4697 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4698 +			offset = 0xFFFFFFFF;
 56.4699 +		else
 56.4700 +			offset = 0;
 56.4701 +		int dest	= (opcode >> 12) & 15;
 56.4702 +		int base	= (opcode >> 16) & 15;
 56.4703 +		u32 address = reg[base].I + offset;
 56.4704 +		reg[dest].I = CPUReadMemory(address);
 56.4705 +		if (dest != base)
 56.4706 +			reg[base].I = address;
 56.4707 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4708 +		if (dest == 15)
 56.4709 +		{
 56.4710 +			clockTicks += 2;
 56.4711 +			reg[15].I  &= 0xFFFFFFFC;
 56.4712 +			armNextPC	= reg[15].I;
 56.4713 +			reg[15].I  += 4;
 56.4714 +		}
 56.4715 +	}
 56.4716 +	break;
 56.4717 +	case 0x7b6:
 56.4718 +	case 0x7be:
 56.4719 +	{
 56.4720 +		// LDR Rd, [Rn, Rm, ROR #]!
 56.4721 +		int shift = (opcode >> 7) & 31;
 56.4722 +		u32 value = reg[opcode & 15].I;
 56.4723 +		if (shift)
 56.4724 +		{
 56.4725 +			ROR_VALUE;
 56.4726 +		}
 56.4727 +		else
 56.4728 +		{
 56.4729 +			RCR_VALUE;
 56.4730 +		}
 56.4731 +		int dest	= (opcode >> 12) & 15;
 56.4732 +		int base	= (opcode >> 16) & 15;
 56.4733 +		u32 address = reg[base].I + value;
 56.4734 +		reg[dest].I = CPUReadMemory(address);
 56.4735 +		if (dest != base)
 56.4736 +			reg[base].I = address;
 56.4737 +		clockTicks += 3 + CPUUpdateTicksAccess32(address);
 56.4738 +		if (dest == 15)
 56.4739 +		{
 56.4740 +			clockTicks += 2;
 56.4741 +			reg[15].I  &= 0xFFFFFFFC;
 56.4742 +			armNextPC	= reg[15].I;
 56.4743 +			reg[15].I  += 4;
 56.4744 +		}
 56.4745 +	}
 56.4746 +	break;
 56.4747 +	case 0x640:
 56.4748 +	case 0x648:
 56.4749 +	// T versions are the same
 56.4750 +	case 0x660:
 56.4751 +	case 0x668:
 56.4752 +	{
 56.4753 +		// STRB Rd, [Rn], -Rm, LSL #
 56.4754 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4755 +		int dest	= (opcode >> 12) & 15;
 56.4756 +		int base	= (opcode >> 16) & 15;
 56.4757 +		u32 address = reg[base].I;
 56.4758 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4759 +		reg[base].I = address - offset;
 56.4760 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4761 +	}
 56.4762 +	break;
 56.4763 +	case 0x642:
 56.4764 +	case 0x64a:
 56.4765 +	// T versions are the same
 56.4766 +	case 0x662:
 56.4767 +	case 0x66a:
 56.4768 +	{
 56.4769 +		// STRB Rd, [Rn], -Rm, LSR #
 56.4770 +		int shift	= (opcode >> 7) & 31;
 56.4771 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4772 +		int dest	= (opcode >> 12) & 15;
 56.4773 +		int base	= (opcode >> 16) & 15;
 56.4774 +		u32 address = reg[base].I;
 56.4775 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4776 +		reg[base].I = address - offset;
 56.4777 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4778 +	}
 56.4779 +	break;
 56.4780 +	case 0x644:
 56.4781 +	case 0x64c:
 56.4782 +	// T versions are the same
 56.4783 +	case 0x664:
 56.4784 +	case 0x66c:
 56.4785 +	{
 56.4786 +		// STRB Rd, [Rn], -Rm, ASR #
 56.4787 +		int shift = (opcode >> 7) & 31;
 56.4788 +		int offset;
 56.4789 +		if (shift)
 56.4790 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4791 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4792 +			offset = 0xFFFFFFFF;
 56.4793 +		else
 56.4794 +			offset = 0;
 56.4795 +		int dest	= (opcode >> 12) & 15;
 56.4796 +		int base	= (opcode >> 16) & 15;
 56.4797 +		u32 address = reg[base].I;
 56.4798 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4799 +		reg[base].I = address - offset;
 56.4800 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4801 +	}
 56.4802 +	break;
 56.4803 +	case 0x646:
 56.4804 +	case 0x64e:
 56.4805 +	// T versions are the same
 56.4806 +	case 0x666:
 56.4807 +	case 0x66e:
 56.4808 +	{
 56.4809 +		// STRB Rd, [Rn], -Rm, ROR #
 56.4810 +		int shift = (opcode >> 7) & 31;
 56.4811 +		u32 value = reg[opcode & 15].I;
 56.4812 +		if (shift)
 56.4813 +		{
 56.4814 +			ROR_VALUE;
 56.4815 +		}
 56.4816 +		else
 56.4817 +		{
 56.4818 +			RCR_VALUE;
 56.4819 +		}
 56.4820 +		int dest	= (opcode >> 12) & 15;
 56.4821 +		int base	= (opcode >> 16) & 15;
 56.4822 +		u32 address = reg[base].I;
 56.4823 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4824 +		reg[base].I = address - value;
 56.4825 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4826 +	}
 56.4827 +	break;
 56.4828 +	case 0x6c0:
 56.4829 +	case 0x6c8:
 56.4830 +	// T versions are the same
 56.4831 +	case 0x6e0:
 56.4832 +	case 0x6e8:
 56.4833 +	{
 56.4834 +		// STRB Rd, [Rn], Rm, LSL #
 56.4835 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4836 +		int dest	= (opcode >> 12) & 15;
 56.4837 +		int base	= (opcode >> 16) & 15;
 56.4838 +		u32 address = reg[base].I;
 56.4839 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4840 +		reg[base].I = address + offset;
 56.4841 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4842 +	}
 56.4843 +	break;
 56.4844 +	case 0x6c2:
 56.4845 +	case 0x6ca:
 56.4846 +	// T versions are the same
 56.4847 +	case 0x6e2:
 56.4848 +	case 0x6ea:
 56.4849 +	{
 56.4850 +		// STRB Rd, [Rn], Rm, LSR #
 56.4851 +		int shift	= (opcode >> 7) & 31;
 56.4852 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4853 +		int dest	= (opcode >> 12) & 15;
 56.4854 +		int base	= (opcode >> 16) & 15;
 56.4855 +		u32 address = reg[base].I;
 56.4856 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4857 +		reg[base].I = address + offset;
 56.4858 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4859 +	}
 56.4860 +	break;
 56.4861 +	case 0x6c4:
 56.4862 +	case 0x6cc:
 56.4863 +	// T versions are the same
 56.4864 +	case 0x6e4:
 56.4865 +	case 0x6ec:
 56.4866 +	{
 56.4867 +		// STR Rd, [Rn], Rm, ASR #
 56.4868 +		int shift = (opcode >> 7) & 31;
 56.4869 +		int offset;
 56.4870 +		if (shift)
 56.4871 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4872 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4873 +			offset = 0xFFFFFFFF;
 56.4874 +		else
 56.4875 +			offset = 0;
 56.4876 +		int dest	= (opcode >> 12) & 15;
 56.4877 +		int base	= (opcode >> 16) & 15;
 56.4878 +		u32 address = reg[base].I;
 56.4879 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4880 +		reg[base].I = address + offset;
 56.4881 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4882 +	}
 56.4883 +	break;
 56.4884 +	case 0x6c6:
 56.4885 +	case 0x6ce:
 56.4886 +	// T versions are the same
 56.4887 +	case 0x6e6:
 56.4888 +	case 0x6ee:
 56.4889 +	{
 56.4890 +		// STRB Rd, [Rn], Rm, ROR #
 56.4891 +		int shift = (opcode >> 7) & 31;
 56.4892 +		u32 value = reg[opcode & 15].I;
 56.4893 +		if (shift)
 56.4894 +		{
 56.4895 +			ROR_VALUE;
 56.4896 +		}
 56.4897 +		else
 56.4898 +		{
 56.4899 +			RCR_VALUE;
 56.4900 +		}
 56.4901 +		int dest	= (opcode >> 12) & 15;
 56.4902 +		int base	= (opcode >> 16) & 15;
 56.4903 +		u32 address = reg[base].I;
 56.4904 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4905 +		reg[base].I = address + value;
 56.4906 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4907 +	}
 56.4908 +	break;
 56.4909 +	case 0x740:
 56.4910 +	case 0x748:
 56.4911 +	{
 56.4912 +		// STRB Rd, [Rn, -Rm, LSL #]
 56.4913 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4914 +		int dest	= (opcode >> 12) & 15;
 56.4915 +		int base	= (opcode >> 16) & 15;
 56.4916 +		u32 address = reg[base].I - offset;
 56.4917 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4918 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4919 +	}
 56.4920 +	break;
 56.4921 +	case 0x742:
 56.4922 +	case 0x74a:
 56.4923 +	{
 56.4924 +		// STRB Rd, [Rn, -Rm, LSR #]
 56.4925 +		int shift	= (opcode >> 7) & 31;
 56.4926 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4927 +		int dest	= (opcode >> 12) & 15;
 56.4928 +		int base	= (opcode >> 16) & 15;
 56.4929 +		u32 address = reg[base].I - offset;
 56.4930 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4931 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4932 +	}
 56.4933 +	break;
 56.4934 +	case 0x744:
 56.4935 +	case 0x74c:
 56.4936 +	{
 56.4937 +		// STRB Rd, [Rn, -Rm, ASR #]
 56.4938 +		int shift = (opcode >> 7) & 31;
 56.4939 +		int offset;
 56.4940 +		if (shift)
 56.4941 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.4942 +		else if (reg[opcode & 15].I & 0x80000000)
 56.4943 +			offset = 0xFFFFFFFF;
 56.4944 +		else
 56.4945 +			offset = 0;
 56.4946 +		int dest	= (opcode >> 12) & 15;
 56.4947 +		int base	= (opcode >> 16) & 15;
 56.4948 +		u32 address = reg[base].I - offset;
 56.4949 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4950 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4951 +	}
 56.4952 +	break;
 56.4953 +	case 0x746:
 56.4954 +	case 0x74e:
 56.4955 +	{
 56.4956 +		// STRB Rd, [Rn, -Rm, ROR #]
 56.4957 +		int shift = (opcode >> 7) & 31;
 56.4958 +		u32 value = reg[opcode & 15].I;
 56.4959 +		if (shift)
 56.4960 +		{
 56.4961 +			ROR_VALUE;
 56.4962 +		}
 56.4963 +		else
 56.4964 +		{
 56.4965 +			RCR_VALUE;
 56.4966 +		}
 56.4967 +		int dest	= (opcode >> 12) & 15;
 56.4968 +		int base	= (opcode >> 16) & 15;
 56.4969 +		u32 address = reg[base].I - value;
 56.4970 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4971 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4972 +	}
 56.4973 +	break;
 56.4974 +	case 0x760:
 56.4975 +	case 0x768:
 56.4976 +	{
 56.4977 +		// STRB Rd, [Rn, -Rm, LSL #]!
 56.4978 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.4979 +		int dest	= (opcode >> 12) & 15;
 56.4980 +		int base	= (opcode >> 16) & 15;
 56.4981 +		u32 address = reg[base].I - offset;
 56.4982 +		reg[base].I = address;
 56.4983 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4984 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4985 +	}
 56.4986 +	break;
 56.4987 +	case 0x762:
 56.4988 +	case 0x76a:
 56.4989 +	{
 56.4990 +		// STRB Rd, [Rn, -Rm, LSR #]!
 56.4991 +		int shift	= (opcode >> 7) & 31;
 56.4992 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.4993 +		int dest	= (opcode >> 12) & 15;
 56.4994 +		int base	= (opcode >> 16) & 15;
 56.4995 +		u32 address = reg[base].I - offset;
 56.4996 +		reg[base].I = address;
 56.4997 +		CPUWriteByte(address, reg[dest].B.B0);
 56.4998 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.4999 +	}
 56.5000 +	break;
 56.5001 +	case 0x764:
 56.5002 +	case 0x76c:
 56.5003 +	{
 56.5004 +		// STRB Rd, [Rn, -Rm, ASR #]!
 56.5005 +		int shift = (opcode >> 7) & 31;
 56.5006 +		int offset;
 56.5007 +		if (shift)
 56.5008 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5009 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5010 +			offset = 0xFFFFFFFF;
 56.5011 +		else
 56.5012 +			offset = 0;
 56.5013 +		int dest	= (opcode >> 12) & 15;
 56.5014 +		int base	= (opcode >> 16) & 15;
 56.5015 +		u32 address = reg[base].I - offset;
 56.5016 +		reg[base].I = address;
 56.5017 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5018 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5019 +	}
 56.5020 +	break;
 56.5021 +	case 0x766:
 56.5022 +	case 0x76e:
 56.5023 +	{
 56.5024 +		// STRB Rd, [Rn, -Rm, ROR #]!
 56.5025 +		int shift = (opcode >> 7) & 31;
 56.5026 +		u32 value = reg[opcode & 15].I;
 56.5027 +		if (shift)
 56.5028 +		{
 56.5029 +			ROR_VALUE;
 56.5030 +		}
 56.5031 +		else
 56.5032 +		{
 56.5033 +			RCR_VALUE;
 56.5034 +		}
 56.5035 +		int dest	= (opcode >> 12) & 15;
 56.5036 +		int base	= (opcode >> 16) & 15;
 56.5037 +		u32 address = reg[base].I - value;
 56.5038 +		reg[base].I = address;
 56.5039 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5040 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5041 +	}
 56.5042 +	break;
 56.5043 +	case 0x7c0:
 56.5044 +	case 0x7c8:
 56.5045 +	{
 56.5046 +		// STRB Rd, [Rn, Rm, LSL #]
 56.5047 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.5048 +		int dest	= (opcode >> 12) & 15;
 56.5049 +		int base	= (opcode >> 16) & 15;
 56.5050 +		u32 address = reg[base].I + offset;
 56.5051 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5052 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5053 +	}
 56.5054 +	break;
 56.5055 +	case 0x7c2:
 56.5056 +	case 0x7ca:
 56.5057 +	{
 56.5058 +		// STRB Rd, [Rn, Rm, LSR #]
 56.5059 +		int shift	= (opcode >> 7) & 31;
 56.5060 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.5061 +		int dest	= (opcode >> 12) & 15;
 56.5062 +		int base	= (opcode >> 16) & 15;
 56.5063 +		u32 address = reg[base].I + offset;
 56.5064 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5065 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5066 +	}
 56.5067 +	break;
 56.5068 +	case 0x7c4:
 56.5069 +	case 0x7cc:
 56.5070 +	{
 56.5071 +		// STRB Rd, [Rn, Rm, ASR #]
 56.5072 +		int shift = (opcode >> 7) & 31;
 56.5073 +		int offset;
 56.5074 +		if (shift)
 56.5075 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5076 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5077 +			offset = 0xFFFFFFFF;
 56.5078 +		else
 56.5079 +			offset = 0;
 56.5080 +		int dest	= (opcode >> 12) & 15;
 56.5081 +		int base	= (opcode >> 16) & 15;
 56.5082 +		u32 address = reg[base].I + offset;
 56.5083 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5084 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5085 +	}
 56.5086 +	break;
 56.5087 +	case 0x7c6:
 56.5088 +	case 0x7ce:
 56.5089 +	{
 56.5090 +		// STRB Rd, [Rn, Rm, ROR #]
 56.5091 +		int shift = (opcode >> 7) & 31;
 56.5092 +		u32 value = reg[opcode & 15].I;
 56.5093 +		if (shift)
 56.5094 +		{
 56.5095 +			ROR_VALUE;
 56.5096 +		}
 56.5097 +		else
 56.5098 +		{
 56.5099 +			RCR_VALUE;
 56.5100 +		}
 56.5101 +		int dest	= (opcode >> 12) & 15;
 56.5102 +		int base	= (opcode >> 16) & 15;
 56.5103 +		u32 address = reg[base].I + value;
 56.5104 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5105 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5106 +	}
 56.5107 +	break;
 56.5108 +	case 0x7e0:
 56.5109 +	case 0x7e8:
 56.5110 +	{
 56.5111 +		// STRB Rd, [Rn, Rm, LSL #]!
 56.5112 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.5113 +		int dest	= (opcode >> 12) & 15;
 56.5114 +		int base	= (opcode >> 16) & 15;
 56.5115 +		u32 address = reg[base].I + offset;
 56.5116 +		reg[base].I = address;
 56.5117 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5118 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5119 +	}
 56.5120 +	break;
 56.5121 +	case 0x7e2:
 56.5122 +	case 0x7ea:
 56.5123 +	{
 56.5124 +		// STRB Rd, [Rn, Rm, LSR #]!
 56.5125 +		int shift	= (opcode >> 7) & 31;
 56.5126 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.5127 +		int dest	= (opcode >> 12) & 15;
 56.5128 +		int base	= (opcode >> 16) & 15;
 56.5129 +		u32 address = reg[base].I + offset;
 56.5130 +		reg[base].I = address;
 56.5131 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5132 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5133 +	}
 56.5134 +	break;
 56.5135 +	case 0x7e4:
 56.5136 +	case 0x7ec:
 56.5137 +	{
 56.5138 +		// STRB Rd, [Rn, Rm, ASR #]!
 56.5139 +		int shift = (opcode >> 7) & 31;
 56.5140 +		int offset;
 56.5141 +		if (shift)
 56.5142 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5143 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5144 +			offset = 0xFFFFFFFF;
 56.5145 +		else
 56.5146 +			offset = 0;
 56.5147 +		int dest	= (opcode >> 12) & 15;
 56.5148 +		int base	= (opcode >> 16) & 15;
 56.5149 +		u32 address = reg[base].I + offset;
 56.5150 +		reg[base].I = address;
 56.5151 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5152 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5153 +	}
 56.5154 +	break;
 56.5155 +	case 0x7e6:
 56.5156 +	case 0x7ee:
 56.5157 +	{
 56.5158 +		// STRB Rd, [Rn, Rm, ROR #]!
 56.5159 +		int shift = (opcode >> 7) & 31;
 56.5160 +		u32 value = reg[opcode & 15].I;
 56.5161 +		if (shift)
 56.5162 +		{
 56.5163 +			ROR_VALUE;
 56.5164 +		}
 56.5165 +		else
 56.5166 +		{
 56.5167 +			RCR_VALUE;
 56.5168 +		}
 56.5169 +		int dest	= (opcode >> 12) & 15;
 56.5170 +		int base	= (opcode >> 16) & 15;
 56.5171 +		u32 address = reg[base].I + value;
 56.5172 +		reg[base].I = address;
 56.5173 +		CPUWriteByte(address, reg[dest].B.B0);
 56.5174 +		clockTicks += 2 + CPUUpdateTicksAccess16(address);
 56.5175 +	}
 56.5176 +	break;
 56.5177 +	case 0x650:
 56.5178 +	case 0x658:
 56.5179 +	// T versions are the same
 56.5180 +	case 0x670:
 56.5181 +	case 0x678:
 56.5182 +	{
 56.5183 +		// LDRB Rd, [Rn], -Rm, LSL #
 56.5184 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.5185 +		int dest	= (opcode >> 12) & 15;
 56.5186 +		int base	= (opcode >> 16) & 15;
 56.5187 +		u32 address = reg[base].I;
 56.5188 +		reg[dest].I = CPUReadByte(address);
 56.5189 +		if (dest != base)
 56.5190 +			reg[base].I = address - offset;
 56.5191 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5192 +	}
 56.5193 +	break;
 56.5194 +	case 0x652:
 56.5195 +	case 0x65a:
 56.5196 +	// T versions are the same
 56.5197 +	case 0x672:
 56.5198 +	case 0x67a:
 56.5199 +	{
 56.5200 +		// LDRB Rd, [Rn], -Rm, LSR #
 56.5201 +		int shift	= (opcode >> 7) & 31;
 56.5202 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.5203 +		int dest	= (opcode >> 12) & 15;
 56.5204 +		int base	= (opcode >> 16) & 15;
 56.5205 +		u32 address = reg[base].I;
 56.5206 +		reg[dest].I = CPUReadByte(address);
 56.5207 +		if (dest != base)
 56.5208 +			reg[base].I = address - offset;
 56.5209 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5210 +	}
 56.5211 +	break;
 56.5212 +	case 0x654:
 56.5213 +	case 0x65c:
 56.5214 +	// T versions are the same
 56.5215 +	case 0x674:
 56.5216 +	case 0x67c:
 56.5217 +	{
 56.5218 +		// LDRB Rd, [Rn], -Rm, ASR #
 56.5219 +		int shift = (opcode >> 7) & 31;
 56.5220 +		int offset;
 56.5221 +		if (shift)
 56.5222 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5223 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5224 +			offset = 0xFFFFFFFF;
 56.5225 +		else
 56.5226 +			offset = 0;
 56.5227 +		int dest	= (opcode >> 12) & 15;
 56.5228 +		int base	= (opcode >> 16) & 15;
 56.5229 +		u32 address = reg[base].I;
 56.5230 +		reg[dest].I = CPUReadByte(address);
 56.5231 +		if (dest != base)
 56.5232 +			reg[base].I = address - offset;
 56.5233 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5234 +	}
 56.5235 +	break;
 56.5236 +	case 0x656:
 56.5237 +	case 0x65e:
 56.5238 +	// T versions are the same
 56.5239 +	case 0x676:
 56.5240 +	case 0x67e:
 56.5241 +	{
 56.5242 +		// LDRB Rd, [Rn], -Rm, ROR #
 56.5243 +		int shift = (opcode >> 7) & 31;
 56.5244 +		u32 value = reg[opcode & 15].I;
 56.5245 +		if (shift)
 56.5246 +		{
 56.5247 +			ROR_VALUE;
 56.5248 +		}
 56.5249 +		else
 56.5250 +		{
 56.5251 +			RCR_VALUE;
 56.5252 +		}
 56.5253 +		int dest	= (opcode >> 12) & 15;
 56.5254 +		int base	= (opcode >> 16) & 15;
 56.5255 +		u32 address = reg[base].I;
 56.5256 +		reg[dest].I = CPUReadByte(address);
 56.5257 +		if (dest != base)
 56.5258 +			reg[base].I = address - value;
 56.5259 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5260 +	}
 56.5261 +	break;
 56.5262 +	case 0x6d0:
 56.5263 +	case 0x6d8:
 56.5264 +	// T versions are the same
 56.5265 +	case 0x6f0:
 56.5266 +	case 0x6f8:
 56.5267 +	{
 56.5268 +		// LDRB Rd, [Rn], Rm, LSL #
 56.5269 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.5270 +		int dest	= (opcode >> 12) & 15;
 56.5271 +		int base	= (opcode >> 16) & 15;
 56.5272 +		u32 address = reg[base].I;
 56.5273 +		reg[dest].I = CPUReadByte(address);
 56.5274 +		if (dest != base)
 56.5275 +			reg[base].I = address + offset;
 56.5276 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5277 +	}
 56.5278 +	break;
 56.5279 +	case 0x6d2:
 56.5280 +	case 0x6da:
 56.5281 +	// T versions are the same
 56.5282 +	case 0x6f2:
 56.5283 +	case 0x6fa:
 56.5284 +	{
 56.5285 +		// LDRB Rd, [Rn], Rm, LSR #
 56.5286 +		int shift	= (opcode >> 7) & 31;
 56.5287 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.5288 +		int dest	= (opcode >> 12) & 15;
 56.5289 +		int base	= (opcode >> 16) & 15;
 56.5290 +		u32 address = reg[base].I;
 56.5291 +		reg[dest].I = CPUReadByte(address);
 56.5292 +		if (dest != base)
 56.5293 +			reg[base].I = address + offset;
 56.5294 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5295 +	}
 56.5296 +	break;
 56.5297 +	case 0x6d4:
 56.5298 +	case 0x6dc:
 56.5299 +	// T versions are the same
 56.5300 +	case 0x6f4:
 56.5301 +	case 0x6fc:
 56.5302 +	{
 56.5303 +		// LDRB Rd, [Rn], Rm, ASR #
 56.5304 +		int shift = (opcode >> 7) & 31;
 56.5305 +		int offset;
 56.5306 +		if (shift)
 56.5307 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5308 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5309 +			offset = 0xFFFFFFFF;
 56.5310 +		else
 56.5311 +			offset = 0;
 56.5312 +		int dest	= (opcode >> 12) & 15;
 56.5313 +		int base	= (opcode >> 16) & 15;
 56.5314 +		u32 address = reg[base].I;
 56.5315 +		reg[dest].I = CPUReadByte(address);
 56.5316 +		if (dest != base)
 56.5317 +			reg[base].I = address + offset;
 56.5318 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5319 +	}
 56.5320 +	break;
 56.5321 +	case 0x6d6:
 56.5322 +	case 0x6de:
 56.5323 +	// T versions are the same
 56.5324 +	case 0x6f6:
 56.5325 +	case 0x6fe:
 56.5326 +	{
 56.5327 +		// LDRB Rd, [Rn], Rm, ROR #
 56.5328 +		int shift = (opcode >> 7) & 31;
 56.5329 +		u32 value = reg[opcode & 15].I;
 56.5330 +		if (shift)
 56.5331 +		{
 56.5332 +			ROR_VALUE;
 56.5333 +		}
 56.5334 +		else
 56.5335 +		{
 56.5336 +			RCR_VALUE;
 56.5337 +		}
 56.5338 +		int dest	= (opcode >> 12) & 15;
 56.5339 +		int base	= (opcode >> 16) & 15;
 56.5340 +		u32 address = reg[base].I;
 56.5341 +		reg[dest].I = CPUReadByte(address);
 56.5342 +		if (dest != base)
 56.5343 +			reg[base].I = address + value;
 56.5344 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5345 +	}
 56.5346 +	break;
 56.5347 +	case 0x750:
 56.5348 +	case 0x758:
 56.5349 +	{
 56.5350 +		// LDRB Rd, [Rn, -Rm, LSL #]
 56.5351 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.5352 +		int dest	= (opcode >> 12) & 15;
 56.5353 +		int base	= (opcode >> 16) & 15;
 56.5354 +		u32 address = reg[base].I - offset;
 56.5355 +		reg[dest].I = CPUReadByte(address);
 56.5356 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5357 +	}
 56.5358 +	break;
 56.5359 +	case 0x752:
 56.5360 +	case 0x75a:
 56.5361 +	{
 56.5362 +		// LDRB Rd, [Rn, -Rm, LSR #]
 56.5363 +		int shift	= (opcode >> 7) & 31;
 56.5364 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.5365 +		int dest	= (opcode >> 12) & 15;
 56.5366 +		int base	= (opcode >> 16) & 15;
 56.5367 +		u32 address = reg[base].I - offset;
 56.5368 +		reg[dest].I = CPUReadByte(address);
 56.5369 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5370 +	}
 56.5371 +	break;
 56.5372 +	case 0x754:
 56.5373 +	case 0x75c:
 56.5374 +	{
 56.5375 +		// LDRB Rd, [Rn, -Rm, ASR #]
 56.5376 +		int shift = (opcode >> 7) & 31;
 56.5377 +		int offset;
 56.5378 +		if (shift)
 56.5379 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5380 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5381 +			offset = 0xFFFFFFFF;
 56.5382 +		else
 56.5383 +			offset = 0;
 56.5384 +		int dest	= (opcode >> 12) & 15;
 56.5385 +		int base	= (opcode >> 16) & 15;
 56.5386 +		u32 address = reg[base].I - offset;
 56.5387 +		reg[dest].I = CPUReadByte(address);
 56.5388 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5389 +	}
 56.5390 +	break;
 56.5391 +	case 0x756:
 56.5392 +	case 0x75e:
 56.5393 +	{
 56.5394 +		// LDRB Rd, [Rn, -Rm, ROR #]
 56.5395 +		int shift = (opcode >> 7) & 31;
 56.5396 +		u32 value = reg[opcode & 15].I;
 56.5397 +		if (shift)
 56.5398 +		{
 56.5399 +			ROR_VALUE;
 56.5400 +		}
 56.5401 +		else
 56.5402 +		{
 56.5403 +			RCR_VALUE;
 56.5404 +		}
 56.5405 +		int dest	= (opcode >> 12) & 15;
 56.5406 +		int base	= (opcode >> 16) & 15;
 56.5407 +		u32 address = reg[base].I - value;
 56.5408 +		reg[dest].I = CPUReadByte(address);
 56.5409 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5410 +	}
 56.5411 +	break;
 56.5412 +	case 0x770:
 56.5413 +	case 0x778:
 56.5414 +	{
 56.5415 +		// LDRB Rd, [Rn, -Rm, LSL #]!
 56.5416 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.5417 +		int dest	= (opcode >> 12) & 15;
 56.5418 +		int base	= (opcode >> 16) & 15;
 56.5419 +		u32 address = reg[base].I - offset;
 56.5420 +		reg[dest].I = CPUReadByte(address);
 56.5421 +		if (dest != base)
 56.5422 +			reg[base].I = address;
 56.5423 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5424 +	}
 56.5425 +	break;
 56.5426 +	case 0x772:
 56.5427 +	case 0x77a:
 56.5428 +	{
 56.5429 +		// LDRB Rd, [Rn, -Rm, LSR #]!
 56.5430 +		int shift	= (opcode >> 7) & 31;
 56.5431 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.5432 +		int dest	= (opcode >> 12) & 15;
 56.5433 +		int base	= (opcode >> 16) & 15;
 56.5434 +		u32 address = reg[base].I - offset;
 56.5435 +		reg[dest].I = CPUReadByte(address);
 56.5436 +		if (dest != base)
 56.5437 +			reg[base].I = address;
 56.5438 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5439 +	}
 56.5440 +	break;
 56.5441 +	case 0x774:
 56.5442 +	case 0x77c:
 56.5443 +	{
 56.5444 +		// LDRB Rd, [Rn, -Rm, ASR #]!
 56.5445 +		int shift = (opcode >> 7) & 31;
 56.5446 +		int offset;
 56.5447 +		if (shift)
 56.5448 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5449 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5450 +			offset = 0xFFFFFFFF;
 56.5451 +		else
 56.5452 +			offset = 0;
 56.5453 +		int dest	= (opcode >> 12) & 15;
 56.5454 +		int base	= (opcode >> 16) & 15;
 56.5455 +		u32 address = reg[base].I - offset;
 56.5456 +		reg[dest].I = CPUReadByte(address);
 56.5457 +		if (dest != base)
 56.5458 +			reg[base].I = address;
 56.5459 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5460 +	}
 56.5461 +	break;
 56.5462 +	case 0x776:
 56.5463 +	case 0x77e:
 56.5464 +	{
 56.5465 +		// LDRB Rd, [Rn, -Rm, ROR #]!
 56.5466 +		int shift = (opcode >> 7) & 31;
 56.5467 +		u32 value = reg[opcode & 15].I;
 56.5468 +		if (shift)
 56.5469 +		{
 56.5470 +			ROR_VALUE;
 56.5471 +		}
 56.5472 +		else
 56.5473 +		{
 56.5474 +			RCR_VALUE;
 56.5475 +		}
 56.5476 +		int dest	= (opcode >> 12) & 15;
 56.5477 +		int base	= (opcode >> 16) & 15;
 56.5478 +		u32 address = reg[base].I - value;
 56.5479 +		reg[dest].I = CPUReadByte(address);
 56.5480 +		if (dest != base)
 56.5481 +			reg[base].I = address;
 56.5482 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5483 +	}
 56.5484 +	break;
 56.5485 +	case 0x7d0:
 56.5486 +	case 0x7d8:
 56.5487 +	{
 56.5488 +		// LDRB Rd, [Rn, Rm, LSL #]
 56.5489 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.5490 +		int dest	= (opcode >> 12) & 15;
 56.5491 +		int base	= (opcode >> 16) & 15;
 56.5492 +		u32 address = reg[base].I + offset;
 56.5493 +		reg[dest].I = CPUReadByte(address);
 56.5494 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5495 +	}
 56.5496 +	break;
 56.5497 +	case 0x7d2:
 56.5498 +	case 0x7da:
 56.5499 +	{
 56.5500 +		// LDRB Rd, [Rn, Rm, LSR #]
 56.5501 +		int shift	= (opcode >> 7) & 31;
 56.5502 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.5503 +		int dest	= (opcode >> 12) & 15;
 56.5504 +		int base	= (opcode >> 16) & 15;
 56.5505 +		u32 address = reg[base].I + offset;
 56.5506 +		reg[dest].I = CPUReadByte(address);
 56.5507 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5508 +	}
 56.5509 +	break;
 56.5510 +	case 0x7d4:
 56.5511 +	case 0x7dc:
 56.5512 +	{
 56.5513 +		// LDRB Rd, [Rn, Rm, ASR #]
 56.5514 +		int shift = (opcode >> 7) & 31;
 56.5515 +		int offset;
 56.5516 +		if (shift)
 56.5517 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5518 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5519 +			offset = 0xFFFFFFFF;
 56.5520 +		else
 56.5521 +			offset = 0;
 56.5522 +		int dest	= (opcode >> 12) & 15;
 56.5523 +		int base	= (opcode >> 16) & 15;
 56.5524 +		u32 address = reg[base].I + offset;
 56.5525 +		reg[dest].I = CPUReadByte(address);
 56.5526 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5527 +	}
 56.5528 +	break;
 56.5529 +	case 0x7d6:
 56.5530 +	case 0x7de:
 56.5531 +	{
 56.5532 +		// LDRB Rd, [Rn, Rm, ROR #]
 56.5533 +		int shift = (opcode >> 7) & 31;
 56.5534 +		u32 value = reg[opcode & 15].I;
 56.5535 +		if (shift)
 56.5536 +		{
 56.5537 +			ROR_VALUE;
 56.5538 +		}
 56.5539 +		else
 56.5540 +		{
 56.5541 +			RCR_VALUE;
 56.5542 +		}
 56.5543 +		int dest	= (opcode >> 12) & 15;
 56.5544 +		int base	= (opcode >> 16) & 15;
 56.5545 +		u32 address = reg[base].I + value;
 56.5546 +		reg[dest].I = CPUReadByte(address);
 56.5547 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5548 +	}
 56.5549 +	break;
 56.5550 +	case 0x7f0:
 56.5551 +	case 0x7f8:
 56.5552 +	{
 56.5553 +		// LDRB Rd, [Rn, Rm, LSL #]!
 56.5554 +		int offset	= reg[opcode & 15].I << ((opcode >> 7) & 31);
 56.5555 +		int dest	= (opcode >> 12) & 15;
 56.5556 +		int base	= (opcode >> 16) & 15;
 56.5557 +		u32 address = reg[base].I + offset;
 56.5558 +		reg[dest].I = CPUReadByte(address);
 56.5559 +		if (dest != base)
 56.5560 +			reg[base].I = address;
 56.5561 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5562 +	}
 56.5563 +	break;
 56.5564 +	case 0x7f2:
 56.5565 +	case 0x7fa:
 56.5566 +	{
 56.5567 +		// LDRB Rd, [Rn, Rm, LSR #]!
 56.5568 +		int shift	= (opcode >> 7) & 31;
 56.5569 +		int offset	= shift ? reg[opcode & 15].I >> shift : 0;
 56.5570 +		int dest	= (opcode >> 12) & 15;
 56.5571 +		int base	= (opcode >> 16) & 15;
 56.5572 +		u32 address = reg[base].I + offset;
 56.5573 +		reg[dest].I = CPUReadByte(address);
 56.5574 +		if (dest != base)
 56.5575 +			reg[base].I = address;
 56.5576 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5577 +	}
 56.5578 +	break;
 56.5579 +	case 0x7f4:
 56.5580 +	case 0x7fc:
 56.5581 +	{
 56.5582 +		// LDRB Rd, [Rn, Rm, ASR #]!
 56.5583 +		int shift = (opcode >> 7) & 31;
 56.5584 +		int offset;
 56.5585 +		if (shift)
 56.5586 +			offset = (int)((s32)reg[opcode & 15].I >> shift);
 56.5587 +		else if (reg[opcode & 15].I & 0x80000000)
 56.5588 +			offset = 0xFFFFFFFF;
 56.5589 +		else
 56.5590 +			offset = 0;
 56.5591 +		int dest	= (opcode >> 12) & 15;
 56.5592 +		int base	= (opcode >> 16) & 15;
 56.5593 +		u32 address = reg[base].I + offset;
 56.5594 +		reg[dest].I = CPUReadByte(address);
 56.5595 +		if (dest != base)
 56.5596 +			reg[base].I = address;
 56.5597 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5598 +	}
 56.5599 +	break;
 56.5600 +	case 0x7f6:
 56.5601 +	case 0x7fe:
 56.5602 +	{
 56.5603 +		// LDRB Rd, [Rn, Rm, ROR #]!
 56.5604 +		int shift = (opcode >> 7) & 31;
 56.5605 +		u32 value = reg[opcode & 15].I;
 56.5606 +		if (shift)
 56.5607 +		{
 56.5608 +			ROR_VALUE;
 56.5609 +		}
 56.5610 +		else
 56.5611 +		{
 56.5612 +			RCR_VALUE;
 56.5613 +		}
 56.5614 +		int dest	= (opcode >> 12) & 15;
 56.5615 +		int base	= (opcode >> 16) & 15;
 56.5616 +		u32 address = reg[base].I + value;
 56.5617 +		reg[dest].I = CPUReadByte(address);
 56.5618 +		if (dest != base)
 56.5619 +			reg[base].I = address;
 56.5620 +		clockTicks += 3 + CPUUpdateTicksAccess16(address);
 56.5621 +	}
 56.5622 +	break;
 56.5623 +#define STMW_REG(val, num) \
 56.5624 +	if (opcode & (val)) { \
 56.5625 +		CPUWriteMemory(address, reg[(num)].I); \
 56.5626 +		if (!offset) { \
 56.5627 +			reg[base].I = temp; \
 56.5628 +			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
 56.5629 +			offset		= 1; \
 56.5630 +		} else { \
 56.5631 +			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
 56.5632 +		} \
 56.5633 +		address += 4; \
 56.5634 +	}
 56.5635 +#define STM_REG(val, num) \
 56.5636 +	if (opcode & (val)) { \
 56.5637 +		CPUWriteMemory(address, reg[(num)].I); \
 56.5638 +		if (!offset) { \
 56.5639 +			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
 56.5640 +			offset		= 1; \
 56.5641 +		} else { \
 56.5642 +			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
 56.5643 +		} \
 56.5644 +		address += 4; \
 56.5645 +	}
 56.5646 +
 56.5647 +		CASE_16(0x800)
 56.5648 +		// STMDA Rn, {Rlist}
 56.5649 +		{
 56.5650 +			int base = (opcode & 0x000F0000) >> 16;
 56.5651 +			u32 temp = reg[base].I -
 56.5652 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.5653 +			u32 address = (temp + 4) & 0xFFFFFFFC;
 56.5654 +			clockTicks += 2;
 56.5655 +			int offset = 0;
 56.5656 +			STM_REG(1, 0);
 56.5657 +			STM_REG(2, 1);
 56.5658 +			STM_REG(4, 2);
 56.5659 +			STM_REG(8, 3);
 56.5660 +			STM_REG(16, 4);
 56.5661 +			STM_REG(32, 5);
 56.5662 +			STM_REG(64, 6);
 56.5663 +			STM_REG(128, 7);
 56.5664 +			STM_REG(256, 8);
 56.5665 +			STM_REG(512, 9);
 56.5666 +			STM_REG(1024, 10);
 56.5667 +			STM_REG(2048, 11);
 56.5668 +			STM_REG(4096, 12);
 56.5669 +			STM_REG(8192, 13);
 56.5670 +			STM_REG(16384, 14);
 56.5671 +			if (opcode & 32768)
 56.5672 +			{
 56.5673 +				CPUWriteMemory(address, reg[15].I + 4);
 56.5674 +				if (!offset)
 56.5675 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.5676 +				else
 56.5677 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.5678 +			}
 56.5679 +		}
 56.5680 +		break;
 56.5681 +		CASE_16(0x820)
 56.5682 +		{
 56.5683 +			// STMDA Rn!, {Rlist}
 56.5684 +			int base = (opcode & 0x000F0000) >> 16;
 56.5685 +			u32 temp = reg[base].I -
 56.5686 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.5687 +			u32 address = (temp + 4) & 0xFFFFFFFC;
 56.5688 +			clockTicks += 2;
 56.5689 +			int offset = 0;
 56.5690 +
 56.5691 +			STMW_REG(1, 0);
 56.5692 +			STMW_REG(2, 1);
 56.5693 +			STMW_REG(4, 2);
 56.5694 +			STMW_REG(8, 3);
 56.5695 +			STMW_REG(16, 4);
 56.5696 +			STMW_REG(32, 5);
 56.5697 +			STMW_REG(64, 6);
 56.5698 +			STMW_REG(128, 7);
 56.5699 +			STMW_REG(256, 8);
 56.5700 +			STMW_REG(512, 9);
 56.5701 +			STMW_REG(1024, 10);
 56.5702 +			STMW_REG(2048, 11);
 56.5703 +			STMW_REG(4096, 12);
 56.5704 +			STMW_REG(8192, 13);
 56.5705 +			STMW_REG(16384, 14);
 56.5706 +			if (opcode & 32768)
 56.5707 +			{
 56.5708 +				CPUWriteMemory(address, reg[15].I + 4);
 56.5709 +				if (!offset)
 56.5710 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.5711 +				else
 56.5712 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.5713 +				reg[base].I = temp;
 56.5714 +			}
 56.5715 +		}
 56.5716 +		break;
 56.5717 +		CASE_16(0x840)
 56.5718 +		{
 56.5719 +			// STMDA Rn, {Rlist}^
 56.5720 +			int base = (opcode & 0x000F0000) >> 16;
 56.5721 +			u32 temp = reg[base].I -
 56.5722 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.5723 +			u32 address = (temp + 4) & 0xFFFFFFFC;
 56.5724 +			clockTicks += 2;
 56.5725 +			int offset = 0;
 56.5726 +
 56.5727 +			STM_REG(1, 0);
 56.5728 +			STM_REG(2, 1);
 56.5729 +			STM_REG(4, 2);
 56.5730 +			STM_REG(8, 3);
 56.5731 +			STM_REG(16, 4);
 56.5732 +			STM_REG(32, 5);
 56.5733 +			STM_REG(64, 6);
 56.5734 +			STM_REG(128, 7);
 56.5735 +
 56.5736 +			if (armMode == 0x11)
 56.5737 +			{
 56.5738 +				STM_REG(256, R8_FIQ);
 56.5739 +				STM_REG(512, R9_FIQ);
 56.5740 +				STM_REG(1024, R10_FIQ);
 56.5741 +				STM_REG(2048, R11_FIQ);
 56.5742 +				STM_REG(4096, R12_FIQ);
 56.5743 +			}
 56.5744 +			else
 56.5745 +			{
 56.5746 +				STM_REG(256, 8);
 56.5747 +				STM_REG(512, 9);
 56.5748 +				STM_REG(1024, 10);
 56.5749 +				STM_REG(2048, 11);
 56.5750 +				STM_REG(4096, 12);
 56.5751 +			}
 56.5752 +
 56.5753 +			if (armMode != 0x10 && armMode != 0x1f)
 56.5754 +			{
 56.5755 +				STM_REG(8192, R13_USR);
 56.5756 +				STM_REG(16384, R14_USR);
 56.5757 +			}
 56.5758 +			else
 56.5759 +			{
 56.5760 +				STM_REG(8192, 13);
 56.5761 +				STM_REG(16384, 14);
 56.5762 +			}
 56.5763 +
 56.5764 +			if (opcode & 32768)
 56.5765 +			{
 56.5766 +				CPUWriteMemory(address, reg[15].I + 4);
 56.5767 +				if (!offset)
 56.5768 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.5769 +				else
 56.5770 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.5771 +			}
 56.5772 +		}
 56.5773 +		break;
 56.5774 +		CASE_16(0x860)
 56.5775 +		{
 56.5776 +			// STMDA Rn!, {Rlist}^
 56.5777 +			int base = (opcode & 0x000F0000) >> 16;
 56.5778 +			u32 temp = reg[base].I -
 56.5779 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.5780 +			u32 address = (temp + 4) & 0xFFFFFFFC;
 56.5781 +			clockTicks += 2;
 56.5782 +			int offset = 0;
 56.5783 +
 56.5784 +			STMW_REG(1, 0);
 56.5785 +			STMW_REG(2, 1);
 56.5786 +			STMW_REG(4, 2);
 56.5787 +			STMW_REG(8, 3);
 56.5788 +			STMW_REG(16, 4);
 56.5789 +			STMW_REG(32, 5);
 56.5790 +			STMW_REG(64, 6);
 56.5791 +			STMW_REG(128, 7);
 56.5792 +
 56.5793 +			if (armMode == 0x11)
 56.5794 +			{
 56.5795 +				STMW_REG(256, R8_FIQ);
 56.5796 +				STMW_REG(512, R9_FIQ);
 56.5797 +				STMW_REG(1024, R10_FIQ);
 56.5798 +				STMW_REG(2048, R11_FIQ);
 56.5799 +				STMW_REG(4096, R12_FIQ);
 56.5800 +			}
 56.5801 +			else
 56.5802 +			{
 56.5803 +				STMW_REG(256, 8);
 56.5804 +				STMW_REG(512, 9);
 56.5805 +				STMW_REG(1024, 10);
 56.5806 +				STMW_REG(2048, 11);
 56.5807 +				STMW_REG(4096, 12);
 56.5808 +			}
 56.5809 +
 56.5810 +			if (armMode != 0x10 && armMode != 0x1f)
 56.5811 +			{
 56.5812 +				STMW_REG(8192, R13_USR);
 56.5813 +				STMW_REG(16384, R14_USR);
 56.5814 +			}
 56.5815 +			else
 56.5816 +			{
 56.5817 +				STMW_REG(8192, 13);
 56.5818 +				STMW_REG(16384, 14);
 56.5819 +			}
 56.5820 +
 56.5821 +			if (opcode & 32768)
 56.5822 +			{
 56.5823 +				CPUWriteMemory(address, reg[15].I + 4);
 56.5824 +				if (!offset)
 56.5825 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.5826 +				else
 56.5827 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.5828 +				reg[base].I = temp;
 56.5829 +			}
 56.5830 +		}
 56.5831 +		break;
 56.5832 +
 56.5833 +		CASE_16(0x880)
 56.5834 +		{
 56.5835 +			// STMIA Rn, {Rlist}
 56.5836 +			int base	= (opcode & 0x000F0000) >> 16;
 56.5837 +			u32 address = reg[base].I & 0xFFFFFFFC;
 56.5838 +			clockTicks += 2;
 56.5839 +			int offset = 0;
 56.5840 +			STM_REG(1, 0);
 56.5841 +			STM_REG(2, 1);
 56.5842 +			STM_REG(4, 2);
 56.5843 +			STM_REG(8, 3);
 56.5844 +			STM_REG(16, 4);
 56.5845 +			STM_REG(32, 5);
 56.5846 +			STM_REG(64, 6);
 56.5847 +			STM_REG(128, 7);
 56.5848 +			STM_REG(256, 8);
 56.5849 +			STM_REG(512, 9);
 56.5850 +			STM_REG(1024, 10);
 56.5851 +			STM_REG(2048, 11);
 56.5852 +			STM_REG(4096, 12);
 56.5853 +			STM_REG(8192, 13);
 56.5854 +			STM_REG(16384, 14);
 56.5855 +			if (opcode & 32768)
 56.5856 +			{
 56.5857 +				CPUWriteMemory(address, reg[15].I + 4);
 56.5858 +				if (!offset)
 56.5859 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.5860 +				else
 56.5861 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.5862 +			}
 56.5863 +		}
 56.5864 +		break;
 56.5865 +		CASE_16(0x8a0)
 56.5866 +		{
 56.5867 +			// STMIA Rn!, {Rlist}
 56.5868 +			int base	= (opcode & 0x000F0000) >> 16;
 56.5869 +			u32 address = reg[base].I & 0xFFFFFFFC;
 56.5870 +			clockTicks += 2;
 56.5871 +			int offset = 0;
 56.5872 +			u32 temp   = reg[base].I + 4 * (cpuBitsSet[opcode & 0xFF] +
 56.5873 +			                                cpuBitsSet[(opcode >> 8) & 255]);
 56.5874 +			STMW_REG(1, 0);
 56.5875 +			STMW_REG(2, 1);
 56.5876 +			STMW_REG(4, 2);
 56.5877 +			STMW_REG(8, 3);
 56.5878 +			STMW_REG(16, 4);
 56.5879 +			STMW_REG(32, 5);
 56.5880 +			STMW_REG(64, 6);
 56.5881 +			STMW_REG(128, 7);
 56.5882 +			STMW_REG(256, 8);
 56.5883 +			STMW_REG(512, 9);
 56.5884 +			STMW_REG(1024, 10);
 56.5885 +			STMW_REG(2048, 11);
 56.5886 +			STMW_REG(4096, 12);
 56.5887 +			STMW_REG(8192, 13);
 56.5888 +			STMW_REG(16384, 14);
 56.5889 +			if (opcode & 32768)
 56.5890 +			{
 56.5891 +				CPUWriteMemory(address, reg[15].I + 4);
 56.5892 +				if (!offset)
 56.5893 +				{
 56.5894 +					reg[base].I = temp;
 56.5895 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.5896 +				}
 56.5897 +				else
 56.5898 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.5899 +			}
 56.5900 +		}
 56.5901 +		break;
 56.5902 +		CASE_16(0x8c0)
 56.5903 +		{
 56.5904 +			// STMIA Rn, {Rlist}^
 56.5905 +			int base	= (opcode & 0x000F0000) >> 16;
 56.5906 +			u32 address = reg[base].I & 0xFFFFFFFC;
 56.5907 +			clockTicks += 2;
 56.5908 +			int offset = 0;
 56.5909 +			STM_REG(1, 0);
 56.5910 +			STM_REG(2, 1);
 56.5911 +			STM_REG(4, 2);
 56.5912 +			STM_REG(8, 3);
 56.5913 +			STM_REG(16, 4);
 56.5914 +			STM_REG(32, 5);
 56.5915 +			STM_REG(64, 6);
 56.5916 +			STM_REG(128, 7);
 56.5917 +			if (armMode == 0x11)
 56.5918 +			{
 56.5919 +				STM_REG(256, R8_FIQ);
 56.5920 +				STM_REG(512, R9_FIQ);
 56.5921 +				STM_REG(1024, R10_FIQ);
 56.5922 +				STM_REG(2048, R11_FIQ);
 56.5923 +				STM_REG(4096, R12_FIQ);
 56.5924 +			}
 56.5925 +			else
 56.5926 +			{
 56.5927 +				STM_REG(256, 8);
 56.5928 +				STM_REG(512, 9);
 56.5929 +				STM_REG(1024, 10);
 56.5930 +				STM_REG(2048, 11);
 56.5931 +				STM_REG(4096, 12);
 56.5932 +			}
 56.5933 +			if (armMode != 0x10 && armMode != 0x1f)
 56.5934 +			{
 56.5935 +				STM_REG(8192, R13_USR);
 56.5936 +				STM_REG(16384, R14_USR);
 56.5937 +			}
 56.5938 +			else
 56.5939 +			{
 56.5940 +				STM_REG(8192, 13);
 56.5941 +				STM_REG(16384, 14);
 56.5942 +			}
 56.5943 +			if (opcode & 32768)
 56.5944 +			{
 56.5945 +				CPUWriteMemory(address, reg[15].I + 4);
 56.5946 +				if (!offset)
 56.5947 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.5948 +				else
 56.5949 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.5950 +			}
 56.5951 +		}
 56.5952 +		break;
 56.5953 +		CASE_16(0x8e0)
 56.5954 +		{
 56.5955 +			// STMIA Rn!, {Rlist}^
 56.5956 +			int base	= (opcode & 0x000F0000) >> 16;
 56.5957 +			u32 address = reg[base].I & 0xFFFFFFFC;
 56.5958 +			clockTicks += 2;
 56.5959 +			int offset = 0;
 56.5960 +			u32 temp   = reg[base].I + 4 * (cpuBitsSet[opcode & 0xFF] +
 56.5961 +			                                cpuBitsSet[(opcode >> 8) & 255]);
 56.5962 +			STMW_REG(1, 0);
 56.5963 +			STMW_REG(2, 1);
 56.5964 +			STMW_REG(4, 2);
 56.5965 +			STMW_REG(8, 3);
 56.5966 +			STMW_REG(16, 4);
 56.5967 +			STMW_REG(32, 5);
 56.5968 +			STMW_REG(64, 6);
 56.5969 +			STMW_REG(128, 7);
 56.5970 +			if (armMode == 0x11)
 56.5971 +			{
 56.5972 +				STMW_REG(256, R8_FIQ);
 56.5973 +				STMW_REG(512, R9_FIQ);
 56.5974 +				STMW_REG(1024, R10_FIQ);
 56.5975 +				STMW_REG(2048, R11_FIQ);
 56.5976 +				STMW_REG(4096, R12_FIQ);
 56.5977 +			}
 56.5978 +			else
 56.5979 +			{
 56.5980 +				STMW_REG(256, 8);
 56.5981 +				STMW_REG(512, 9);
 56.5982 +				STMW_REG(1024, 10);
 56.5983 +				STMW_REG(2048, 11);
 56.5984 +				STMW_REG(4096, 12);
 56.5985 +			}
 56.5986 +			if (armMode != 0x10 && armMode != 0x1f)
 56.5987 +			{
 56.5988 +				STMW_REG(8192, R13_USR);
 56.5989 +				STMW_REG(16384, R14_USR);
 56.5990 +			}
 56.5991 +			else
 56.5992 +			{
 56.5993 +				STMW_REG(8192, 13);
 56.5994 +				STMW_REG(16384, 14);
 56.5995 +			}
 56.5996 +			if (opcode & 32768)
 56.5997 +			{
 56.5998 +				CPUWriteMemory(address, reg[15].I + 4);
 56.5999 +				if (!offset)
 56.6000 +				{
 56.6001 +					reg[base].I = temp;
 56.6002 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6003 +				}
 56.6004 +				else
 56.6005 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6006 +			}
 56.6007 +		}
 56.6008 +		break;
 56.6009 +
 56.6010 +		CASE_16(0x900)
 56.6011 +		{
 56.6012 +			// STMDB Rn, {Rlist}
 56.6013 +			int base = (opcode & 0x000F0000) >> 16;
 56.6014 +			u32 temp = reg[base].I -
 56.6015 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6016 +			u32 address = temp & 0xFFFFFFFC;
 56.6017 +			clockTicks += 2;
 56.6018 +			int offset = 0;
 56.6019 +			STM_REG(1, 0);
 56.6020 +			STM_REG(2, 1);
 56.6021 +			STM_REG(4, 2);
 56.6022 +			STM_REG(8, 3);
 56.6023 +			STM_REG(16, 4);
 56.6024 +			STM_REG(32, 5);
 56.6025 +			STM_REG(64, 6);
 56.6026 +			STM_REG(128, 7);
 56.6027 +			STM_REG(256, 8);
 56.6028 +			STM_REG(512, 9);
 56.6029 +			STM_REG(1024, 10);
 56.6030 +			STM_REG(2048, 11);
 56.6031 +			STM_REG(4096, 12);
 56.6032 +			STM_REG(8192, 13);
 56.6033 +			STM_REG(16384, 14);
 56.6034 +			if (opcode & 32768)
 56.6035 +			{
 56.6036 +				CPUWriteMemory(address, reg[15].I + 4);
 56.6037 +				if (!offset)
 56.6038 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6039 +				else
 56.6040 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6041 +			}
 56.6042 +		}
 56.6043 +		break;
 56.6044 +		CASE_16(0x920)
 56.6045 +		{
 56.6046 +			// STMDB Rn!, {Rlist}
 56.6047 +			int base = (opcode & 0x000F0000) >> 16;
 56.6048 +			u32 temp = reg[base].I -
 56.6049 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6050 +			u32 address = temp & 0xFFFFFFFC;
 56.6051 +			clockTicks += 2;
 56.6052 +			int offset = 0;
 56.6053 +
 56.6054 +			STMW_REG(1, 0);
 56.6055 +			STMW_REG(2, 1);
 56.6056 +			STMW_REG(4, 2);
 56.6057 +			STMW_REG(8, 3);
 56.6058 +			STMW_REG(16, 4);
 56.6059 +			STMW_REG(32, 5);
 56.6060 +			STMW_REG(64, 6);
 56.6061 +			STMW_REG(128, 7);
 56.6062 +			STMW_REG(256, 8);
 56.6063 +			STMW_REG(512, 9);
 56.6064 +			STMW_REG(1024, 10);
 56.6065 +			STMW_REG(2048, 11);
 56.6066 +			STMW_REG(4096, 12);
 56.6067 +			STMW_REG(8192, 13);
 56.6068 +			STMW_REG(16384, 14);
 56.6069 +			if (opcode & 32768)
 56.6070 +			{
 56.6071 +				CPUWriteMemory(address, reg[15].I + 4);
 56.6072 +				if (!offset)
 56.6073 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6074 +				else
 56.6075 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6076 +				reg[base].I = temp;
 56.6077 +			}
 56.6078 +		}
 56.6079 +		break;
 56.6080 +		CASE_16(0x940)
 56.6081 +		{
 56.6082 +			// STMDB Rn, {Rlist}^
 56.6083 +			int base = (opcode & 0x000F0000) >> 16;
 56.6084 +			u32 temp = reg[base].I -
 56.6085 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6086 +			u32 address = temp & 0xFFFFFFFC;
 56.6087 +			clockTicks += 2;
 56.6088 +			int offset = 0;
 56.6089 +
 56.6090 +			STM_REG(1, 0);
 56.6091 +			STM_REG(2, 1);
 56.6092 +			STM_REG(4, 2);
 56.6093 +			STM_REG(8, 3);
 56.6094 +			STM_REG(16, 4);
 56.6095 +			STM_REG(32, 5);
 56.6096 +			STM_REG(64, 6);
 56.6097 +			STM_REG(128, 7);
 56.6098 +
 56.6099 +			if (armMode == 0x11)
 56.6100 +			{
 56.6101 +				STM_REG(256, R8_FIQ);
 56.6102 +				STM_REG(512, R9_FIQ);
 56.6103 +				STM_REG(1024, R10_FIQ);
 56.6104 +				STM_REG(2048, R11_FIQ);
 56.6105 +				STM_REG(4096, R12_FIQ);
 56.6106 +			}
 56.6107 +			else
 56.6108 +			{
 56.6109 +				STM_REG(256, 8);
 56.6110 +				STM_REG(512, 9);
 56.6111 +				STM_REG(1024, 10);
 56.6112 +				STM_REG(2048, 11);
 56.6113 +				STM_REG(4096, 12);
 56.6114 +			}
 56.6115 +
 56.6116 +			if (armMode != 0x10 && armMode != 0x1f)
 56.6117 +			{
 56.6118 +				STM_REG(8192, R13_USR);
 56.6119 +				STM_REG(16384, R14_USR);
 56.6120 +			}
 56.6121 +			else
 56.6122 +			{
 56.6123 +				STM_REG(8192, 13);
 56.6124 +				STM_REG(16384, 14);
 56.6125 +			}
 56.6126 +
 56.6127 +			if (opcode & 32768)
 56.6128 +			{
 56.6129 +				CPUWriteMemory(address, reg[15].I + 4);
 56.6130 +				if (!offset)
 56.6131 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6132 +				else
 56.6133 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6134 +			}
 56.6135 +		}
 56.6136 +		break;
 56.6137 +		CASE_16(0x960)
 56.6138 +		{
 56.6139 +			// STMDB Rn!, {Rlist}^
 56.6140 +			int base = (opcode & 0x000F0000) >> 16;
 56.6141 +			u32 temp = reg[base].I -
 56.6142 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6143 +			u32 address = temp & 0xFFFFFFFC;
 56.6144 +			clockTicks += 2;
 56.6145 +			int offset = 0;
 56.6146 +
 56.6147 +			STMW_REG(1, 0);
 56.6148 +			STMW_REG(2, 1);
 56.6149 +			STMW_REG(4, 2);
 56.6150 +			STMW_REG(8, 3);
 56.6151 +			STMW_REG(16, 4);
 56.6152 +			STMW_REG(32, 5);
 56.6153 +			STMW_REG(64, 6);
 56.6154 +			STMW_REG(128, 7);
 56.6155 +
 56.6156 +			if (armMode == 0x11)
 56.6157 +			{
 56.6158 +				STMW_REG(256, R8_FIQ);
 56.6159 +				STMW_REG(512, R9_FIQ);
 56.6160 +				STMW_REG(1024, R10_FIQ);
 56.6161 +				STMW_REG(2048, R11_FIQ);
 56.6162 +				STMW_REG(4096, R12_FIQ);
 56.6163 +			}
 56.6164 +			else
 56.6165 +			{
 56.6166 +				STMW_REG(256, 8);
 56.6167 +				STMW_REG(512, 9);
 56.6168 +				STMW_REG(1024, 10);
 56.6169 +				STMW_REG(2048, 11);
 56.6170 +				STMW_REG(4096, 12);
 56.6171 +			}
 56.6172 +
 56.6173 +			if (armMode != 0x10 && armMode != 0x1f)
 56.6174 +			{
 56.6175 +				STMW_REG(8192, R13_USR);
 56.6176 +				STMW_REG(16384, R14_USR);
 56.6177 +			}
 56.6178 +			else
 56.6179 +			{
 56.6180 +				STMW_REG(8192, 13);
 56.6181 +				STMW_REG(16384, 14);
 56.6182 +			}
 56.6183 +
 56.6184 +			if (opcode & 32768)
 56.6185 +			{
 56.6186 +				CPUWriteMemory(address, reg[15].I + 4);
 56.6187 +				if (!offset)
 56.6188 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6189 +				else
 56.6190 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6191 +				reg[base].I = temp;
 56.6192 +			}
 56.6193 +		}
 56.6194 +		break;
 56.6195 +
 56.6196 +		CASE_16(0x980)
 56.6197 +		// STMIB Rn, {Rlist}
 56.6198 +		{
 56.6199 +			int base	= (opcode & 0x000F0000) >> 16;
 56.6200 +			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
 56.6201 +			clockTicks += 2;
 56.6202 +			int offset = 0;
 56.6203 +			STM_REG(1, 0);
 56.6204 +			STM_REG(2, 1);
 56.6205 +			STM_REG(4, 2);
 56.6206 +			STM_REG(8, 3);
 56.6207 +			STM_REG(16, 4);
 56.6208 +			STM_REG(32, 5);
 56.6209 +			STM_REG(64, 6);
 56.6210 +			STM_REG(128, 7);
 56.6211 +			STM_REG(256, 8);
 56.6212 +			STM_REG(512, 9);
 56.6213 +			STM_REG(1024, 10);
 56.6214 +			STM_REG(2048, 11);
 56.6215 +			STM_REG(4096, 12);
 56.6216 +			STM_REG(8192, 13);
 56.6217 +			STM_REG(16384, 14);
 56.6218 +			if (opcode & 32768)
 56.6219 +			{
 56.6220 +				CPUWriteMemory(address, reg[15].I + 4);
 56.6221 +				if (!offset)
 56.6222 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6223 +				else
 56.6224 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6225 +			}
 56.6226 +		}
 56.6227 +		break;
 56.6228 +		CASE_16(0x9a0)
 56.6229 +		{
 56.6230 +			// STMIB Rn!, {Rlist}
 56.6231 +			int base	= (opcode & 0x000F0000) >> 16;
 56.6232 +			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
 56.6233 +			clockTicks += 2;
 56.6234 +			int offset = 0;
 56.6235 +			u32 temp   = reg[base].I + 4 * (cpuBitsSet[opcode & 0xFF] +
 56.6236 +			                                cpuBitsSet[(opcode >> 8) & 255]);
 56.6237 +			STMW_REG(1, 0);
 56.6238 +			STMW_REG(2, 1);
 56.6239 +			STMW_REG(4, 2);
 56.6240 +			STMW_REG(8, 3);
 56.6241 +			STMW_REG(16, 4);
 56.6242 +			STMW_REG(32, 5);
 56.6243 +			STMW_REG(64, 6);
 56.6244 +			STMW_REG(128, 7);
 56.6245 +			STMW_REG(256, 8);
 56.6246 +			STMW_REG(512, 9);
 56.6247 +			STMW_REG(1024, 10);
 56.6248 +			STMW_REG(2048, 11);
 56.6249 +			STMW_REG(4096, 12);
 56.6250 +			STMW_REG(8192, 13);
 56.6251 +			STMW_REG(16384, 14);
 56.6252 +			if (opcode & 32768)
 56.6253 +			{
 56.6254 +				CPUWriteMemory(address, reg[15].I + 4);
 56.6255 +				if (!offset)
 56.6256 +				{
 56.6257 +					reg[base].I = temp;
 56.6258 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6259 +				}
 56.6260 +				else
 56.6261 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6262 +			}
 56.6263 +		}
 56.6264 +		break;
 56.6265 +		CASE_16(0x9c0)
 56.6266 +		{
 56.6267 +			// STMIB Rn, {Rlist}^
 56.6268 +			int base	= (opcode & 0x000F0000) >> 16;
 56.6269 +			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
 56.6270 +			clockTicks += 2;
 56.6271 +			int offset = 0;
 56.6272 +			STM_REG(1, 0);
 56.6273 +			STM_REG(2, 1);
 56.6274 +			STM_REG(4, 2);
 56.6275 +			STM_REG(8, 3);
 56.6276 +			STM_REG(16, 4);
 56.6277 +			STM_REG(32, 5);
 56.6278 +			STM_REG(64, 6);
 56.6279 +			STM_REG(128, 7);
 56.6280 +			if (armMode == 0x11)
 56.6281 +			{
 56.6282 +				STM_REG(256, R8_FIQ);
 56.6283 +				STM_REG(512, R9_FIQ);
 56.6284 +				STM_REG(1024, R10_FIQ);
 56.6285 +				STM_REG(2048, R11_FIQ);
 56.6286 +				STM_REG(4096, R12_FIQ);
 56.6287 +			}
 56.6288 +			else
 56.6289 +			{
 56.6290 +				STM_REG(256, 8);
 56.6291 +				STM_REG(512, 9);
 56.6292 +				STM_REG(1024, 10);
 56.6293 +				STM_REG(2048, 11);
 56.6294 +				STM_REG(4096, 12);
 56.6295 +			}
 56.6296 +			if (armMode != 0x10 && armMode != 0x1f)
 56.6297 +			{
 56.6298 +				STM_REG(8192, R13_USR);
 56.6299 +				STM_REG(16384, R14_USR);
 56.6300 +			}
 56.6301 +			else
 56.6302 +			{
 56.6303 +				STM_REG(8192, 13);
 56.6304 +				STM_REG(16384, 14);
 56.6305 +			}
 56.6306 +			if (opcode & 32768)
 56.6307 +			{
 56.6308 +				CPUWriteMemory(address, reg[15].I + 4);
 56.6309 +				if (!offset)
 56.6310 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6311 +				else
 56.6312 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6313 +			}
 56.6314 +		}
 56.6315 +		break;
 56.6316 +		CASE_16(0x9e0)
 56.6317 +		{
 56.6318 +			// STMIB Rn!, {Rlist}^
 56.6319 +			int base	= (opcode & 0x000F0000) >> 16;
 56.6320 +			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
 56.6321 +			clockTicks += 2;
 56.6322 +			int offset = 0;
 56.6323 +			u32 temp   = reg[base].I + 4 * (cpuBitsSet[opcode & 0xFF] +
 56.6324 +			                                cpuBitsSet[(opcode >> 8) & 255]);
 56.6325 +			STMW_REG(1, 0);
 56.6326 +			STMW_REG(2, 1);
 56.6327 +			STMW_REG(4, 2);
 56.6328 +			STMW_REG(8, 3);
 56.6329 +			STMW_REG(16, 4);
 56.6330 +			STMW_REG(32, 5);
 56.6331 +			STMW_REG(64, 6);
 56.6332 +			STMW_REG(128, 7);
 56.6333 +			if (armMode == 0x11)
 56.6334 +			{
 56.6335 +				STMW_REG(256, R8_FIQ);
 56.6336 +				STMW_REG(512, R9_FIQ);
 56.6337 +				STMW_REG(1024, R10_FIQ);
 56.6338 +				STMW_REG(2048, R11_FIQ);
 56.6339 +				STMW_REG(4096, R12_FIQ);
 56.6340 +			}
 56.6341 +			else
 56.6342 +			{
 56.6343 +				STMW_REG(256, 8);
 56.6344 +				STMW_REG(512, 9);
 56.6345 +				STMW_REG(1024, 10);
 56.6346 +				STMW_REG(2048, 11);
 56.6347 +				STMW_REG(4096, 12);
 56.6348 +			}
 56.6349 +			if (armMode != 0x10 && armMode != 0x1f)
 56.6350 +			{
 56.6351 +				STMW_REG(8192, R13_USR);
 56.6352 +				STMW_REG(16384, R14_USR);
 56.6353 +			}
 56.6354 +			else
 56.6355 +			{
 56.6356 +				STMW_REG(8192, 13);
 56.6357 +				STMW_REG(16384, 14);
 56.6358 +			}
 56.6359 +			if (opcode & 32768)
 56.6360 +			{
 56.6361 +				CPUWriteMemory(address, reg[15].I + 4);
 56.6362 +				if (!offset)
 56.6363 +				{
 56.6364 +					reg[base].I = temp;
 56.6365 +					clockTicks += 1 + CPUUpdateTicksAccess32(address);
 56.6366 +				}
 56.6367 +				else
 56.6368 +					clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
 56.6369 +			}
 56.6370 +		}
 56.6371 +		break;
 56.6372 +
 56.6373 +#define LDM_REG(val, num) \
 56.6374 +	if (opcode & (val)) { \
 56.6375 +		reg[(num)].I = CPUReadMemory(address); \
 56.6376 +		if (offset) \
 56.6377 +			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
 56.6378 +		else { \
 56.6379 +			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
 56.6380 +			offset		= 1; \
 56.6381 +		} \
 56.6382 +		address += 4; \
 56.6383 +	}
 56.6384 +
 56.6385 +		CASE_16(0x810)
 56.6386 +		{
 56.6387 +			// LDMDA Rn, {Rlist}
 56.6388 +			int base = (opcode & 0x000F0000) >> 16;
 56.6389 +			u32 temp = reg[base].I -
 56.6390 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6391 +			u32 address = (temp + 4) & 0xFFFFFFFC;
 56.6392 +			clockTicks += 2;
 56.6393 +			int offset = 0;
 56.6394 +			LDM_REG(1, 0);
 56.6395 +			LDM_REG(2, 1);
 56.6396 +			LDM_REG(4, 2);
 56.6397 +			LDM_REG(8, 3);
 56.6398 +			LDM_REG(16, 4);
 56.6399 +			LDM_REG(32, 5);
 56.6400 +			LDM_REG(64, 6);
 56.6401 +			LDM_REG(128, 7);
 56.6402 +			LDM_REG(256, 8);
 56.6403 +			LDM_REG(512, 9);
 56.6404 +			LDM_REG(1024, 10);
 56.6405 +			LDM_REG(2048, 11);
 56.6406 +			LDM_REG(4096, 12);
 56.6407 +			LDM_REG(8192, 13);
 56.6408 +			LDM_REG(16384, 14);
 56.6409 +			if (opcode & 32768)
 56.6410 +			{
 56.6411 +				reg[15].I = CPUReadMemory(address);
 56.6412 +				if (!offset)
 56.6413 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6414 +				else
 56.6415 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6416 +				armNextPC  = reg[15].I;
 56.6417 +				reg[15].I += 4;
 56.6418 +			}
 56.6419 +		}
 56.6420 +		break;
 56.6421 +		CASE_16(0x830)
 56.6422 +		{
 56.6423 +			// LDMDA Rn!, {Rlist}
 56.6424 +			int base = (opcode & 0x000F0000) >> 16;
 56.6425 +			u32 temp = reg[base].I -
 56.6426 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6427 +			u32 address = (temp + 4) & 0xFFFFFFFC;
 56.6428 +			clockTicks += 2;
 56.6429 +			int offset = 0;
 56.6430 +			LDM_REG(1, 0);
 56.6431 +			LDM_REG(2, 1);
 56.6432 +			LDM_REG(4, 2);
 56.6433 +			LDM_REG(8, 3);
 56.6434 +			LDM_REG(16, 4);
 56.6435 +			LDM_REG(32, 5);
 56.6436 +			LDM_REG(64, 6);
 56.6437 +			LDM_REG(128, 7);
 56.6438 +			LDM_REG(256, 8);
 56.6439 +			LDM_REG(512, 9);
 56.6440 +			LDM_REG(1024, 10);
 56.6441 +			LDM_REG(2048, 11);
 56.6442 +			LDM_REG(4096, 12);
 56.6443 +			LDM_REG(8192, 13);
 56.6444 +			LDM_REG(16384, 14);
 56.6445 +			if (opcode & 32768)
 56.6446 +			{
 56.6447 +				reg[15].I = CPUReadMemory(address);
 56.6448 +				if (!offset)
 56.6449 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6450 +				else
 56.6451 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6452 +				armNextPC  = reg[15].I;
 56.6453 +				reg[15].I += 4;
 56.6454 +			}
 56.6455 +			if (!(opcode & (1 << base)))
 56.6456 +				reg[base].I = temp;
 56.6457 +		}
 56.6458 +		break;
 56.6459 +		CASE_16(0x850)
 56.6460 +		{
 56.6461 +			// LDMDA Rn, {Rlist}^
 56.6462 +			int base = (opcode & 0x000F0000) >> 16;
 56.6463 +			u32 temp = reg[base].I -
 56.6464 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6465 +			u32 address = (temp + 4) & 0xFFFFFFFC;
 56.6466 +			clockTicks += 2;
 56.6467 +			int offset = 0;
 56.6468 +			if (opcode & 0x8000)
 56.6469 +			{
 56.6470 +				LDM_REG(1, 0);
 56.6471 +				LDM_REG(2, 1);
 56.6472 +				LDM_REG(4, 2);
 56.6473 +				LDM_REG(8, 3);
 56.6474 +				LDM_REG(16, 4);
 56.6475 +				LDM_REG(32, 5);
 56.6476 +				LDM_REG(64, 6);
 56.6477 +				LDM_REG(128, 7);
 56.6478 +				LDM_REG(256, 8);
 56.6479 +				LDM_REG(512, 9);
 56.6480 +				LDM_REG(1024, 10);
 56.6481 +				LDM_REG(2048, 11);
 56.6482 +				LDM_REG(4096, 12);
 56.6483 +				LDM_REG(8192, 13);
 56.6484 +				LDM_REG(16384, 14);
 56.6485 +
 56.6486 +				reg[15].I = CPUReadMemory(address);
 56.6487 +				if (!offset)
 56.6488 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6489 +				else
 56.6490 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6491 +
 56.6492 +				CPUSwitchMode(reg[17].I & 0x1f, false);
 56.6493 +				if (armState)
 56.6494 +				{
 56.6495 +					armNextPC = reg[15].I & 0xFFFFFFFC;
 56.6496 +					reg[15].I = armNextPC + 4;
 56.6497 +				}
 56.6498 +				else
 56.6499 +				{
 56.6500 +					armNextPC = reg[15].I & 0xFFFFFFFE;
 56.6501 +					reg[15].I = armNextPC + 2;
 56.6502 +				}
 56.6503 +			}
 56.6504 +			else
 56.6505 +			{
 56.6506 +				LDM_REG(1, 0);
 56.6507 +				LDM_REG(2, 1);
 56.6508 +				LDM_REG(4, 2);
 56.6509 +				LDM_REG(8, 3);
 56.6510 +				LDM_REG(16, 4);
 56.6511 +				LDM_REG(32, 5);
 56.6512 +				LDM_REG(64, 6);
 56.6513 +				LDM_REG(128, 7);
 56.6514 +
 56.6515 +				if (armMode == 0x11)
 56.6516 +				{
 56.6517 +					LDM_REG(256, R8_FIQ);
 56.6518 +					LDM_REG(512, R9_FIQ);
 56.6519 +					LDM_REG(1024, R10_FIQ);
 56.6520 +					LDM_REG(2048, R11_FIQ);
 56.6521 +					LDM_REG(4096, R12_FIQ);
 56.6522 +				}
 56.6523 +				else
 56.6524 +				{
 56.6525 +					LDM_REG(256, 8);
 56.6526 +					LDM_REG(512, 9);
 56.6527 +					LDM_REG(1024, 10);
 56.6528 +					LDM_REG(2048, 11);
 56.6529 +					LDM_REG(4096, 12);
 56.6530 +				}
 56.6531 +
 56.6532 +				if (armMode != 0x10 && armMode != 0x1f)
 56.6533 +				{
 56.6534 +					LDM_REG(8192, R13_USR);
 56.6535 +					LDM_REG(16384, R14_USR);
 56.6536 +				}
 56.6537 +				else
 56.6538 +				{
 56.6539 +					LDM_REG(8192, 13);
 56.6540 +					LDM_REG(16384, 14);
 56.6541 +				}
 56.6542 +			}
 56.6543 +		}
 56.6544 +		break;
 56.6545 +		CASE_16(0x870)
 56.6546 +		{
 56.6547 +			// LDMDA Rn!, {Rlist}^
 56.6548 +			int base = (opcode & 0x000F0000) >> 16;
 56.6549 +			u32 temp = reg[base].I -
 56.6550 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6551 +			u32 address = (temp + 4) & 0xFFFFFFFC;
 56.6552 +			clockTicks += 2;
 56.6553 +			int offset = 0;
 56.6554 +			if (opcode & 0x8000)
 56.6555 +			{
 56.6556 +				LDM_REG(1, 0);
 56.6557 +				LDM_REG(2, 1);
 56.6558 +				LDM_REG(4, 2);
 56.6559 +				LDM_REG(8, 3);
 56.6560 +				LDM_REG(16, 4);
 56.6561 +				LDM_REG(32, 5);
 56.6562 +				LDM_REG(64, 6);
 56.6563 +				LDM_REG(128, 7);
 56.6564 +				LDM_REG(256, 8);
 56.6565 +				LDM_REG(512, 9);
 56.6566 +				LDM_REG(1024, 10);
 56.6567 +				LDM_REG(2048, 11);
 56.6568 +				LDM_REG(4096, 12);
 56.6569 +				LDM_REG(8192, 13);
 56.6570 +				LDM_REG(16384, 14);
 56.6571 +
 56.6572 +				reg[15].I = CPUReadMemory(address);
 56.6573 +				if (!offset)
 56.6574 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6575 +				else
 56.6576 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6577 +
 56.6578 +				if (!(opcode & (1 << base)))
 56.6579 +					reg[base].I = temp;
 56.6580 +
 56.6581 +				CPUSwitchMode(reg[17].I & 0x1f, false);
 56.6582 +				if (armState)
 56.6583 +				{
 56.6584 +					armNextPC = reg[15].I & 0xFFFFFFFC;
 56.6585 +					reg[15].I = armNextPC + 4;
 56.6586 +				}
 56.6587 +				else
 56.6588 +				{
 56.6589 +					armNextPC = reg[15].I & 0xFFFFFFFE;
 56.6590 +					reg[15].I = armNextPC + 2;
 56.6591 +				}
 56.6592 +			}
 56.6593 +			else
 56.6594 +			{
 56.6595 +				LDM_REG(1, 0);
 56.6596 +				LDM_REG(2, 1);
 56.6597 +				LDM_REG(4, 2);
 56.6598 +				LDM_REG(8, 3);
 56.6599 +				LDM_REG(16, 4);
 56.6600 +				LDM_REG(32, 5);
 56.6601 +				LDM_REG(64, 6);
 56.6602 +				LDM_REG(128, 7);
 56.6603 +
 56.6604 +				if (armMode == 0x11)
 56.6605 +				{
 56.6606 +					LDM_REG(256, R8_FIQ);
 56.6607 +					LDM_REG(512, R9_FIQ);
 56.6608 +					LDM_REG(1024, R10_FIQ);
 56.6609 +					LDM_REG(2048, R11_FIQ);
 56.6610 +					LDM_REG(4096, R12_FIQ);
 56.6611 +				}
 56.6612 +				else
 56.6613 +				{
 56.6614 +					LDM_REG(256, 8);
 56.6615 +					LDM_REG(512, 9);
 56.6616 +					LDM_REG(1024, 10);
 56.6617 +					LDM_REG(2048, 11);
 56.6618 +					LDM_REG(4096, 12);
 56.6619 +				}
 56.6620 +
 56.6621 +				if (armMode != 0x10 && armMode != 0x1f)
 56.6622 +				{
 56.6623 +					LDM_REG(8192, R13_USR);
 56.6624 +					LDM_REG(16384, R14_USR);
 56.6625 +				}
 56.6626 +				else
 56.6627 +				{
 56.6628 +					LDM_REG(8192, 13);
 56.6629 +					LDM_REG(16384, 14);
 56.6630 +				}
 56.6631 +
 56.6632 +				if (!(opcode & (1 << base)))
 56.6633 +					reg[base].I = temp;
 56.6634 +			}
 56.6635 +		}
 56.6636 +		break;
 56.6637 +
 56.6638 +		CASE_16(0x890)
 56.6639 +		{
 56.6640 +			// LDMIA Rn, {Rlist}
 56.6641 +			int base	= (opcode & 0x000F0000) >> 16;
 56.6642 +			u32 address = reg[base].I & 0xFFFFFFFC;
 56.6643 +			clockTicks += 2;
 56.6644 +			int offset = 0;
 56.6645 +			LDM_REG(1, 0);
 56.6646 +			LDM_REG(2, 1);
 56.6647 +			LDM_REG(4, 2);
 56.6648 +			LDM_REG(8, 3);
 56.6649 +			LDM_REG(16, 4);
 56.6650 +			LDM_REG(32, 5);
 56.6651 +			LDM_REG(64, 6);
 56.6652 +			LDM_REG(128, 7);
 56.6653 +			LDM_REG(256, 8);
 56.6654 +			LDM_REG(512, 9);
 56.6655 +			LDM_REG(1024, 10);
 56.6656 +			LDM_REG(2048, 11);
 56.6657 +			LDM_REG(4096, 12);
 56.6658 +			LDM_REG(8192, 13);
 56.6659 +			LDM_REG(16384, 14);
 56.6660 +			if (opcode & 32768)
 56.6661 +			{
 56.6662 +				reg[15].I = CPUReadMemory(address);
 56.6663 +				if (!offset)
 56.6664 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6665 +				else
 56.6666 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6667 +				armNextPC  = reg[15].I;
 56.6668 +				reg[15].I += 4;
 56.6669 +			}
 56.6670 +		}
 56.6671 +		break;
 56.6672 +		CASE_16(0x8b0)
 56.6673 +		{
 56.6674 +			// LDMIA Rn!, {Rlist}
 56.6675 +			int base = (opcode & 0x000F0000) >> 16;
 56.6676 +			u32 temp = reg[base].I +
 56.6677 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6678 +			u32 address = reg[base].I & 0xFFFFFFFC;
 56.6679 +			clockTicks += 2;
 56.6680 +			int offset = 0;
 56.6681 +			LDM_REG(1, 0);
 56.6682 +			LDM_REG(2, 1);
 56.6683 +			LDM_REG(4, 2);
 56.6684 +			LDM_REG(8, 3);
 56.6685 +			LDM_REG(16, 4);
 56.6686 +			LDM_REG(32, 5);
 56.6687 +			LDM_REG(64, 6);
 56.6688 +			LDM_REG(128, 7);
 56.6689 +			LDM_REG(256, 8);
 56.6690 +			LDM_REG(512, 9);
 56.6691 +			LDM_REG(1024, 10);
 56.6692 +			LDM_REG(2048, 11);
 56.6693 +			LDM_REG(4096, 12);
 56.6694 +			LDM_REG(8192, 13);
 56.6695 +			LDM_REG(16384, 14);
 56.6696 +			if (opcode & 32768)
 56.6697 +			{
 56.6698 +				reg[15].I = CPUReadMemory(address);
 56.6699 +				if (!offset)
 56.6700 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6701 +				else
 56.6702 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6703 +				armNextPC  = reg[15].I;
 56.6704 +				reg[15].I += 4;
 56.6705 +			}
 56.6706 +			if (!(opcode & (1 << base)))
 56.6707 +				reg[base].I = temp;
 56.6708 +		}
 56.6709 +		break;
 56.6710 +		CASE_16(0x8d0)
 56.6711 +		{
 56.6712 +			// LDMIA Rn, {Rlist}^
 56.6713 +			int base	= (opcode & 0x000F0000) >> 16;
 56.6714 +			u32 address = reg[base].I & 0xFFFFFFFC;
 56.6715 +			clockTicks += 2;
 56.6716 +			int offset = 0;
 56.6717 +			if (opcode & 0x8000)
 56.6718 +			{
 56.6719 +				LDM_REG(1, 0);
 56.6720 +				LDM_REG(2, 1);
 56.6721 +				LDM_REG(4, 2);
 56.6722 +				LDM_REG(8, 3);
 56.6723 +				LDM_REG(16, 4);
 56.6724 +				LDM_REG(32, 5);
 56.6725 +				LDM_REG(64, 6);
 56.6726 +				LDM_REG(128, 7);
 56.6727 +				LDM_REG(256, 8);
 56.6728 +				LDM_REG(512, 9);
 56.6729 +				LDM_REG(1024, 10);
 56.6730 +				LDM_REG(2048, 11);
 56.6731 +				LDM_REG(4096, 12);
 56.6732 +				LDM_REG(8192, 13);
 56.6733 +				LDM_REG(16384, 14);
 56.6734 +
 56.6735 +				reg[15].I = CPUReadMemory(address);
 56.6736 +				if (!offset)
 56.6737 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6738 +				else
 56.6739 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6740 +
 56.6741 +				CPUSwitchMode(reg[17].I & 0x1f, false);
 56.6742 +				if (armState)
 56.6743 +				{
 56.6744 +					armNextPC = reg[15].I & 0xFFFFFFFC;
 56.6745 +					reg[15].I = armNextPC + 4;
 56.6746 +				}
 56.6747 +				else
 56.6748 +				{
 56.6749 +					armNextPC = reg[15].I & 0xFFFFFFFE;
 56.6750 +					reg[15].I = armNextPC + 2;
 56.6751 +				}
 56.6752 +			}
 56.6753 +			else
 56.6754 +			{
 56.6755 +				LDM_REG(1, 0);
 56.6756 +				LDM_REG(2, 1);
 56.6757 +				LDM_REG(4, 2);
 56.6758 +				LDM_REG(8, 3);
 56.6759 +				LDM_REG(16, 4);
 56.6760 +				LDM_REG(32, 5);
 56.6761 +				LDM_REG(64, 6);
 56.6762 +				LDM_REG(128, 7);
 56.6763 +
 56.6764 +				if (armMode == 0x11)
 56.6765 +				{
 56.6766 +					LDM_REG(256, R8_FIQ);
 56.6767 +					LDM_REG(512, R9_FIQ);
 56.6768 +					LDM_REG(1024, R10_FIQ);
 56.6769 +					LDM_REG(2048, R11_FIQ);
 56.6770 +					LDM_REG(4096, R12_FIQ);
 56.6771 +				}
 56.6772 +				else
 56.6773 +				{
 56.6774 +					LDM_REG(256, 8);
 56.6775 +					LDM_REG(512, 9);
 56.6776 +					LDM_REG(1024, 10);
 56.6777 +					LDM_REG(2048, 11);
 56.6778 +					LDM_REG(4096, 12);
 56.6779 +				}
 56.6780 +
 56.6781 +				if (armMode != 0x10 && armMode != 0x1f)
 56.6782 +				{
 56.6783 +					LDM_REG(8192, R13_USR);
 56.6784 +					LDM_REG(16384, R14_USR);
 56.6785 +				}
 56.6786 +				else
 56.6787 +				{
 56.6788 +					LDM_REG(8192, 13);
 56.6789 +					LDM_REG(16384, 14);
 56.6790 +				}
 56.6791 +			}
 56.6792 +		}
 56.6793 +		break;
 56.6794 +		CASE_16(0x8f0)
 56.6795 +		{
 56.6796 +			// LDMIA Rn!, {Rlist}^
 56.6797 +			int base = (opcode & 0x000F0000) >> 16;
 56.6798 +			u32 temp = reg[base].I +
 56.6799 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6800 +			u32 address = reg[base].I & 0xFFFFFFFC;
 56.6801 +			clockTicks += 2;
 56.6802 +			int offset = 0;
 56.6803 +			if (opcode & 0x8000)
 56.6804 +			{
 56.6805 +				LDM_REG(1, 0);
 56.6806 +				LDM_REG(2, 1);
 56.6807 +				LDM_REG(4, 2);
 56.6808 +				LDM_REG(8, 3);
 56.6809 +				LDM_REG(16, 4);
 56.6810 +				LDM_REG(32, 5);
 56.6811 +				LDM_REG(64, 6);
 56.6812 +				LDM_REG(128, 7);
 56.6813 +				LDM_REG(256, 8);
 56.6814 +				LDM_REG(512, 9);
 56.6815 +				LDM_REG(1024, 10);
 56.6816 +				LDM_REG(2048, 11);
 56.6817 +				LDM_REG(4096, 12);
 56.6818 +				LDM_REG(8192, 13);
 56.6819 +				LDM_REG(16384, 14);
 56.6820 +
 56.6821 +				reg[15].I = CPUReadMemory(address);
 56.6822 +				if (!offset)
 56.6823 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6824 +				else
 56.6825 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6826 +
 56.6827 +				if (!(opcode & (1 << base)))
 56.6828 +					reg[base].I = temp;
 56.6829 +
 56.6830 +				CPUSwitchMode(reg[17].I & 0x1f, false);
 56.6831 +				if (armState)
 56.6832 +				{
 56.6833 +					armNextPC = reg[15].I & 0xFFFFFFFC;
 56.6834 +					reg[15].I = armNextPC + 4;
 56.6835 +				}
 56.6836 +				else
 56.6837 +				{
 56.6838 +					armNextPC = reg[15].I & 0xFFFFFFFE;
 56.6839 +					reg[15].I = armNextPC + 2;
 56.6840 +				}
 56.6841 +			}
 56.6842 +			else
 56.6843 +			{
 56.6844 +				LDM_REG(1, 0);
 56.6845 +				LDM_REG(2, 1);
 56.6846 +				LDM_REG(4, 2);
 56.6847 +				LDM_REG(8, 3);
 56.6848 +				LDM_REG(16, 4);
 56.6849 +				LDM_REG(32, 5);
 56.6850 +				LDM_REG(64, 6);
 56.6851 +				LDM_REG(128, 7);
 56.6852 +
 56.6853 +				if (armMode == 0x11)
 56.6854 +				{
 56.6855 +					LDM_REG(256, R8_FIQ);
 56.6856 +					LDM_REG(512, R9_FIQ);
 56.6857 +					LDM_REG(1024, R10_FIQ);
 56.6858 +					LDM_REG(2048, R11_FIQ);
 56.6859 +					LDM_REG(4096, R12_FIQ);
 56.6860 +				}
 56.6861 +				else
 56.6862 +				{
 56.6863 +					LDM_REG(256, 8);
 56.6864 +					LDM_REG(512, 9);
 56.6865 +					LDM_REG(1024, 10);
 56.6866 +					LDM_REG(2048, 11);
 56.6867 +					LDM_REG(4096, 12);
 56.6868 +				}
 56.6869 +
 56.6870 +				if (armMode != 0x10 && armMode != 0x1f)
 56.6871 +				{
 56.6872 +					LDM_REG(8192, R13_USR);
 56.6873 +					LDM_REG(16384, R14_USR);
 56.6874 +				}
 56.6875 +				else
 56.6876 +				{
 56.6877 +					LDM_REG(8192, 13);
 56.6878 +					LDM_REG(16384, 14);
 56.6879 +				}
 56.6880 +
 56.6881 +				if (!(opcode & (1 << base)))
 56.6882 +					reg[base].I = temp;
 56.6883 +			}
 56.6884 +		}
 56.6885 +		break;
 56.6886 +
 56.6887 +		CASE_16(0x910)
 56.6888 +		{
 56.6889 +			// LDMDB Rn, {Rlist}
 56.6890 +			int base = (opcode & 0x000F0000) >> 16;
 56.6891 +			u32 temp = reg[base].I -
 56.6892 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6893 +			u32 address = temp & 0xFFFFFFFC;
 56.6894 +			clockTicks += 2;
 56.6895 +			int offset = 0;
 56.6896 +			LDM_REG(1, 0);
 56.6897 +			LDM_REG(2, 1);
 56.6898 +			LDM_REG(4, 2);
 56.6899 +			LDM_REG(8, 3);
 56.6900 +			LDM_REG(16, 4);
 56.6901 +			LDM_REG(32, 5);
 56.6902 +			LDM_REG(64, 6);
 56.6903 +			LDM_REG(128, 7);
 56.6904 +			LDM_REG(256, 8);
 56.6905 +			LDM_REG(512, 9);
 56.6906 +			LDM_REG(1024, 10);
 56.6907 +			LDM_REG(2048, 11);
 56.6908 +			LDM_REG(4096, 12);
 56.6909 +			LDM_REG(8192, 13);
 56.6910 +			LDM_REG(16384, 14);
 56.6911 +			if (opcode & 32768)
 56.6912 +			{
 56.6913 +				reg[15].I = CPUReadMemory(address);
 56.6914 +				if (!offset)
 56.6915 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6916 +				else
 56.6917 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6918 +				armNextPC  = reg[15].I;
 56.6919 +				reg[15].I += 4;
 56.6920 +			}
 56.6921 +		}
 56.6922 +		break;
 56.6923 +		CASE_16(0x930)
 56.6924 +		{
 56.6925 +			// LDMDB Rn!, {Rlist}
 56.6926 +			int base = (opcode & 0x000F0000) >> 16;
 56.6927 +			u32 temp = reg[base].I -
 56.6928 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6929 +			u32 address = temp & 0xFFFFFFFC;
 56.6930 +			clockTicks += 2;
 56.6931 +			int offset = 0;
 56.6932 +			LDM_REG(1, 0);
 56.6933 +			LDM_REG(2, 1);
 56.6934 +			LDM_REG(4, 2);
 56.6935 +			LDM_REG(8, 3);
 56.6936 +			LDM_REG(16, 4);
 56.6937 +			LDM_REG(32, 5);
 56.6938 +			LDM_REG(64, 6);
 56.6939 +			LDM_REG(128, 7);
 56.6940 +			LDM_REG(256, 8);
 56.6941 +			LDM_REG(512, 9);
 56.6942 +			LDM_REG(1024, 10);
 56.6943 +			LDM_REG(2048, 11);
 56.6944 +			LDM_REG(4096, 12);
 56.6945 +			LDM_REG(8192, 13);
 56.6946 +			LDM_REG(16384, 14);
 56.6947 +			if (opcode & 32768)
 56.6948 +			{
 56.6949 +				reg[15].I = CPUReadMemory(address);
 56.6950 +				if (!offset)
 56.6951 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6952 +				else
 56.6953 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6954 +				armNextPC  = reg[15].I;
 56.6955 +				reg[15].I += 4;
 56.6956 +			}
 56.6957 +			if (!(opcode & (1 << base)))
 56.6958 +				reg[base].I = temp;
 56.6959 +		}
 56.6960 +		break;
 56.6961 +		CASE_16(0x950)
 56.6962 +		{
 56.6963 +			// LDMDB Rn, {Rlist}^
 56.6964 +			int base = (opcode & 0x000F0000) >> 16;
 56.6965 +			u32 temp = reg[base].I -
 56.6966 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.6967 +			u32 address = temp & 0xFFFFFFFC;
 56.6968 +			clockTicks += 2;
 56.6969 +			int offset = 0;
 56.6970 +			if (opcode & 0x8000)
 56.6971 +			{
 56.6972 +				LDM_REG(1, 0);
 56.6973 +				LDM_REG(2, 1);
 56.6974 +				LDM_REG(4, 2);
 56.6975 +				LDM_REG(8, 3);
 56.6976 +				LDM_REG(16, 4);
 56.6977 +				LDM_REG(32, 5);
 56.6978 +				LDM_REG(64, 6);
 56.6979 +				LDM_REG(128, 7);
 56.6980 +				LDM_REG(256, 8);
 56.6981 +				LDM_REG(512, 9);
 56.6982 +				LDM_REG(1024, 10);
 56.6983 +				LDM_REG(2048, 11);
 56.6984 +				LDM_REG(4096, 12);
 56.6985 +				LDM_REG(8192, 13);
 56.6986 +				LDM_REG(16384, 14);
 56.6987 +
 56.6988 +				reg[15].I = CPUReadMemory(address);
 56.6989 +				if (!offset)
 56.6990 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.6991 +				else
 56.6992 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.6993 +
 56.6994 +				CPUSwitchMode(reg[17].I & 0x1f, false);
 56.6995 +				if (armState)
 56.6996 +				{
 56.6997 +					armNextPC = reg[15].I & 0xFFFFFFFC;
 56.6998 +					reg[15].I = armNextPC + 4;
 56.6999 +				}
 56.7000 +				else
 56.7001 +				{
 56.7002 +					armNextPC = reg[15].I & 0xFFFFFFFE;
 56.7003 +					reg[15].I = armNextPC + 2;
 56.7004 +				}
 56.7005 +			}
 56.7006 +			else
 56.7007 +			{
 56.7008 +				LDM_REG(1, 0);
 56.7009 +				LDM_REG(2, 1);
 56.7010 +				LDM_REG(4, 2);
 56.7011 +				LDM_REG(8, 3);
 56.7012 +				LDM_REG(16, 4);
 56.7013 +				LDM_REG(32, 5);
 56.7014 +				LDM_REG(64, 6);
 56.7015 +				LDM_REG(128, 7);
 56.7016 +
 56.7017 +				if (armMode == 0x11)
 56.7018 +				{
 56.7019 +					LDM_REG(256, R8_FIQ);
 56.7020 +					LDM_REG(512, R9_FIQ);
 56.7021 +					LDM_REG(1024, R10_FIQ);
 56.7022 +					LDM_REG(2048, R11_FIQ);
 56.7023 +					LDM_REG(4096, R12_FIQ);
 56.7024 +				}
 56.7025 +				else
 56.7026 +				{
 56.7027 +					LDM_REG(256, 8);
 56.7028 +					LDM_REG(512, 9);
 56.7029 +					LDM_REG(1024, 10);
 56.7030 +					LDM_REG(2048, 11);
 56.7031 +					LDM_REG(4096, 12);
 56.7032 +				}
 56.7033 +
 56.7034 +				if (armMode != 0x10 && armMode != 0x1f)
 56.7035 +				{
 56.7036 +					LDM_REG(8192, R13_USR);
 56.7037 +					LDM_REG(16384, R14_USR);
 56.7038 +				}
 56.7039 +				else
 56.7040 +				{
 56.7041 +					LDM_REG(8192, 13);
 56.7042 +					LDM_REG(16384, 14);
 56.7043 +				}
 56.7044 +			}
 56.7045 +		}
 56.7046 +		break;
 56.7047 +		CASE_16(0x970)
 56.7048 +		{
 56.7049 +			// LDMDB Rn!, {Rlist}^
 56.7050 +			int base = (opcode & 0x000F0000) >> 16;
 56.7051 +			u32 temp = reg[base].I -
 56.7052 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.7053 +			u32 address = temp & 0xFFFFFFFC;
 56.7054 +			clockTicks += 2;
 56.7055 +			int offset = 0;
 56.7056 +			if (opcode & 0x8000)
 56.7057 +			{
 56.7058 +				LDM_REG(1, 0);
 56.7059 +				LDM_REG(2, 1);
 56.7060 +				LDM_REG(4, 2);
 56.7061 +				LDM_REG(8, 3);
 56.7062 +				LDM_REG(16, 4);
 56.7063 +				LDM_REG(32, 5);
 56.7064 +				LDM_REG(64, 6);
 56.7065 +				LDM_REG(128, 7);
 56.7066 +				LDM_REG(256, 8);
 56.7067 +				LDM_REG(512, 9);
 56.7068 +				LDM_REG(1024, 10);
 56.7069 +				LDM_REG(2048, 11);
 56.7070 +				LDM_REG(4096, 12);
 56.7071 +				LDM_REG(8192, 13);
 56.7072 +				LDM_REG(16384, 14);
 56.7073 +
 56.7074 +				reg[15].I = CPUReadMemory(address);
 56.7075 +				if (!offset)
 56.7076 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.7077 +				else
 56.7078 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.7079 +
 56.7080 +				if (!(opcode & (1 << base)))
 56.7081 +					reg[base].I = temp;
 56.7082 +
 56.7083 +				CPUSwitchMode(reg[17].I & 0x1f, false);
 56.7084 +				if (armState)
 56.7085 +				{
 56.7086 +					armNextPC = reg[15].I & 0xFFFFFFFC;
 56.7087 +					reg[15].I = armNextPC + 4;
 56.7088 +				}
 56.7089 +				else
 56.7090 +				{
 56.7091 +					armNextPC = reg[15].I & 0xFFFFFFFE;
 56.7092 +					reg[15].I = armNextPC + 2;
 56.7093 +				}
 56.7094 +			}
 56.7095 +			else
 56.7096 +			{
 56.7097 +				LDM_REG(1, 0);
 56.7098 +				LDM_REG(2, 1);
 56.7099 +				LDM_REG(4, 2);
 56.7100 +				LDM_REG(8, 3);
 56.7101 +				LDM_REG(16, 4);
 56.7102 +				LDM_REG(32, 5);
 56.7103 +				LDM_REG(64, 6);
 56.7104 +				LDM_REG(128, 7);
 56.7105 +
 56.7106 +				if (armMode == 0x11)
 56.7107 +				{
 56.7108 +					LDM_REG(256, R8_FIQ);
 56.7109 +					LDM_REG(512, R9_FIQ);
 56.7110 +					LDM_REG(1024, R10_FIQ);
 56.7111 +					LDM_REG(2048, R11_FIQ);
 56.7112 +					LDM_REG(4096, R12_FIQ);
 56.7113 +				}
 56.7114 +				else
 56.7115 +				{
 56.7116 +					LDM_REG(256, 8);
 56.7117 +					LDM_REG(512, 9);
 56.7118 +					LDM_REG(1024, 10);
 56.7119 +					LDM_REG(2048, 11);
 56.7120 +					LDM_REG(4096, 12);
 56.7121 +				}
 56.7122 +
 56.7123 +				if (armMode != 0x10 && armMode != 0x1f)
 56.7124 +				{
 56.7125 +					LDM_REG(8192, R13_USR);
 56.7126 +					LDM_REG(16384, R14_USR);
 56.7127 +				}
 56.7128 +				else
 56.7129 +				{
 56.7130 +					LDM_REG(8192, 13);
 56.7131 +					LDM_REG(16384, 14);
 56.7132 +				}
 56.7133 +
 56.7134 +				if (!(opcode & (1 << base)))
 56.7135 +					reg[base].I = temp;
 56.7136 +			}
 56.7137 +		}
 56.7138 +		break;
 56.7139 +
 56.7140 +		CASE_16(0x990)
 56.7141 +		{
 56.7142 +			// LDMIB Rn, {Rlist}
 56.7143 +			int base	= (opcode & 0x000F0000) >> 16;
 56.7144 +			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
 56.7145 +			clockTicks += 2;
 56.7146 +			int offset = 0;
 56.7147 +			LDM_REG(1, 0);
 56.7148 +			LDM_REG(2, 1);
 56.7149 +			LDM_REG(4, 2);
 56.7150 +			LDM_REG(8, 3);
 56.7151 +			LDM_REG(16, 4);
 56.7152 +			LDM_REG(32, 5);
 56.7153 +			LDM_REG(64, 6);
 56.7154 +			LDM_REG(128, 7);
 56.7155 +			LDM_REG(256, 8);
 56.7156 +			LDM_REG(512, 9);
 56.7157 +			LDM_REG(1024, 10);
 56.7158 +			LDM_REG(2048, 11);
 56.7159 +			LDM_REG(4096, 12);
 56.7160 +			LDM_REG(8192, 13);
 56.7161 +			LDM_REG(16384, 14);
 56.7162 +			if (opcode & 32768)
 56.7163 +			{
 56.7164 +				reg[15].I = CPUReadMemory(address);
 56.7165 +				if (!offset)
 56.7166 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.7167 +				else
 56.7168 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.7169 +				armNextPC  = reg[15].I;
 56.7170 +				reg[15].I += 4;
 56.7171 +			}
 56.7172 +		}
 56.7173 +		break;
 56.7174 +		CASE_16(0x9b0)
 56.7175 +		{
 56.7176 +			// LDMIB Rn!, {Rlist}
 56.7177 +			int base = (opcode & 0x000F0000) >> 16;
 56.7178 +			u32 temp = reg[base].I +
 56.7179 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.7180 +			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
 56.7181 +			clockTicks += 2;
 56.7182 +			int offset = 0;
 56.7183 +			LDM_REG(1, 0);
 56.7184 +			LDM_REG(2, 1);
 56.7185 +			LDM_REG(4, 2);
 56.7186 +			LDM_REG(8, 3);
 56.7187 +			LDM_REG(16, 4);
 56.7188 +			LDM_REG(32, 5);
 56.7189 +			LDM_REG(64, 6);
 56.7190 +			LDM_REG(128, 7);
 56.7191 +			LDM_REG(256, 8);
 56.7192 +			LDM_REG(512, 9);
 56.7193 +			LDM_REG(1024, 10);
 56.7194 +			LDM_REG(2048, 11);
 56.7195 +			LDM_REG(4096, 12);
 56.7196 +			LDM_REG(8192, 13);
 56.7197 +			LDM_REG(16384, 14);
 56.7198 +			if (opcode & 32768)
 56.7199 +			{
 56.7200 +				reg[15].I = CPUReadMemory(address);
 56.7201 +				if (!offset)
 56.7202 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.7203 +				else
 56.7204 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.7205 +				armNextPC  = reg[15].I;
 56.7206 +				reg[15].I += 4;
 56.7207 +			}
 56.7208 +			if (!(opcode & (1 << base)))
 56.7209 +				reg[base].I = temp;
 56.7210 +		}
 56.7211 +		break;
 56.7212 +		CASE_16(0x9d0)
 56.7213 +		{
 56.7214 +			// LDMIB Rn, {Rlist}^
 56.7215 +			int base	= (opcode & 0x000F0000) >> 16;
 56.7216 +			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
 56.7217 +			clockTicks += 2;
 56.7218 +			int offset = 0;
 56.7219 +			if (opcode & 0x8000)
 56.7220 +			{
 56.7221 +				LDM_REG(1, 0);
 56.7222 +				LDM_REG(2, 1);
 56.7223 +				LDM_REG(4, 2);
 56.7224 +				LDM_REG(8, 3);
 56.7225 +				LDM_REG(16, 4);
 56.7226 +				LDM_REG(32, 5);
 56.7227 +				LDM_REG(64, 6);
 56.7228 +				LDM_REG(128, 7);
 56.7229 +				LDM_REG(256, 8);
 56.7230 +				LDM_REG(512, 9);
 56.7231 +				LDM_REG(1024, 10);
 56.7232 +				LDM_REG(2048, 11);
 56.7233 +				LDM_REG(4096, 12);
 56.7234 +				LDM_REG(8192, 13);
 56.7235 +				LDM_REG(16384, 14);
 56.7236 +
 56.7237 +				reg[15].I = CPUReadMemory(address);
 56.7238 +				if (!offset)
 56.7239 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.7240 +				else
 56.7241 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.7242 +
 56.7243 +				CPUSwitchMode(reg[17].I & 0x1f, false);
 56.7244 +				if (armState)
 56.7245 +				{
 56.7246 +					armNextPC = reg[15].I & 0xFFFFFFFC;
 56.7247 +					reg[15].I = armNextPC + 4;
 56.7248 +				}
 56.7249 +				else
 56.7250 +				{
 56.7251 +					armNextPC = reg[15].I & 0xFFFFFFFE;
 56.7252 +					reg[15].I = armNextPC + 2;
 56.7253 +				}
 56.7254 +			}
 56.7255 +			else
 56.7256 +			{
 56.7257 +				LDM_REG(1, 0);
 56.7258 +				LDM_REG(2, 1);
 56.7259 +				LDM_REG(4, 2);
 56.7260 +				LDM_REG(8, 3);
 56.7261 +				LDM_REG(16, 4);
 56.7262 +				LDM_REG(32, 5);
 56.7263 +				LDM_REG(64, 6);
 56.7264 +				LDM_REG(128, 7);
 56.7265 +
 56.7266 +				if (armMode == 0x11)
 56.7267 +				{
 56.7268 +					LDM_REG(256, R8_FIQ);
 56.7269 +					LDM_REG(512, R9_FIQ);
 56.7270 +					LDM_REG(1024, R10_FIQ);
 56.7271 +					LDM_REG(2048, R11_FIQ);
 56.7272 +					LDM_REG(4096, R12_FIQ);
 56.7273 +				}
 56.7274 +				else
 56.7275 +				{
 56.7276 +					LDM_REG(256, 8);
 56.7277 +					LDM_REG(512, 9);
 56.7278 +					LDM_REG(1024, 10);
 56.7279 +					LDM_REG(2048, 11);
 56.7280 +					LDM_REG(4096, 12);
 56.7281 +				}
 56.7282 +
 56.7283 +				if (armMode != 0x10 && armMode != 0x1f)
 56.7284 +				{
 56.7285 +					LDM_REG(8192, R13_USR);
 56.7286 +					LDM_REG(16384, R14_USR);
 56.7287 +				}
 56.7288 +				else
 56.7289 +				{
 56.7290 +					LDM_REG(8192, 13);
 56.7291 +					LDM_REG(16384, 14);
 56.7292 +				}
 56.7293 +			}
 56.7294 +		}
 56.7295 +		break;
 56.7296 +		CASE_16(0x9f0)
 56.7297 +		{
 56.7298 +			// LDMIB Rn!, {Rlist}^
 56.7299 +			int base = (opcode & 0x000F0000) >> 16;
 56.7300 +			u32 temp = reg[base].I +
 56.7301 +			           4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
 56.7302 +			u32 address = (reg[base].I + 4) & 0xFFFFFFFC;
 56.7303 +			clockTicks += 2;
 56.7304 +			int offset = 0;
 56.7305 +			if (opcode & 0x8000)
 56.7306 +			{
 56.7307 +				LDM_REG(1, 0);
 56.7308 +				LDM_REG(2, 1);
 56.7309 +				LDM_REG(4, 2);
 56.7310 +				LDM_REG(8, 3);
 56.7311 +				LDM_REG(16, 4);
 56.7312 +				LDM_REG(32, 5);
 56.7313 +				LDM_REG(64, 6);
 56.7314 +				LDM_REG(128, 7);
 56.7315 +				LDM_REG(256, 8);
 56.7316 +				LDM_REG(512, 9);
 56.7317 +				LDM_REG(1024, 10);
 56.7318 +				LDM_REG(2048, 11);
 56.7319 +				LDM_REG(4096, 12);
 56.7320 +				LDM_REG(8192, 13);
 56.7321 +				LDM_REG(16384, 14);
 56.7322 +
 56.7323 +				reg[15].I = CPUReadMemory(address);
 56.7324 +				if (!offset)
 56.7325 +					clockTicks += 2 + CPUUpdateTicksAccess32(address);
 56.7326 +				else
 56.7327 +					clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
 56.7328 +
 56.7329 +				if (!(opcode & (1 << base)))
 56.7330 +					reg[base].I = temp;
 56.7331 +
 56.7332 +				CPUSwitchMode(reg[17].I & 0x1f, false);
 56.7333 +				if (armState)
 56.7334 +				{
 56.7335 +					armNextPC = reg[15].I & 0xFFFFFFFC;
 56.7336 +					reg[15].I = armNextPC + 4;
 56.7337 +				}
 56.7338 +				else
 56.7339 +				{
 56.7340 +					armNextPC = reg[15].I & 0xFFFFFFFE;
 56.7341 +					reg[15].I = armNextPC + 2;
 56.7342 +				}
 56.7343 +			}
 56.7344 +			else
 56.7345 +			{
 56.7346 +				LDM_REG(1, 0);
 56.7347 +				LDM_REG(2, 1);
 56.7348 +				LDM_REG(4, 2);
 56.7349 +				LDM_REG(8, 3);
 56.7350 +				LDM_REG(16, 4);
 56.7351 +				LDM_REG(32, 5);
 56.7352 +				LDM_REG(64, 6);
 56.7353 +				LDM_REG(128, 7);
 56.7354 +
 56.7355 +				if (armMode == 0x11)
 56.7356 +				{
 56.7357 +					LDM_REG(256, R8_FIQ);
 56.7358 +					LDM_REG(512, R9_FIQ);
 56.7359 +					LDM_REG(1024, R10_FIQ);
 56.7360 +					LDM_REG(2048, R11_FIQ);
 56.7361 +					LDM_REG(4096, R12_FIQ);
 56.7362 +				}
 56.7363 +				else
 56.7364 +				{
 56.7365 +					LDM_REG(256, 8);
 56.7366 +					LDM_REG(512, 9);
 56.7367 +					LDM_REG(1024, 10);
 56.7368 +					LDM_REG(2048, 11);
 56.7369 +					LDM_REG(4096, 12);
 56.7370 +				}
 56.7371 +
 56.7372 +				if (armMode != 0x10 && armMode != 0x1f)
 56.7373 +				{
 56.7374 +					LDM_REG(8192, R13_USR);
 56.7375 +					LDM_REG(16384, R14_USR);
 56.7376 +				}
 56.7377 +				else
 56.7378 +				{
 56.7379 +					LDM_REG(8192, 13);
 56.7380 +					LDM_REG(16384, 14);
 56.7381 +				}
 56.7382 +
 56.7383 +				if (!(opcode & (1 << base)))
 56.7384 +					reg[base].I = temp;
 56.7385 +			}
 56.7386 +		}
 56.7387 +		break;
 56.7388 +		CASE_256(0xa00)
 56.7389 +		{
 56.7390 +			// B <offset>
 56.7391 +			clockTicks += 3;
 56.7392 +			int offset = opcode & 0x00FFFFFF;
 56.7393 +			if (offset & 0x00800000)
 56.7394 +			{
 56.7395 +				offset |= 0xFF000000;
 56.7396 +			}
 56.7397 +			offset	 <<= 2;
 56.7398 +			reg[15].I += offset;
 56.7399 +			armNextPC  = reg[15].I;
 56.7400 +			reg[15].I += 4;
 56.7401 +		}
 56.7402 +		break;
 56.7403 +		CASE_256(0xb00)
 56.7404 +		{
 56.7405 +			// BL <offset>
 56.7406 +			clockTicks += 3;
 56.7407 +			int offset = opcode & 0x00FFFFFF;
 56.7408 +			if (offset & 0x00800000)
 56.7409 +			{
 56.7410 +				offset |= 0xFF000000;
 56.7411 +			}
 56.7412 +			offset	 <<= 2;
 56.7413 +			reg[14].I  = reg[15].I - 4;
 56.7414 +			reg[15].I += offset;
 56.7415 +			armNextPC  = reg[15].I;
 56.7416 +			reg[15].I += 4;
 56.7417 +		}
 56.7418 +		break;
 56.7419 +		CASE_256(0xf00)
 56.7420 +		// SWI <comment>
 56.7421 +		clockTicks += 3;
 56.7422 +		CPUSoftwareInterrupt(opcode & 0x00FFFFFF);
 56.7423 +		break;
 56.7424 +#ifdef GP_SUPPORT
 56.7425 +	case 0xe11:
 56.7426 +	case 0xe13:
 56.7427 +	case 0xe15:
 56.7428 +	case 0xe17:
 56.7429 +	case 0xe19:
 56.7430 +	case 0xe1b:
 56.7431 +	case 0xe1d:
 56.7432 +	case 0xe1f:
 56.7433 +		// MRC
 56.7434 +		break;
 56.7435 +	case 0xe01:
 56.7436 +	case 0xe03:
 56.7437 +	case 0xe05:
 56.7438 +	case 0xe07:
 56.7439 +	case 0xe09:
 56.7440 +	case 0xe0b:
 56.7441 +	case 0xe0d:
 56.7442 +	case 0xe0f:
 56.7443 +		// MRC
 56.7444 +		break;
 56.7445 +#endif
 56.7446 +	default:
 56.7447 +#ifdef GBA_LOGGING
 56.7448 +		if (systemVerbose & VERBOSE_UNDEFINED)
 56.7449 +			log("Undefined ARM instruction %08x at %08x\n", opcode,
 56.7450 +			    armNextPC - 4);
 56.7451 +#endif
 56.7452 +		CPUUndefinedException();
 56.7453 +		break;
 56.7454 +		// END
 56.7455 +	}
 56.7456 +}
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/src/gba/armdis.cpp	Sun Mar 04 14:33:52 2012 -0600
    57.3 @@ -0,0 +1,774 @@
    57.4 +/************************************************************************/
    57.5 +/* Arm/Thumb command set disassembler                                   */
    57.6 +/************************************************************************/
    57.7 +#include <cstdio>
    57.8 +
    57.9 +#include "GBAGlobals.h"
   57.10 +#include "armdis.h"
   57.11 +#include "elf.h"
   57.12 +
   57.13 +struct Opcodes
   57.14 +{
   57.15 +	u32 mask;
   57.16 +	u32 cval;
   57.17 +	const char *mnemonic;
   57.18 +};
   57.19 +
   57.20 +const char hdig[] = "0123456789abcdef";
   57.21 +
   57.22 +const char *decVals[16] = {
   57.23 +	"0", "1",  "2",	 "3",  "4",	 "5",  "6", "7", "8",
   57.24 +	"9", "10", "11", "12", "13", "14", "15"
   57.25 +};
   57.26 +
   57.27 +const char *regs[16] = {
   57.28 +	"r0", "r1", "r2",  "r3",  "r4",	 "r5", "r6", "r7",
   57.29 +	"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"
   57.30 +};
   57.31 +
   57.32 +const char *conditions[16] = {
   57.33 +	"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
   57.34 +	"hi", "ls", "ge", "lt", "gt", "le", "",	  "nv"
   57.35 +};
   57.36 +
   57.37 +const char *shifts[5] = {
   57.38 +	"lsl", "lsr", "asr", "ror", "rrx"
   57.39 +};
   57.40 +
   57.41 +const char *armMultLoadStore[12] = {
   57.42 +	// non-stack
   57.43 +	"da", "ia", "db", "ib",
   57.44 +	// stack store
   57.45 +	"ed", "ea", "fd", "fa",
   57.46 +	// stack load
   57.47 +	"fa", "fd", "ea", "ed"
   57.48 +};
   57.49 +
   57.50 +const Opcodes thumbOpcodes[] = {
   57.51 +	// Format 1
   57.52 +	{ 0xf800, 0x0000, "lsl %r0, %r3, %o"	  },
   57.53 +	{ 0xf800, 0x0800, "lsr %r0, %r3, %o"	  },
   57.54 +	{ 0xf800, 0x1000, "asr %r0, %r3, %o"	  },
   57.55 +	// Format 2
   57.56 +	{ 0xfe00, 0x1800, "add %r0, %r3, %r6"	  },
   57.57 +	{ 0xfe00, 0x1a00, "sub %r0, %r3, %r6"	  },
   57.58 +	{ 0xfe00, 0x1c00, "add %r0, %r3, %i"	  },
   57.59 +	{ 0xfe00, 0x1e00, "sub %r0, %r3, %i"	  },
   57.60 +	// Format 3
   57.61 +	{ 0xf800, 0x2000, "mov %r8, %O"			  },
   57.62 +	{ 0xf800, 0x2800, "cmp %r8, %O"			  },
   57.63 +	{ 0xf800, 0x3000, "add %r8, %O"			  },
   57.64 +	{ 0xf800, 0x3800, "sub %r8, %O"			  },
   57.65 +	// Format 4
   57.66 +	{ 0xffc0, 0x4000, "and %r0, %r3"		  },
   57.67 +	{ 0xffc0, 0x4040, "eor %r0, %r3"		  },
   57.68 +	{ 0xffc0, 0x4080, "lsl %r0, %r3"		  },
   57.69 +	{ 0xffc0, 0x40c0, "lsr %r0, %r3"		  },
   57.70 +	{ 0xffc0, 0x4100, "asr %r0, %r3"		  },
   57.71 +	{ 0xffc0, 0x4140, "adc %r0, %r3"		  },
   57.72 +	{ 0xffc0, 0x4180, "sbc %r0, %r3"		  },
   57.73 +	{ 0xffc0, 0x41c0, "ror %r0, %r3"		  },
   57.74 +	{ 0xffc0, 0x4200, "tst %r0, %r3"		  },
   57.75 +	{ 0xffc0, 0x4240, "neg %r0, %r3"		  },
   57.76 +	{ 0xffc0, 0x4280, "cmp %r0, %r3"		  },
   57.77 +	{ 0xffc0, 0x42c0, "cmn %r0, %r3"		  },
   57.78 +	{ 0xffc0, 0x4300, "orr %r0, %r3"		  },
   57.79 +	{ 0xffc0, 0x4340, "mul %r0, %r3"		  },
   57.80 +	{ 0xffc0, 0x4380, "bic %r0, %r3"		  },
   57.81 +	{ 0xffc0, 0x43c0, "mvn %r0, %r3"		  },
   57.82 +	// Format 5
   57.83 +	{ 0xff80, 0x4700, "bx %h36"				  },
   57.84 +	{ 0xfcc0, 0x4400, "[ ??? ]"				  },
   57.85 +	{ 0xff00, 0x4400, "add %h07, %h36"		  },
   57.86 +	{ 0xff00, 0x4500, "cmp %h07, %h36"		  },
   57.87 +	{ 0xff00, 0x4600, "mov %h07, %h36"		  },
   57.88 +	// Format 6
   57.89 +	{ 0xf800, 0x4800, "ldr %r8, [%I] (=%J)"	  },
   57.90 +	// Format 7
   57.91 +	{ 0xfa00, 0x5000, "str%b %r0, [%r3, %r6]" },
   57.92 +	{ 0xfa00, 0x5800, "ldr%b %r0, [%r3, %r6]" },
   57.93 +	// Format 8
   57.94 +	{ 0xfe00, 0x5200, "strh %r0, [%r3, %r6]"  },
   57.95 +	{ 0xfe00, 0x5600, "ldsb %r0, [%r3, %r6]"  },
   57.96 +	{ 0xfe00, 0x5a00, "ldrh %r0, [%r3, %r6]"  },
   57.97 +	{ 0xfe00, 0x5e00, "ldsh %r0, [%r3, %r6]"  },
   57.98 +	// Format 9
   57.99 +	{ 0xe800, 0x6000, "str%B %r0, [%r3, %p]"  },
  57.100 +	{ 0xe800, 0x6800, "ldr%B %r0, [%r3, %p]"  },
  57.101 +	// Format 10
  57.102 +	{ 0xf800, 0x8000, "strh %r0, [%r3, %e]"	  },
  57.103 +	{ 0xf800, 0x8800, "ldrh %r0, [%r3, %e]"	  },
  57.104 +	// Format 11
  57.105 +	{ 0xf800, 0x9000, "str %r8, [sp, %w]"	  },
  57.106 +	{ 0xf800, 0x9800, "ldr %r8, [sp, %w]"	  },
  57.107 +	// Format 12
  57.108 +	{ 0xf800, 0xa000, "add %r8, pc, %w (=%K)" },
  57.109 +	{ 0xf800, 0xa800, "add %r8, sp, %w"		  },
  57.110 +	// Format 13
  57.111 +	{ 0xff00, 0xb000, "add sp, %s"			  },
  57.112 +	// Format 14
  57.113 +	{ 0xffff, 0xb500, "push {lr}"			  },
  57.114 +	{ 0xff00, 0xb400, "push {%l}"			  },
  57.115 +	{ 0xff00, 0xb500, "push {%l,lr}"		  },
  57.116 +	{ 0xffff, 0xbd00, "pop {pc}"			  },
  57.117 +	{ 0xff00, 0xbd00, "pop {%l,pc}"			  },
  57.118 +	{ 0xff00, 0xbc00, "pop {%l}"			  },
  57.119 +	// Format 15
  57.120 +	{ 0xf800, 0xc000, "stmia %r8!, {%l}"	  },
  57.121 +	{ 0xf800, 0xc800, "ldmia %r8!, {%l}"	  },
  57.122 +	// Format 17
  57.123 +	{ 0xff00, 0xdf00, "swi %m"				  },
  57.124 +	// Format 16
  57.125 +	{ 0xf000, 0xd000, "b%c %W"				  },
  57.126 +	// Format 18
  57.127 +	{ 0xf800, 0xe000, "b %a"				  },
  57.128 +	// Format 19
  57.129 +	{ 0xf800, 0xf000, "bl %A"				  },
  57.130 +	{ 0xf800, 0xf800, "blh %Z"				  },
  57.131 +	{ 0xff00, 0xbe00, "bkpt %O"				  },
  57.132 +	// Unknown
  57.133 +	{ 0x0000, 0x0000, "[ ??? ]"				  }
  57.134 +};
  57.135 +
  57.136 +const Opcodes armOpcodes[] = {
  57.137 +	// Undefined
  57.138 +	{ 0x0e000010, 0x06000010, "[ undefined ]"				  },
  57.139 +	// Branch instructions
  57.140 +	{ 0x0ff000f0, 0x01200010, "bx%c %r0"					  },
  57.141 +	{ 0x0f000000, 0x0a000000, "b%c %o"						  },
  57.142 +	{ 0x0f000000, 0x0b000000, "bl%c %o"						  },
  57.143 +	{ 0x0f000000, 0x0f000000, "swi%c %q"					  },
  57.144 +	// PSR transfer
  57.145 +	{ 0x0fbf0fff, 0x010f0000, "mrs%c %r3, %p"				  },
  57.146 +	{ 0x0db0f000, 0x0120f000, "msr%c %p, %i"				  },
  57.147 +	// Multiply instructions
  57.148 +	{ 0x0fe000f0, 0x00000090, "mul%c%s %r4, %r0, %r2"		  },
  57.149 +	{ 0x0fe000f0, 0x00200090, "mla%c%s %r4, %r0, %r2, %r3"	  },
  57.150 +	{ 0x0fa000f0, 0x00800090, "%umull%c%s %r3, %r4, %r0, %r2" },
  57.151 +	{ 0x0fa000f0, 0x00a00090, "%umlal%c%s %r3, %r4, %r0, %r2" },
  57.152 +	// Load/Store instructions
  57.153 +	{ 0x0fb00ff0, 0x01000090, "swp%c%b %r3, %r0, [%r4]"		  },
  57.154 +	{ 0x0fb000f0, 0x01000090, "[ ??? ]"						  },
  57.155 +	{ 0x0c100000, 0x04000000, "str%c%b%t %r3, %a"			  },
  57.156 +	{ 0x0c100000, 0x04100000, "ldr%c%b%t %r3, %a"			  },
  57.157 +	{ 0x0e100090, 0x00000090, "str%c%h %r3, %a"				  },
  57.158 +	{ 0x0e100090, 0x00100090, "ldr%c%h %r3, %a"				  },
  57.159 +	{ 0x0e100000, 0x08000000, "stm%c%m %r4%l"				  },
  57.160 +	{ 0x0e100000, 0x08100000, "ldm%c%m %r4%l"				  },
  57.161 +	// Data processing
  57.162 +	{ 0x0de00000, 0x00000000, "and%c%s %r3, %r4, %i"		  },
  57.163 +	{ 0x0de00000, 0x00200000, "eor%c%s %r3, %r4, %i"		  },
  57.164 +	{ 0x0de00000, 0x00400000, "sub%c%s %r3, %r4, %i"		  },
  57.165 +	{ 0x0de00000, 0x00600000, "rsb%c%s %r3, %r4, %i"		  },
  57.166 +	{ 0x0de00000, 0x00800000, "add%c%s %r3, %r4, %i"		  },
  57.167 +	{ 0x0de00000, 0x00a00000, "adc%c%s %r3, %r4, %i"		  },
  57.168 +	{ 0x0de00000, 0x00c00000, "sbc%c%s %r3, %r4, %i"		  },
  57.169 +	{ 0x0de00000, 0x00e00000, "rsc%c%s %r3, %r4, %i"		  },
  57.170 +	{ 0x0de00000, 0x01000000, "tst%c%s %r4, %i"				  },
  57.171 +	{ 0x0de00000, 0x01200000, "teq%c%s %r4, %i"				  },
  57.172 +	{ 0x0de00000, 0x01400000, "cmp%c%s %r4, %i"				  },
  57.173 +	{ 0x0de00000, 0x01600000, "cmn%c%s %r4, %i"				  },
  57.174 +	{ 0x0de00000, 0x01800000, "orr%c%s %r3, %r4, %i"		  },
  57.175 +	{ 0x0de00000, 0x01a00000, "mov%c%s %r3, %i"				  },
  57.176 +	{ 0x0de00000, 0x01c00000, "bic%c%s %r3, %r4, %i"		  },
  57.177 +	{ 0x0de00000, 0x01e00000, "mvn%c%s %r3, %i"				  },
  57.178 +	// Coprocessor operations
  57.179 +	{ 0x0f000010, 0x0e000000, "cdp%c %P, %N, %r3, %R4, %R0%V" },
  57.180 +	{ 0x0e100000, 0x0c000000, "stc%c%L %P, %r3, %A"			  },
  57.181 +	{ 0x0f100010, 0x0e000010, "mcr%c %P, %N, %r3, %R4, %R0%V" },
  57.182 +	{ 0x0f100010, 0x0e100010, "mrc%c %P, %N, %r3, %R4, %R0%V" },
  57.183 +	// Unknown
  57.184 +	{ 0x00000000, 0x00000000, "[ ??? ]"						  }
  57.185 +};
  57.186 +
  57.187 +char *addStr(char *dest, const char *src)
  57.188 +{
  57.189 +	while (*src)
  57.190 +	{
  57.191 +		*dest++ = *src++;
  57.192 +	}
  57.193 +	return dest;
  57.194 +}
  57.195 +
  57.196 +char *addHex(char *dest, int siz, u32 val)
  57.197 +{
  57.198 +	if (siz == 0)
  57.199 +	{
  57.200 +		siz = 28;
  57.201 +		while ((((val >> siz) & 15) == 0) && (siz >= 4))
  57.202 +			siz -= 4;
  57.203 +		siz += 4;
  57.204 +	}
  57.205 +	while (siz > 0)
  57.206 +	{
  57.207 +		siz	   -= 4;
  57.208 +		*dest++ = hdig[(val >> siz) & 15];
  57.209 +	}
  57.210 +	return dest;
  57.211 +}
  57.212 +
  57.213 +int disArm(u32 offset, char *dest, int flags)
  57.214 +{
  57.215 +	u32 opcode = debuggerReadMemory(offset);
  57.216 +
  57.217 +	const Opcodes *sp = armOpcodes;
  57.218 +	while (sp->cval != (opcode & sp->mask))
  57.219 +		sp++;
  57.220 +
  57.221 +	if (flags & DIS_VIEW_ADDRESS)
  57.222 +	{
  57.223 +		dest	= addHex(dest, 32, offset);
  57.224 +		*dest++ = ' ';
  57.225 +	}
  57.226 +	if (flags & DIS_VIEW_CODE)
  57.227 +	{
  57.228 +		dest	= addHex(dest, 32, opcode);
  57.229 +		*dest++ = ' ';
  57.230 +	}
  57.231 +
  57.232 +	const char *src = sp->mnemonic;
  57.233 +	while (*src)
  57.234 +	{
  57.235 +		if (*src != '%')
  57.236 +			*dest++ = *src++;
  57.237 +		else
  57.238 +		{
  57.239 +			src++;
  57.240 +			switch (*src)
  57.241 +			{
  57.242 +			case 'c':
  57.243 +				dest = addStr(dest, conditions[opcode >> 28]);
  57.244 +				break;
  57.245 +			case 'r':
  57.246 +				dest = addStr(dest, regs[(opcode >> ((*(++src) - '0') * 4)) & 15]);
  57.247 +				break;
  57.248 +			case 'o':
  57.249 +			{
  57.250 +				*dest++ = '$';
  57.251 +				int off = opcode & 0xffffff;
  57.252 +				if (off & 0x800000)
  57.253 +					off |= 0xff000000;
  57.254 +				off <<= 2;
  57.255 +				dest  = addHex(dest, 32, offset + 8 + off);
  57.256 +			}
  57.257 +			break;
  57.258 +			case 'i':
  57.259 +				if (opcode & (1 << 25))
  57.260 +				{
  57.261 +					dest = addStr(dest, "#0x");
  57.262 +					int imm = opcode & 0xff;
  57.263 +					int rot = (opcode & 0xf00) >> 7;
  57.264 +					int val = (imm << (32 - rot)) | (imm >> rot);
  57.265 +					dest = addHex(dest, 0, val);
  57.266 +				}
  57.267 +				else
  57.268 +				{
  57.269 +					dest = addStr(dest, regs[opcode & 0x0f]);
  57.270 +					int shi = (opcode >> 5) & 3;
  57.271 +					int sdw = (opcode >> 7) & 0x1f;
  57.272 +					if ((sdw == 0) && (shi == 3))
  57.273 +						shi = 4;
  57.274 +					if ((sdw) || (opcode & 0x10) || (shi))
  57.275 +					{
  57.276 +						dest = addStr(dest, ", ");
  57.277 +						dest = addStr(dest, shifts[shi]);
  57.278 +						if (opcode & 0x10)
  57.279 +						{
  57.280 +							*dest++ = ' ';
  57.281 +							dest	= addStr(dest, regs[(opcode >> 8) & 15]);
  57.282 +						}
  57.283 +						else
  57.284 +						{
  57.285 +							if (sdw == 0 && ((shi == 1) || (shi == 2)))
  57.286 +								sdw = 32;
  57.287 +							if (shi != 4)
  57.288 +							{
  57.289 +								dest = addStr(dest, " #0x");
  57.290 +								dest = addHex(dest, 8, sdw);
  57.291 +							}
  57.292 +						}
  57.293 +					}
  57.294 +				}
  57.295 +				break;
  57.296 +			case 'p':
  57.297 +				if (opcode & (1 << 22))
  57.298 +					dest = addStr(dest, "spsr");
  57.299 +				else
  57.300 +					dest = addStr(dest, "cpsr");
  57.301 +				if (opcode & 0x00F00000)
  57.302 +				{
  57.303 +					*dest++ = '_';
  57.304 +					if (opcode & 0x00080000)
  57.305 +						*dest++ = 'f';
  57.306 +					if (opcode & 0x00040000)
  57.307 +						*dest++ = 's';
  57.308 +					if (opcode & 0x00020000)
  57.309 +						*dest++ = 'x';
  57.310 +					if (opcode & 0x00010000)
  57.311 +						*dest++ = 'c';
  57.312 +				}
  57.313 +				break;
  57.314 +			case 's':
  57.315 +				if (opcode & (1 << 20))
  57.316 +					*dest++ = 's';
  57.317 +				break;
  57.318 +			case 'S':
  57.319 +				if (opcode & (1 << 22))
  57.320 +					*dest++ = 's';
  57.321 +				break;
  57.322 +			case 'u':
  57.323 +				if (opcode & (1 << 22))
  57.324 +					*dest++ = 's';
  57.325 +				else
  57.326 +					*dest++ = 'u';
  57.327 +				break;
  57.328 +			case 'b':
  57.329 +				if (opcode & (1 << 22))
  57.330 +					*dest++ = 'b';
  57.331 +				break;
  57.332 +			case 'a':
  57.333 +				if ((opcode & 0x076f0000) == 0x004f0000)
  57.334 +				{
  57.335 +					*dest++ = '[';
  57.336 +					*dest++ = '$';
  57.337 +					int adr = offset + 8;
  57.338 +					int add = (opcode & 15) | ((opcode >> 8) & 0xf0);
  57.339 +					if (opcode & (1 << 23))
  57.340 +						adr += add;
  57.341 +					else
  57.342 +						adr -= add;
  57.343 +					dest	= addHex(dest, 32, adr);
  57.344 +					*dest++ = ']';
  57.345 +					dest	= addStr(dest, " (=");
  57.346 +					*dest++ = '$';
  57.347 +					dest	= addHex(dest, 32, debuggerReadMemory(adr));
  57.348 +					*dest++ = ')';
  57.349 +				}
  57.350 +				if ((opcode & 0x072f0000) == 0x050f0000)
  57.351 +				{
  57.352 +					*dest++ = '[';
  57.353 +					*dest++ = '$';
  57.354 +					int adr = offset + 8;
  57.355 +					if (opcode & (1 << 23))
  57.356 +						adr += opcode & 0xfff;
  57.357 +					else
  57.358 +						adr -= opcode & 0xfff;
  57.359 +					dest	= addHex(dest, 32, adr);
  57.360 +					*dest++ = ']';
  57.361 +					dest	= addStr(dest, " (=");
  57.362 +					*dest++ = '$';
  57.363 +					dest	= addHex(dest, 32, debuggerReadMemory(adr));
  57.364 +					*dest++ = ')';
  57.365 +				}
  57.366 +				else
  57.367 +				{
  57.368 +					int reg = (opcode >> 16) & 15;
  57.369 +					*dest++ = '[';
  57.370 +					dest	= addStr(dest, regs[reg]);
  57.371 +					if (!(opcode & (1 << 24)))
  57.372 +						*dest++ = ']';
  57.373 +					if (((opcode & (1 << 25)) && (opcode & (1 << 26))) || (!(opcode & (1 << 22)) && !(opcode & (1 << 26))))
  57.374 +					{
  57.375 +						dest = addStr(dest, ", ");
  57.376 +						if (!(opcode & (1 << 23)))
  57.377 +							*dest++ = '-';
  57.378 +						dest = addStr(dest, regs[opcode & 0x0f]);
  57.379 +						int shi = (opcode >> 5) & 3;
  57.380 +						if (opcode & (1 << 26))
  57.381 +						{
  57.382 +							if (((opcode >> 7) & 0x1f) || (opcode & 0x10) || (shi == 1) || (shi == 2))
  57.383 +							{
  57.384 +								dest = addStr(dest, ", ");
  57.385 +								dest = addStr(dest, shifts[shi]);
  57.386 +								if (opcode & 0x10)
  57.387 +								{
  57.388 +									*dest++ = ' ';
  57.389 +									dest	= addStr(dest, regs[(opcode >> 8) & 15]);
  57.390 +								}
  57.391 +								else
  57.392 +								{
  57.393 +									int sdw = (opcode >> 7) & 0x1f;
  57.394 +									if (sdw == 0 && ((shi == 1) || (shi == 2)))
  57.395 +										sdw = 32;
  57.396 +									dest = addStr(dest, " #0x");
  57.397 +									dest = addHex(dest, 8, sdw);
  57.398 +								}
  57.399 +							}
  57.400 +						}
  57.401 +					}
  57.402 +					else
  57.403 +					{
  57.404 +						int off;
  57.405 +						if (opcode & (1 << 26))
  57.406 +							off = opcode & 0xfff;
  57.407 +						else
  57.408 +							off = (opcode & 15) | ((opcode >> 4) & 0xf0);
  57.409 +						if (off)
  57.410 +						{
  57.411 +							dest = addStr(dest, ", ");
  57.412 +							if (!(opcode & (1 << 23)))
  57.413 +								*dest++ = '-';
  57.414 +							dest = addStr(dest, "#0x");
  57.415 +							dest = addHex(dest, 0, off);
  57.416 +						}
  57.417 +					}
  57.418 +					if (opcode & (1 << 24))
  57.419 +					{
  57.420 +						*dest++ = ']';
  57.421 +						if (opcode & (1 << 21))
  57.422 +							*dest++ = '!';
  57.423 +					}
  57.424 +				}
  57.425 +				break;
  57.426 +			case 't':
  57.427 +				if ((opcode & 0x01200000) == 0x01200000)
  57.428 +					*dest++ = 't';
  57.429 +				break;
  57.430 +			case 'h':
  57.431 +				if (opcode & (1 << 6))
  57.432 +					*dest++ = 's';
  57.433 +				if (opcode & (1 << 5))
  57.434 +					*dest++ = 'h';
  57.435 +				else
  57.436 +					*dest++ = 'b';
  57.437 +				break;
  57.438 +			case 'm':
  57.439 +				if (((opcode >> 16) & 15) == 13)
  57.440 +				{
  57.441 +					if (opcode & 0x00100000)
  57.442 +						dest = addStr(dest, armMultLoadStore[8 + ((opcode >> 23) & 3)]);
  57.443 +					else
  57.444 +						dest = addStr(dest, armMultLoadStore[4 + ((opcode >> 23) & 3)]);
  57.445 +				}
  57.446 +				else
  57.447 +					dest = addStr(dest, armMultLoadStore[(opcode >> 23) & 3]);
  57.448 +				break;
  57.449 +			case 'l':
  57.450 +				if (opcode & (1 << 21))
  57.451 +					*dest++ = '!';
  57.452 +				dest = addStr(dest, ", {");
  57.453 +				{
  57.454 +					int rlst	  = opcode & 0xffff;
  57.455 +					int msk		  = 0;
  57.456 +					int not_first = 0;
  57.457 +					while (msk < 16)
  57.458 +					{
  57.459 +						if (rlst & (1 << msk))
  57.460 +						{
  57.461 +							int fr = msk;
  57.462 +							while (rlst & (1 << msk))
  57.463 +								msk++;
  57.464 +							int to = msk - 1;
  57.465 +							if (not_first)
  57.466 +								//dest = addStr(dest, ", ");
  57.467 +								*dest++ = ',';
  57.468 +							dest = addStr(dest, regs[fr]);
  57.469 +							if (fr != to)
  57.470 +							{
  57.471 +								if (fr == to - 1)
  57.472 +									//dest = addStr(", ");
  57.473 +									*dest++ = ',';
  57.474 +								else
  57.475 +									*dest++ = '-';
  57.476 +								dest = addStr(dest, regs[to]);
  57.477 +							}
  57.478 +							not_first = 1;
  57.479 +						}
  57.480 +						else
  57.481 +							msk++;
  57.482 +					}
  57.483 +					*dest++ = '}';
  57.484 +					if (opcode & (1 << 22))
  57.485 +						*dest++ = '^';
  57.486 +				}
  57.487 +				break;
  57.488 +			case 'q':
  57.489 +				*dest++ = '$';
  57.490 +				dest	= addHex(dest, 24, opcode & 0xffffff);
  57.491 +				break;
  57.492 +			case 'P':
  57.493 +				*dest++ = 'p';
  57.494 +				dest	= addStr(dest, decVals[(opcode >> 8) & 15]);
  57.495 +				break;
  57.496 +			case 'N':
  57.497 +				if (opcode & 0x10)
  57.498 +					dest = addStr(dest, decVals[(opcode >> 21) & 7]);
  57.499 +				else
  57.500 +					dest = addStr(dest, decVals[(opcode >> 20) & 15]);
  57.501 +				break;
  57.502 +			case 'R':
  57.503 +			{
  57.504 +				src++;
  57.505 +				int reg = 4 * (*src - '0');
  57.506 +				*dest++ = 'c';
  57.507 +				dest	= addStr(dest, decVals[(opcode >> reg) & 15]);
  57.508 +			}
  57.509 +			break;
  57.510 +			case 'V':
  57.511 +			{
  57.512 +				int val = (opcode >> 5) & 7;
  57.513 +				if (val)
  57.514 +				{
  57.515 +					dest = addStr(dest, ", ");
  57.516 +					dest = addStr(dest, decVals[val]);
  57.517 +				}
  57.518 +			}
  57.519 +			break;
  57.520 +			case 'L':
  57.521 +				if (opcode & (1 << 22))
  57.522 +					*dest++ = 'l';
  57.523 +				break;
  57.524 +			case 'A':
  57.525 +				if ((opcode & 0x012f0000) == 0x010f0000)
  57.526 +				{
  57.527 +					int adr = offset + 8;
  57.528 +					int add = (opcode & 0xff) << 2;
  57.529 +					if (opcode & (1 << 23))
  57.530 +						adr += add;
  57.531 +					else
  57.532 +						adr -= add;
  57.533 +					*dest++ = '$';
  57.534 +					addHex(dest, 32, adr);
  57.535 +				}
  57.536 +				else
  57.537 +				{
  57.538 +					*dest++ = '[';
  57.539 +					dest	= addStr(dest, regs[(opcode >> 16) & 15]);
  57.540 +					if (!(opcode & (1 << 24)))
  57.541 +						*dest++ = ']';
  57.542 +					int off = (opcode & 0xff) << 2;
  57.543 +					if (off)
  57.544 +					{
  57.545 +						dest = addStr(dest, ", ");
  57.546 +						if (!(opcode & (1 << 23)))
  57.547 +							*dest++ = '-';
  57.548 +						dest = addStr(dest, "#0x");
  57.549 +						dest = addHex(dest, 0, off);
  57.550 +					}
  57.551 +					if (opcode & (1 << 24))
  57.552 +					{
  57.553 +						*dest++ = ']';
  57.554 +						if (opcode & (1 << 21))
  57.555 +							*dest++ = '!';
  57.556 +					}
  57.557 +				}
  57.558 +				break;
  57.559 +			}
  57.560 +			src++;
  57.561 +		}
  57.562 +	}
  57.563 +	*dest++ = 0;
  57.564 +
  57.565 +	return 4;
  57.566 +}
  57.567 +
  57.568 +int disThumb(u32 offset, char *dest, int flags)
  57.569 +{
  57.570 +	u32 opcode = debuggerReadHalfWord(offset);
  57.571 +
  57.572 +	const Opcodes *sp = thumbOpcodes;
  57.573 +	int ret = 2;
  57.574 +	while (sp->cval != (opcode & sp->mask))
  57.575 +		sp++;
  57.576 +
  57.577 +	if (flags & DIS_VIEW_ADDRESS)
  57.578 +	{
  57.579 +		dest	= addHex(dest, 32, offset);
  57.580 +		*dest++ = ' ';
  57.581 +	}
  57.582 +	if (flags & DIS_VIEW_CODE)
  57.583 +	{
  57.584 +		dest	= addHex(dest, 16, opcode);
  57.585 +		*dest++ = ' ';
  57.586 +	}
  57.587 +
  57.588 +	const char *src = sp->mnemonic;
  57.589 +	while (*src)
  57.590 +	{
  57.591 +		if (*src != '%')
  57.592 +			*dest++ = *src++;
  57.593 +		else
  57.594 +		{
  57.595 +			src++;
  57.596 +			switch (*src)
  57.597 +			{
  57.598 +			case 'r':
  57.599 +				src++;
  57.600 +				dest = addStr(dest, regs[(opcode >> (*src - '0')) & 7]);
  57.601 +				break;
  57.602 +			case 'o':
  57.603 +				dest = addStr(dest, "#0x");
  57.604 +				{
  57.605 +					int val = (opcode >> 6) & 0x1f;
  57.606 +					dest = addHex(dest, 8, val);
  57.607 +				}
  57.608 +				break;
  57.609 +			case 'p':
  57.610 +				dest = addStr(dest, "#0x");
  57.611 +				{
  57.612 +					int val = (opcode >> 6) & 0x1f;
  57.613 +					if (!(opcode & (1 << 12)))
  57.614 +						val <<= 2;
  57.615 +					dest = addHex(dest, 0, val);
  57.616 +				}
  57.617 +				break;
  57.618 +			case 'e':
  57.619 +				dest = addStr(dest, "#0x");
  57.620 +				dest = addHex(dest, 0, ((opcode >> 6) & 0x1f) << 1);
  57.621 +				break;
  57.622 +			case 'i':
  57.623 +				dest = addStr(dest, "#0x");
  57.624 +				dest = addHex(dest, 0, (opcode >> 6) & 7);
  57.625 +				break;
  57.626 +			case 'h':
  57.627 +			{
  57.628 +				src++;
  57.629 +				int reg = (opcode >> (*src - '0')) & 7;
  57.630 +				src++;
  57.631 +				if (opcode & (1 << (*src - '0')))
  57.632 +					reg += 8;
  57.633 +				dest = addStr(dest, regs[reg]);
  57.634 +			}
  57.635 +			break;
  57.636 +			case 'O':
  57.637 +				dest = addStr(dest, "#0x");
  57.638 +				dest = addHex(dest, 0, (opcode & 0xff));
  57.639 +				break;
  57.640 +			case 'I':
  57.641 +				*dest++ = '$';
  57.642 +				dest	= addHex(dest, 32, (offset & 0xfffffffc) + 4 + ((opcode & 0xff) << 2));
  57.643 +				break;
  57.644 +			case 'J':
  57.645 +			{
  57.646 +				u32 value = debuggerReadMemory((offset & 0xfffffffc) + 4 +
  57.647 +				                               ((opcode & 0xff) << 2));
  57.648 +				*dest++ = '$';
  57.649 +				dest	= addHex(dest, 32, value);
  57.650 +				const char *s = elfGetAddressSymbol(value);
  57.651 +				if (*s)
  57.652 +				{
  57.653 +					*dest++ = ' ';
  57.654 +					dest	= addStr(dest, s);
  57.655 +				}
  57.656 +			}
  57.657 +			break;
  57.658 +			case 'K':
  57.659 +			{
  57.660 +				u32 value = (offset & 0xfffffffc) + 4 + ((opcode & 0xff) << 2);
  57.661 +				*dest++ = '$';
  57.662 +				dest	= addHex(dest, 32, value);
  57.663 +				const char *s = elfGetAddressSymbol(value);
  57.664 +				if (*s)
  57.665 +				{
  57.666 +					*dest++ = ' ';
  57.667 +					dest	= addStr(dest, s);
  57.668 +				}
  57.669 +			}
  57.670 +			break;
  57.671 +			case 'b':
  57.672 +				if (opcode & (1 << 10))
  57.673 +					*dest++ = 'b';
  57.674 +				break;
  57.675 +			case 'B':
  57.676 +				if (opcode & (1 << 12))
  57.677 +					*dest++ = 'b';
  57.678 +				break;
  57.679 +			case 'w':
  57.680 +				dest = addStr(dest, "#0x");
  57.681 +				dest = addHex(dest, 0, (opcode & 0xff) << 2);
  57.682 +				break;
  57.683 +			case 'W':
  57.684 +				*dest++ = '$';
  57.685 +				{
  57.686 +					int add = opcode & 0xff;
  57.687 +					if (add & 0x80)
  57.688 +						add |= 0xffffff00;
  57.689 +					dest = addHex(dest, 32, (offset & 0xfffffffe) + 4 + (add << 1));
  57.690 +				}
  57.691 +				break;
  57.692 +			case 'c':
  57.693 +				dest = addStr(dest, conditions[(opcode >> 8) & 15]);
  57.694 +				break;
  57.695 +			case 's':
  57.696 +				if (opcode & (1 << 7))
  57.697 +					*dest++ = '-';
  57.698 +				dest = addStr(dest, "#0x");
  57.699 +				dest = addHex(dest, 0, (opcode & 0x7f) << 2);
  57.700 +				break;
  57.701 +			case 'l':
  57.702 +			{
  57.703 +				int rlst	  = opcode & 0xff;
  57.704 +				int msk		  = 0;
  57.705 +				int not_first = 0;
  57.706 +				while (msk < 8)
  57.707 +				{
  57.708 +					if (rlst & (1 << msk))
  57.709 +					{
  57.710 +						int fr = msk;
  57.711 +						while (rlst & (1 << msk))
  57.712 +							msk++;
  57.713 +						int to = msk - 1;
  57.714 +						if (not_first)
  57.715 +							*dest++ = ',';
  57.716 +						dest = addStr(dest, regs[fr]);
  57.717 +						if (fr != to)
  57.718 +						{
  57.719 +							if (fr == to - 1)
  57.720 +								*dest++ = ',';
  57.721 +							else
  57.722 +								*dest++ = '-';
  57.723 +							dest = addStr(dest, regs[to]);
  57.724 +						}
  57.725 +						not_first = 1;
  57.726 +					}
  57.727 +					else
  57.728 +						msk++;
  57.729 +				}
  57.730 +			}
  57.731 +			break;
  57.732 +			case 'm':
  57.733 +				*dest++ = '$';
  57.734 +				dest	= addHex(dest, 8, opcode & 0xff);
  57.735 +				break;
  57.736 +			case 'Z':
  57.737 +				*dest++ = '$';
  57.738 +				dest	= addHex(dest, 16, (opcode & 0x7ff) << 1);
  57.739 +				break;
  57.740 +			case 'a':
  57.741 +				*dest++ = '$';
  57.742 +				{
  57.743 +					int add = opcode & 0x07ff;
  57.744 +					if (add & 0x400)
  57.745 +						add |= 0xfffff800;
  57.746 +					add <<= 1;
  57.747 +					dest  = addHex(dest, 32, offset + 4 + add);
  57.748 +				}
  57.749 +				break;
  57.750 +			case 'A':
  57.751 +			{
  57.752 +				int nopcode = debuggerReadHalfWord(offset + 2);
  57.753 +				int add		= opcode & 0x7ff;
  57.754 +				if (add & 0x400)
  57.755 +					add |= 0xfff800;
  57.756 +				add		= (add << 12) | ((nopcode & 0x7ff) << 1);
  57.757 +				*dest++ = '$';
  57.758 +				dest	= addHex(dest, 32, offset + 4 + add);
  57.759 +				const char *s = elfGetAddressSymbol(offset + 4 + add);
  57.760 +				if (*s)
  57.761 +				{
  57.762 +					*dest++ = ' ';
  57.763 +					*dest++ = '(';
  57.764 +					dest	= addStr(dest, s);
  57.765 +					*dest++ = ')';
  57.766 +				}
  57.767 +				ret = 4;
  57.768 +			}
  57.769 +			break;
  57.770 +			}
  57.771 +			src++;
  57.772 +		}
  57.773 +	}
  57.774 +	*dest++ = 0;
  57.775 +	return ret;
  57.776 +}
  57.777 +
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/src/gba/armdis.h	Sun Mar 04 14:33:52 2012 -0600
    58.3 @@ -0,0 +1,14 @@
    58.4 +#ifndef VBA_GBA_ARMDIS_H
    58.5 +#define VBA_GBA_ARMDIS_H
    58.6 +
    58.7 +#if _MSC_VER > 1000
    58.8 +#pragma once
    58.9 +#endif // _MSC_VER > 1000
   58.10 +
   58.11 +#define DIS_VIEW_ADDRESS 1
   58.12 +#define DIS_VIEW_CODE 2
   58.13 +
   58.14 +int disThumb(u32 offset, char *dest, int flags);
   58.15 +int disArm(u32 offset, char *dest, int flags);
   58.16 +
   58.17 +#endif // VBA_GBA_ARMDIS_H
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/src/gba/bios.cpp	Sun Mar 04 14:33:52 2012 -0600
    59.3 @@ -0,0 +1,1278 @@
    59.4 +#include <cmath>
    59.5 +#include <cstdlib>
    59.6 +#include <cstring>
    59.7 +
    59.8 +#include "bios.h"
    59.9 +#include "../common/System.h"
   59.10 +#include "GBA.h"
   59.11 +#include "GBACheats.h" // FIXME: SDL build requires this
   59.12 +#include "GBAinline.h"
   59.13 +#include "GBAGlobals.h"
   59.14 +
   59.15 +s16 sineTable[256] = {
   59.16 +	(s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1,
   59.17 +	(s16)0x0C7C, (s16)0x0E05, (s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708,
   59.18 +	(s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6, (s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D,
   59.19 +	(s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD, (s16)0x2AFA, (s16)0x2C21,
   59.20 +	(s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453,
   59.21 +	(s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82,
   59.22 +	(s16)0x3B20, (s16)0x3BB6, (s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71,
   59.23 +	(s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84, (s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB,
   59.24 +	(s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84, (s16)0x3F4E, (s16)0x3F0E,
   59.25 +	(s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6,
   59.26 +	(s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612,
   59.27 +	(s16)0x3536, (s16)0x3453, (s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A,
   59.28 +	(s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD, (s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA,
   59.29 +	(s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6, (s16)0x1B5D, (s16)0x19EF,
   59.30 +	(s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05,
   59.31 +	(s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192,
   59.32 +	(s16)0x0000, (s16)0xFE6E, (s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F,
   59.33 +	(s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF, (s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8,
   59.34 +	(s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075, (s16)0xDF19, (s16)0xDDC3,
   59.35 +	(s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF,
   59.36 +	(s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD,
   59.37 +	(s16)0xCACA, (s16)0xC9EE, (s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E,
   59.38 +	(s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B, (s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F,
   59.39 +	(s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D, (s16)0xC014, (s16)0xC005,
   59.40 +	(s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2,
   59.41 +	(s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A,
   59.42 +	(s16)0xC4E0, (s16)0xC57E, (s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE,
   59.43 +	(s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C, (s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6,
   59.44 +	(s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1, (s16)0xD9E1, (s16)0xDB26,
   59.45 +	(s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611,
   59.46 +	(s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB,
   59.47 +	(s16)0xF384, (s16)0xF50F, (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E
   59.48 +};
   59.49 +
   59.50 +void BIOS_ArcTan()
   59.51 +{
   59.52 +#ifdef GBA_LOGGING
   59.53 +	if (systemVerbose & VERBOSE_SWI)
   59.54 +	{
   59.55 +		log("ArcTan: %08x (VCOUNT=%2d)\n",
   59.56 +		    reg[0].I,
   59.57 +		    VCOUNT);
   59.58 +	}
   59.59 +#endif
   59.60 +
   59.61 +	s32 a = -((s32)(reg[0].I * reg[0].I)) >> 14;
   59.62 +	s32 b = ((0xA9 * a) >> 14) + 0x390;
   59.63 +	b        = ((b * a) >> 14) + 0x91C;
   59.64 +	b        = ((b * a) >> 14) + 0xFB6;
   59.65 +	b        = ((b * a) >> 14) + 0x16AA;
   59.66 +	b        = ((b * a) >> 14) + 0x2081;
   59.67 +	b        = ((b * a) >> 14) + 0x3651;
   59.68 +	b        = ((b * a) >> 14) + 0xA2F9;
   59.69 +	reg[0].I = (reg[0].I * b) >> 16;
   59.70 +
   59.71 +#ifdef GBA_LOGGING
   59.72 +	if (systemVerbose & VERBOSE_SWI)
   59.73 +	{
   59.74 +		log("ArcTan: return=%08x\n",
   59.75 +		    reg[0].I);
   59.76 +	}
   59.77 +#endif
   59.78 +}
   59.79 +
   59.80 +void BIOS_ArcTan2()
   59.81 +{
   59.82 +#ifdef GBA_LOGGING
   59.83 +	if (systemVerbose & VERBOSE_SWI)
   59.84 +	{
   59.85 +		log("ArcTan2: %08x,%08x (VCOUNT=%2d)\n",
   59.86 +		    reg[0].I,
   59.87 +		    reg[1].I,
   59.88 +		    VCOUNT);
   59.89 +	}
   59.90 +#endif
   59.91 +
   59.92 +	s16 x = reg[0].I;
   59.93 +	s16 y = reg[1].I;
   59.94 +
   59.95 +	if (y == 0)
   59.96 +	{
   59.97 +		reg[0].I = 0x8000 & x;
   59.98 +		reg[3].I = 0x170;
   59.99 +	}
  59.100 +	else
  59.101 +	{
  59.102 +		if (x == 0)
  59.103 +		{
  59.104 +			reg[0].I = (0x8000 & y) + 0x4000;
  59.105 +			reg[3].I = 0x170;
  59.106 +		}
  59.107 +		else
  59.108 +		{
  59.109 +			if (abs(x) > abs(y))
  59.110 +			{
  59.111 +				reg[1].I = x;
  59.112 +				reg[0].I = y << 14;
  59.113 +				BIOS_Div();
  59.114 +				BIOS_ArcTan();
  59.115 +				if (x < 0)
  59.116 +					reg[0].I = 0x8000 + reg[0].I;
  59.117 +				else
  59.118 +					reg[0].I = ((y & 0x8000) << 1) + reg[0].I;
  59.119 +				reg[3].I = 0x170;
  59.120 +			}
  59.121 +			else
  59.122 +			{
  59.123 +				reg[0].I = x << 14;
  59.124 +				BIOS_Div();
  59.125 +				BIOS_ArcTan();
  59.126 +				reg[0].I = (0x4000 + (y & 0x8000)) - reg[0].I;
  59.127 +				reg[3].I = 0x170;
  59.128 +			}
  59.129 +		}
  59.130 +	}
  59.131 +
  59.132 +#ifdef GBA_LOGGING
  59.133 +	if (systemVerbose & VERBOSE_SWI)
  59.134 +	{
  59.135 +		log("ArcTan2: return=%08x\n",
  59.136 +		    reg[0].I);
  59.137 +	}
  59.138 +#endif
  59.139 +}
  59.140 +
  59.141 +void BIOS_BitUnPack()
  59.142 +{
  59.143 +#ifdef GBA_LOGGING
  59.144 +	if (systemVerbose & VERBOSE_SWI)
  59.145 +	{
  59.146 +		log("BitUnPack: %08x,%08x,%08x (VCOUNT=%2d)\n",
  59.147 +		    reg[0].I,
  59.148 +		    reg[1].I,
  59.149 +		    reg[2].I,
  59.150 +		    VCOUNT);
  59.151 +	}
  59.152 +#endif
  59.153 +
  59.154 +	u32 source = reg[0].I;
  59.155 +	u32 dest   = reg[1].I;
  59.156 +	u32 header = reg[2].I;
  59.157 +
  59.158 +	int len = CPUReadHalfWord(header);
  59.159 +	// check address
  59.160 +	int bits    = CPUReadByte(header+2);
  59.161 +	int revbits = 8 - bits;
  59.162 +	// u32 value = 0;
  59.163 +	u32  base    = CPUReadMemory(header+4);
  59.164 +	bool addBase = (base & 0x80000000) ? true : false;
  59.165 +	base &= 0x7fffffff;
  59.166 +	int dataSize = CPUReadByte(header+3);
  59.167 +
  59.168 +	int data = 0;
  59.169 +	int bitwritecount = 0;
  59.170 +	while (1)
  59.171 +	{
  59.172 +		len -= 1;
  59.173 +		if (len < 0)
  59.174 +			break;
  59.175 +		int mask = 0xff >> revbits;
  59.176 +		u8  b    = CPUReadByte(source);
  59.177 +		source++;
  59.178 +		int bitcount = 0;
  59.179 +		while (1)
  59.180 +		{
  59.181 +			if (bitcount >= 8)
  59.182 +				break;
  59.183 +			u32 d    = b & mask;
  59.184 +			u32 temp = d >> bitcount;
  59.185 +			if (!temp && addBase)
  59.186 +			{
  59.187 +				temp += base;
  59.188 +			}
  59.189 +			data |= temp << bitwritecount;
  59.190 +			bitwritecount += dataSize;
  59.191 +			if (bitwritecount >= 32)
  59.192 +			{
  59.193 +				CPUWriteMemory(dest, data);
  59.194 +				dest += 4;
  59.195 +				data  = 0;
  59.196 +				bitwritecount = 0;
  59.197 +			}
  59.198 +			mask    <<= bits;
  59.199 +			bitcount += bits;
  59.200 +		}
  59.201 +	}
  59.202 +}
  59.203 +
  59.204 +void BIOS_BgAffineSet()
  59.205 +{
  59.206 +#ifdef GBA_LOGGING
  59.207 +	if (systemVerbose & VERBOSE_SWI)
  59.208 +	{
  59.209 +		log("BgAffineSet: %08x,%08x,%08x (VCOUNT=%2d)\n",
  59.210 +		    reg[0].I,
  59.211 +		    reg[1].I,
  59.212 +		    reg[2].I,
  59.213 +		    VCOUNT);
  59.214 +	}
  59.215 +#endif
  59.216 +
  59.217 +	u32 src  = reg[0].I;
  59.218 +	u32 dest = reg[1].I;
  59.219 +	int num  = reg[2].I;
  59.220 +
  59.221 +	for (int i = 0; i < num; i++)
  59.222 +	{
  59.223 +		s32 cx = CPUReadMemory(src);
  59.224 +		src += 4;
  59.225 +		s32 cy = CPUReadMemory(src);
  59.226 +		src += 4;
  59.227 +		s16 dispx = CPUReadHalfWord(src);
  59.228 +		src += 2;
  59.229 +		s16 dispy = CPUReadHalfWord(src);
  59.230 +		src += 2;
  59.231 +		s16 rx = CPUReadHalfWord(src);
  59.232 +		src += 2;
  59.233 +		s16 ry = CPUReadHalfWord(src);
  59.234 +		src += 2;
  59.235 +		u16 theta = CPUReadHalfWord(src)>>8;
  59.236 +		src += 4; // keep structure alignment
  59.237 +		s32 a = (s32)sineTable[(theta+0x40)&255];
  59.238 +		s32 b = (s32)sineTable[theta];
  59.239 +
  59.240 +		s16 dx  =  (s16)((rx * a)>>14);
  59.241 +		s16 dmx = (s16)((rx * b)>>14);
  59.242 +		s16 dy  =  (s16)((ry * b)>>14);
  59.243 +		s16 dmy = (s16)((ry * a)>>14);
  59.244 +
  59.245 +		CPUWriteHalfWord(dest, dx);
  59.246 +		dest += 2;
  59.247 +		CPUWriteHalfWord(dest, -dmx);
  59.248 +		dest += 2;
  59.249 +		CPUWriteHalfWord(dest, dy);
  59.250 +		dest += 2;
  59.251 +		CPUWriteHalfWord(dest, dmy);
  59.252 +		dest += 2;
  59.253 +
  59.254 +		s32 startx = cx - dx * dispx + dmx * dispy;
  59.255 +		s32 starty = cy - dy * dispx - dmy * dispy;
  59.256 +
  59.257 +		CPUWriteMemory(dest, startx);
  59.258 +		dest += 4;
  59.259 +		CPUWriteMemory(dest, starty);
  59.260 +		dest += 4;
  59.261 +	}
  59.262 +}
  59.263 +
  59.264 +void BIOS_CpuSet()
  59.265 +{
  59.266 +#ifdef GBA_LOGGING
  59.267 +	if (systemVerbose & VERBOSE_SWI)
  59.268 +	{
  59.269 +		log("CpuSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
  59.270 +		    reg[2].I, VCOUNT);
  59.271 +	}
  59.272 +#endif
  59.273 +
  59.274 +	u32 source = reg[0].I;
  59.275 +	u32 dest   = reg[1].I;
  59.276 +	u32 cnt    = reg[2].I;
  59.277 +
  59.278 +	if (((source & 0xe000000) == 0) ||
  59.279 +	    ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0)
  59.280 +		return;
  59.281 +
  59.282 +	int count = cnt & 0x1FFFFF;
  59.283 +
  59.284 +	// 32-bit ?
  59.285 +	if ((cnt >> 26) & 1)
  59.286 +	{
  59.287 +		// needed for 32-bit mode!
  59.288 +		source &= 0xFFFFFFFC;
  59.289 +		dest   &= 0xFFFFFFFC;
  59.290 +		// fill ?
  59.291 +		if ((cnt >> 24) & 1)
  59.292 +		{
  59.293 +			u32 value = CPUReadMemory(source);
  59.294 +			while (count)
  59.295 +			{
  59.296 +				CPUWriteMemory(dest, value);
  59.297 +				dest += 4;
  59.298 +				count--;
  59.299 +			}
  59.300 +		}
  59.301 +		else
  59.302 +		{
  59.303 +			// copy
  59.304 +			while (count)
  59.305 +			{
  59.306 +				CPUWriteMemory(dest, CPUReadMemory(source));
  59.307 +				source += 4;
  59.308 +				dest   += 4;
  59.309 +				count--;
  59.310 +			}
  59.311 +		}
  59.312 +	}
  59.313 +	else
  59.314 +	{
  59.315 +		// 16-bit fill?
  59.316 +		if ((cnt >> 24) & 1)
  59.317 +		{
  59.318 +			u16 value = CPUReadHalfWord(source);
  59.319 +			while (count)
  59.320 +			{
  59.321 +				CPUWriteHalfWord(dest, value);
  59.322 +				dest += 2;
  59.323 +				count--;
  59.324 +			}
  59.325 +		}
  59.326 +		else
  59.327 +		{
  59.328 +			// copy
  59.329 +			while (count)
  59.330 +			{
  59.331 +				CPUWriteHalfWord(dest, CPUReadHalfWord(source));
  59.332 +				source += 2;
  59.333 +				dest   += 2;
  59.334 +				count--;
  59.335 +			}
  59.336 +		}
  59.337 +	}
  59.338 +}
  59.339 +
  59.340 +void BIOS_CpuFastSet()
  59.341 +{
  59.342 +#ifdef GBA_LOGGING
  59.343 +	if (systemVerbose & VERBOSE_SWI)
  59.344 +	{
  59.345 +		log("CpuFastSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
  59.346 +		    reg[2].I, VCOUNT);
  59.347 +	}
  59.348 +#endif
  59.349 +
  59.350 +	u32 source = reg[0].I;
  59.351 +	u32 dest   = reg[1].I;
  59.352 +	u32 cnt    = reg[2].I;
  59.353 +
  59.354 +	if (((source & 0xe000000) == 0) ||
  59.355 +	    ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0)
  59.356 +		return;
  59.357 +
  59.358 +	// needed for 32-bit mode!
  59.359 +	source &= 0xFFFFFFFC;
  59.360 +	dest   &= 0xFFFFFFFC;
  59.361 +
  59.362 +	int count = cnt & 0x1FFFFF;
  59.363 +
  59.364 +	// fill?
  59.365 +	if ((cnt >> 24) & 1)
  59.366 +	{
  59.367 +		while (count > 0)
  59.368 +		{
  59.369 +			// BIOS always transfers 32 bytes at a time
  59.370 +			u32 value = CPUReadMemory(source);
  59.371 +			for (int i = 0; i < 8; i++)
  59.372 +			{
  59.373 +				CPUWriteMemory(dest, value);
  59.374 +				dest += 4;
  59.375 +			}
  59.376 +			count -= 8;
  59.377 +		}
  59.378 +	}
  59.379 +	else
  59.380 +	{
  59.381 +		// copy
  59.382 +		while (count > 0)
  59.383 +		{
  59.384 +			// BIOS always transfers 32 bytes at a time
  59.385 +			for (int i = 0; i < 8; i++)
  59.386 +			{
  59.387 +				CPUWriteMemory(dest, CPUReadMemory(source));
  59.388 +				source += 4;
  59.389 +				dest   += 4;
  59.390 +			}
  59.391 +			count -= 8;
  59.392 +		}
  59.393 +	}
  59.394 +}
  59.395 +
  59.396 +void BIOS_Diff8bitUnFilterWram()
  59.397 +{
  59.398 +#ifdef GBA_LOGGING
  59.399 +	if (systemVerbose & VERBOSE_SWI)
  59.400 +	{
  59.401 +		log("Diff8bitUnFilterWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
  59.402 +		    reg[1].I, VCOUNT);
  59.403 +	}
  59.404 +#endif
  59.405 +
  59.406 +	u32 source = reg[0].I;
  59.407 +	u32 dest   = reg[1].I;
  59.408 +
  59.409 +	u32 header = CPUReadMemory(source);
  59.410 +	source += 4;
  59.411 +
  59.412 +	if (((source & 0xe000000) == 0) ||
  59.413 +	    ((source + ((header >> 8) & 0x1fffff) & 0xe000000) == 0))
  59.414 +		return;
  59.415 +
  59.416 +	int len = header >> 8;
  59.417 +
  59.418 +	u8 data = CPUReadByte(source++);
  59.419 +	CPUWriteByte(dest++, data);
  59.420 +	len--;
  59.421 +
  59.422 +	while (len > 0)
  59.423 +	{
  59.424 +		u8 diff = CPUReadByte(source++);
  59.425 +		data += diff;
  59.426 +		CPUWriteByte(dest++, data);
  59.427 +		len--;
  59.428 +	}
  59.429 +}
  59.430 +
  59.431 +void BIOS_Diff8bitUnFilterVram()
  59.432 +{
  59.433 +#ifdef GBA_LOGGING
  59.434 +	if (systemVerbose & VERBOSE_SWI)
  59.435 +	{
  59.436 +		log("Diff8bitUnFilterVram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
  59.437 +		    reg[1].I, VCOUNT);
  59.438 +	}
  59.439 +#endif
  59.440 +
  59.441 +	u32 source = reg[0].I;
  59.442 +	u32 dest   = reg[1].I;
  59.443 +
  59.444 +	u32 header = CPUReadMemory(source);
  59.445 +	source += 4;
  59.446 +
  59.447 +	if (((source & 0xe000000) == 0) ||
  59.448 +	    ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
  59.449 +		return;
  59.450 +
  59.451 +	int len = header >> 8;
  59.452 +
  59.453 +	u8  data      = CPUReadByte(source++);
  59.454 +	u16 writeData = data;
  59.455 +	int shift     = 8;
  59.456 +	int bytes     = 1;
  59.457 +
  59.458 +	while (len >= 2)
  59.459 +	{
  59.460 +		u8 diff = CPUReadByte(source++);
  59.461 +		data      += diff;
  59.462 +		writeData |= (data << shift);
  59.463 +		bytes++;
  59.464 +		shift += 8;
  59.465 +		if (bytes == 2)
  59.466 +		{
  59.467 +			CPUWriteHalfWord(dest, writeData);
  59.468 +			dest     += 2;
  59.469 +			len      -= 2;
  59.470 +			bytes     = 0;
  59.471 +			writeData = 0;
  59.472 +			shift     = 0;
  59.473 +		}
  59.474 +	}
  59.475 +}
  59.476 +
  59.477 +void BIOS_Diff16bitUnFilter()
  59.478 +{
  59.479 +#ifdef GBA_LOGGING
  59.480 +	if (systemVerbose & VERBOSE_SWI)
  59.481 +	{
  59.482 +		log("Diff16bitUnFilter: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
  59.483 +		    reg[1].I, VCOUNT);
  59.484 +	}
  59.485 +#endif
  59.486 +
  59.487 +	u32 source = reg[0].I;
  59.488 +	u32 dest   = reg[1].I;
  59.489 +
  59.490 +	u32 header = CPUReadMemory(source);
  59.491 +	source += 4;
  59.492 +
  59.493 +	if (((source & 0xe000000) == 0) ||
  59.494 +	    ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
  59.495 +		return;
  59.496 +
  59.497 +	int len = header >> 8;
  59.498 +
  59.499 +	u16 data = CPUReadHalfWord(source);
  59.500 +	source += 2;
  59.501 +	CPUWriteHalfWord(dest, data);
  59.502 +	dest += 2;
  59.503 +	len  -= 2;
  59.504 +
  59.505 +	while (len >= 2)
  59.506 +	{
  59.507 +		u16 diff = CPUReadHalfWord(source);
  59.508 +		source += 2;
  59.509 +		data   += diff;
  59.510 +		CPUWriteHalfWord(dest, data);
  59.511 +		dest += 2;
  59.512 +		len  -= 2;
  59.513 +	}
  59.514 +}
  59.515 +
  59.516 +void BIOS_Div()
  59.517 +{
  59.518 +#ifdef GBA_LOGGING
  59.519 +	if (systemVerbose & VERBOSE_SWI)
  59.520 +	{
  59.521 +		log("Div: 0x%08x,0x%08x (VCOUNT=%d)\n",
  59.522 +		    reg[0].I,
  59.523 +		    reg[1].I,
  59.524 +		    VCOUNT);
  59.525 +	}
  59.526 +#endif
  59.527 +
  59.528 +	int number = reg[0].I;
  59.529 +	int denom  = reg[1].I;
  59.530 +
  59.531 +	if (denom != 0)
  59.532 +	{
  59.533 +		reg[0].I = number / denom;
  59.534 +		reg[1].I = number % denom;
  59.535 +		s32 temp = (s32)reg[0].I;
  59.536 +		reg[3].I = temp < 0 ? (u32)-temp : (u32)temp;
  59.537 +	}
  59.538 +#ifdef GBA_LOGGING
  59.539 +	if (systemVerbose & VERBOSE_SWI)
  59.540 +	{
  59.541 +		log("Div: return=0x%08x,0x%08x,0x%08x\n",
  59.542 +		    reg[0].I,
  59.543 +		    reg[1].I,
  59.544 +		    reg[3].I);
  59.545 +	}
  59.546 +#endif
  59.547 +}
  59.548 +
  59.549 +void BIOS_DivARM()
  59.550 +{
  59.551 +#ifdef GBA_LOGGING
  59.552 +	if (systemVerbose & VERBOSE_SWI)
  59.553 +	{
  59.554 +		log("DivARM: 0x%08x, (VCOUNT=%d)\n",
  59.555 +		    reg[0].I,
  59.556 +		    VCOUNT);
  59.557 +	}
  59.558 +#endif
  59.559 +
  59.560 +	u32 temp = reg[0].I;
  59.561 +	reg[0].I = reg[1].I;
  59.562 +	reg[1].I = temp;
  59.563 +	BIOS_Div();
  59.564 +}
  59.565 +
  59.566 +void BIOS_HuffUnComp()
  59.567 +{
  59.568 +#ifdef GBA_LOGGING
  59.569 +	if (systemVerbose & VERBOSE_SWI)
  59.570 +	{
  59.571 +		log("HuffUnComp: 0x%08x,0x%08x (VCOUNT=%d)\n",
  59.572 +		    reg[0].I,
  59.573 +		    reg[1].I,
  59.574 +		    VCOUNT);
  59.575 +	}
  59.576 +#endif
  59.577 +
  59.578 +	u32 source = reg[0].I;
  59.579 +	u32 dest   = reg[1].I;
  59.580 +
  59.581 +	u32 header = CPUReadMemory(source);
  59.582 +	source += 4;
  59.583 +
  59.584 +	if (((source & 0xe000000) == 0) ||
  59.585 +	    ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
  59.586 +		return;
  59.587 +
  59.588 +	u8 treeSize = CPUReadByte(source++);
  59.589 +
  59.590 +	u32 treeStart = source;
  59.591 +
  59.592 +	source += (treeSize<<1) + 1;
  59.593 +
  59.594 +	int len = header >> 8;
  59.595 +
  59.596 +	u32 mask = 0x80000000;
  59.597 +	u32 data = CPUReadMemory(source);
  59.598 +	source += 4;
  59.599 +
  59.600 +	int  pos         = 0;
  59.601 +	u8   rootNode    = CPUReadByte(treeStart);
  59.602 +	u8   currentNode = rootNode;
  59.603 +	bool writeData   = false;
  59.604 +	int  byteShift   = 0;
  59.605 +	int  byteCount   = 0;
  59.606 +	u32  writeValue  = 0;
  59.607 +
  59.608 +	if ((header & 0x0F) == 8)
  59.609 +	{
  59.610 +		while (len > 0)
  59.611 +		{
  59.612 +			// take left
  59.613 +			if (pos == 0)
  59.614 +				pos++;
  59.615 +			else
  59.616 +				pos += (((currentNode & 0x3F)+1)<<1);
  59.617 +
  59.618 +			if (data & mask)
  59.619 +			{
  59.620 +				// right
  59.621 +				if (currentNode & 0x40)
  59.622 +					writeData = true;
  59.623 +				currentNode = CPUReadByte(treeStart+pos+1);
  59.624 +			}
  59.625 +			else
  59.626 +			{
  59.627 +				// left
  59.628 +				if (currentNode & 0x80)
  59.629 +					writeData = true;
  59.630 +				currentNode = CPUReadByte(treeStart+pos);
  59.631 +			}
  59.632 +
  59.633 +			if (writeData)
  59.634 +			{
  59.635 +				writeValue |= (currentNode << byteShift);
  59.636 +				byteCount++;
  59.637 +				byteShift += 8;
  59.638 +
  59.639 +				pos         = 0;
  59.640 +				currentNode = rootNode;
  59.641 +				writeData   = false;
  59.642 +
  59.643 +				if (byteCount == 4)
  59.644 +				{
  59.645 +					byteCount = 0;
  59.646 +					byteShift = 0;
  59.647 +					CPUWriteMemory(dest, writeValue);
  59.648 +					writeValue = 0;
  59.649 +					dest      += 4;
  59.650 +					len       -= 4;
  59.651 +				}
  59.652 +			}
  59.653 +			mask >>= 1;
  59.654 +			if (mask == 0)
  59.655 +			{
  59.656 +				mask    = 0x80000000;
  59.657 +				data    = CPUReadMemory(source);
  59.658 +				source += 4;
  59.659 +			}
  59.660 +		}
  59.661 +	}
  59.662 +	else
  59.663 +	{
  59.664 +		int halfLen = 0;
  59.665 +		int value   = 0;
  59.666 +		while (len > 0)
  59.667 +		{
  59.668 +			// take left
  59.669 +			if (pos == 0)
  59.670 +				pos++;
  59.671 +			else
  59.672 +				pos += (((currentNode & 0x3F)+1)<<1);
  59.673 +
  59.674 +			if ((data & mask))
  59.675 +			{
  59.676 +				// right
  59.677 +				if (currentNode & 0x40)
  59.678 +					writeData = true;
  59.679 +				currentNode = CPUReadByte(treeStart+pos+1);
  59.680 +			}
  59.681 +			else
  59.682 +			{
  59.683 +				// left
  59.684 +				if (currentNode & 0x80)
  59.685 +					writeData = true;
  59.686 +				currentNode = CPUReadByte(treeStart+pos);
  59.687 +			}
  59.688 +
  59.689 +			if (writeData)
  59.690 +			{
  59.691 +				if (halfLen == 0)
  59.692 +					value |= currentNode;
  59.693 +				else
  59.694 +					value |= (currentNode<<4);
  59.695 +
  59.696 +				halfLen += 4;
  59.697 +				if (halfLen == 8)
  59.698 +				{
  59.699 +					writeValue |= (value << byteShift);
  59.700 +					byteCount++;
  59.701 +					byteShift += 8;
  59.702 +
  59.703 +					halfLen = 0;
  59.704 +					value   = 0;
  59.705 +
  59.706 +					if (byteCount == 4)
  59.707 +					{
  59.708 +						byteCount = 0;
  59.709 +						byteShift = 0;
  59.710 +						CPUWriteMemory(dest, writeValue);
  59.711 +						dest      += 4;
  59.712 +						writeValue = 0;
  59.713 +						len       -= 4;
  59.714 +					}
  59.715 +				}
  59.716 +				pos         = 0;
  59.717 +				currentNode = rootNode;
  59.718 +				writeData   = false;
  59.719 +			}
  59.720 +			mask >>= 1;
  59.721 +			if (mask == 0)
  59.722 +			{
  59.723 +				mask    = 0x80000000;
  59.724 +				data    = CPUReadMemory(source);
  59.725 +				source += 4;
  59.726 +			}
  59.727 +		}
  59.728 +	}
  59.729 +}
  59.730 +
  59.731 +void BIOS_LZ77UnCompVram()
  59.732 +{
  59.733 +#ifdef GBA_LOGGING
  59.734 +	if (systemVerbose & VERBOSE_SWI)
  59.735 +	{
  59.736 +		log("LZ77UnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n",
  59.737 +		    reg[0].I,
  59.738 +		    reg[1].I,
  59.739 +		    VCOUNT);
  59.740 +	}
  59.741 +#endif
  59.742 +
  59.743 +	u32 source = reg[0].I;
  59.744 +	u32 dest   = reg[1].I;
  59.745 +
  59.746 +	u32 header = CPUReadMemory(source);
  59.747 +	source += 4;
  59.748 +
  59.749 +	if (((source & 0xe000000) == 0) ||
  59.750 +	    ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
  59.751 +		return;
  59.752 +
  59.753 +	int byteCount  = 0;
  59.754 +	int byteShift  = 0;
  59.755 +	u32 writeValue = 0;
  59.756 +
  59.757 +	int len = header >> 8;
  59.758 +
  59.759 +	while (len > 0)
  59.760 +	{
  59.761 +		u8 d = CPUReadByte(source++);
  59.762 +
  59.763 +		if (d)
  59.764 +		{
  59.765 +			for (int i = 0; i < 8; i++)
  59.766 +			{
  59.767 +				if (d & 0x80)
  59.768 +				{
  59.769 +					u16 data = CPUReadByte(source++) << 8;
  59.770 +					data |= CPUReadByte(source++);
  59.771 +					int length       = (data >> 12) + 3;
  59.772 +					int offset       = (data & 0x0FFF);
  59.773 +					u32 windowOffset = dest + byteCount - offset - 1;
  59.774 +					for (int i = 0; i < length; i++)
  59.775 +					{
  59.776 +						writeValue |= (CPUReadByte(windowOffset++) << byteShift);
  59.777 +						byteShift  += 8;
  59.778 +						byteCount++;
  59.779 +
  59.780 +						if (byteCount == 2)
  59.781 +						{
  59.782 +							CPUWriteHalfWord(dest, writeValue);
  59.783 +							dest      += 2;
  59.784 +							byteCount  = 0;
  59.785 +							byteShift  = 0;
  59.786 +							writeValue = 0;
  59.787 +						}
  59.788 +						len--;
  59.789 +						if (len == 0)
  59.790 +							return;
  59.791 +					}
  59.792 +				}
  59.793 +				else
  59.794 +				{
  59.795 +					writeValue |= (CPUReadByte(source++) << byteShift);
  59.796 +					byteShift  += 8;
  59.797 +					byteCount++;
  59.798 +					if (byteCount == 2)
  59.799 +					{
  59.800 +						CPUWriteHalfWord(dest, writeValue);
  59.801 +						dest      += 2;
  59.802 +						byteCount  = 0;
  59.803 +						byteShift  = 0;
  59.804 +						writeValue = 0;
  59.805 +					}
  59.806 +					len--;
  59.807 +					if (len == 0)
  59.808 +						return;
  59.809 +				}
  59.810 +				d <<= 1;
  59.811 +			}
  59.812 +		}
  59.813 +		else
  59.814 +		{
  59.815 +			for (int i = 0; i < 8; i++)
  59.816 +			{
  59.817 +				writeValue |= (CPUReadByte(source++) << byteShift);
  59.818 +				byteShift  += 8;
  59.819 +				byteCount++;
  59.820 +				if (byteCount == 2)
  59.821 +				{
  59.822 +					CPUWriteHalfWord(dest, writeValue);
  59.823 +					dest      += 2;
  59.824 +					byteShift  = 0;
  59.825 +					byteCount  = 0;
  59.826 +					writeValue = 0;
  59.827 +				}
  59.828 +				len--;
  59.829 +				if (len == 0)
  59.830 +					return;
  59.831 +			}
  59.832 +		}
  59.833 +	}
  59.834 +}
  59.835 +
  59.836 +void BIOS_LZ77UnCompWram()
  59.837 +{
  59.838 +#ifdef GBA_LOGGING
  59.839 +	if (systemVerbose & VERBOSE_SWI)
  59.840 +	{
  59.841 +		log("LZ77UnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
  59.842 +		    VCOUNT);
  59.843 +	}
  59.844 +#endif
  59.845 +
  59.846 +	u32 source = reg[0].I;
  59.847 +	u32 dest   = reg[1].I;
  59.848 +
  59.849 +	u32 header = CPUReadMemory(source);
  59.850 +	source += 4;
  59.851 +
  59.852 +	if (((source & 0xe000000) == 0) ||
  59.853 +	    ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
  59.854 +		return;
  59.855 +
  59.856 +	int len = header >> 8;
  59.857 +
  59.858 +	while (len > 0)
  59.859 +	{
  59.860 +		u8 d = CPUReadByte(source++);
  59.861 +
  59.862 +		if (d)
  59.863 +		{
  59.864 +			for (int i = 0; i < 8; i++)
  59.865 +			{
  59.866 +				if (d & 0x80)
  59.867 +				{
  59.868 +					u16 data = CPUReadByte(source++) << 8;
  59.869 +					data |= CPUReadByte(source++);
  59.870 +					int length       = (data >> 12) + 3;
  59.871 +					int offset       = (data & 0x0FFF);
  59.872 +					u32 windowOffset = dest - offset - 1;
  59.873 +					for (int i = 0; i < length; i++)
  59.874 +					{
  59.875 +						CPUWriteByte(dest++, CPUReadByte(windowOffset++));
  59.876 +						len--;
  59.877 +						if (len == 0)
  59.878 +							return;
  59.879 +					}
  59.880 +				}
  59.881 +				else
  59.882 +				{
  59.883 +					CPUWriteByte(dest++, CPUReadByte(source++));
  59.884 +					len--;
  59.885 +					if (len == 0)
  59.886 +						return;
  59.887 +				}
  59.888 +				d <<= 1;
  59.889 +			}
  59.890 +		}
  59.891 +		else
  59.892 +		{
  59.893 +			for (int i = 0; i < 8; i++)
  59.894 +			{
  59.895 +				CPUWriteByte(dest++, CPUReadByte(source++));
  59.896 +				len--;
  59.897 +				if (len == 0)
  59.898 +					return;
  59.899 +			}
  59.900 +		}
  59.901 +	}
  59.902 +}
  59.903 +
  59.904 +void BIOS_ObjAffineSet()
  59.905 +{
  59.906 +#ifdef GBA_LOGGING
  59.907 +	if (systemVerbose & VERBOSE_SWI)
  59.908 +	{
  59.909 +		log("ObjAffineSet: 0x%08x,0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n",
  59.910 +		    reg[0].I,
  59.911 +		    reg[1].I,
  59.912 +		    reg[2].I,
  59.913 +		    reg[3].I,
  59.914 +		    VCOUNT);
  59.915 +	}
  59.916 +#endif
  59.917 +
  59.918 +	u32 src    = reg[0].I;
  59.919 +	u32 dest   = reg[1].I;
  59.920 +	int num    = reg[2].I;
  59.921 +	int offset = reg[3].I;
  59.922 +
  59.923 +	for (int i = 0; i < num; i++)
  59.924 +	{
  59.925 +		s16 rx = CPUReadHalfWord(src);
  59.926 +		src += 2;
  59.927 +		s16 ry = CPUReadHalfWord(src);
  59.928 +		src += 2;
  59.929 +		u16 theta = CPUReadHalfWord(src)>>8;
  59.930 +		src += 4; // keep structure alignment
  59.931 +
  59.932 +		s32 a = (s32)sineTable[(theta+0x40)&255];
  59.933 +		s32 b = (s32)sineTable[theta];
  59.934 +
  59.935 +		s16 dx  =  (s16)((rx * a)>>14);
  59.936 +		s16 dmx = (s16)((rx * b)>>14);
  59.937 +		s16 dy  =  (s16)((ry * b)>>14);
  59.938 +		s16 dmy = (s16)((ry * a)>>14);
  59.939 +
  59.940 +		CPUWriteHalfWord(dest, dx);
  59.941 +		dest += offset;
  59.942 +		CPUWriteHalfWord(dest, -dmx);
  59.943 +		dest += offset;
  59.944 +		CPUWriteHalfWord(dest, dy);
  59.945 +		dest += offset;
  59.946 +		CPUWriteHalfWord(dest, dmy);
  59.947 +		dest += offset;
  59.948 +	}
  59.949 +}
  59.950 +
  59.951 +void BIOS_RegisterRamReset(u32 flags)
  59.952 +{
  59.953 +	// no need to trace here. this is only called directly from GBA.cpp
  59.954 +	// to emulate bios initialization
  59.955 +
  59.956 +	if (flags)
  59.957 +	{
  59.958 +		if (flags & 0x01)
  59.959 +		{
  59.960 +			// clear work RAM
  59.961 +			memset(workRAM, 0, 0x40000);
  59.962 +		}
  59.963 +		if (flags & 0x02)
  59.964 +		{
  59.965 +			// clear internal RAM
  59.966 +			memset(internalRAM, 0, 0x7e00); // don't clear 0x7e00-0x7fff
  59.967 +		}
  59.968 +		if (flags & 0x04)
  59.969 +		{
  59.970 +			// clear palette RAM
  59.971 +			memset(paletteRAM, 0, 0x400);
  59.972 +		}
  59.973 +		if (flags & 0x08)
  59.974 +		{
  59.975 +			// clear VRAM
  59.976 +			memset(vram, 0, 0x18000);
  59.977 +		}
  59.978 +		if (flags & 0x10)
  59.979 +		{
  59.980 +			// clean OAM
  59.981 +			memset(oam, 0, 0x400);
  59.982 +		}
  59.983 +
  59.984 +		if (flags & 0x80)
  59.985 +		{
  59.986 +			int i;
  59.987 +			for (i = 0; i < 8; i++)
  59.988 +				CPUUpdateRegister(0x200+i*2, 0);
  59.989 +
  59.990 +			CPUUpdateRegister(0x202, 0xFFFF);
  59.991 +
  59.992 +			for (i = 0; i < 8; i++)
  59.993 +				CPUUpdateRegister(0x4+i*2, 0);
  59.994 +
  59.995 +			for (i = 0; i < 16; i++)
  59.996 +				CPUUpdateRegister(0x20+i*2, 0);
  59.997 +
  59.998 +			for (i = 0; i < 24; i++)
  59.999 +				CPUUpdateRegister(0xb0+i*2, 0);
 59.1000 +
 59.1001 +			CPUUpdateRegister(0x130, 0);
 59.1002 +			CPUUpdateRegister(0x20, 0x100);
 59.1003 +			CPUUpdateRegister(0x30, 0x100);
 59.1004 +			CPUUpdateRegister(0x26, 0x100);
 59.1005 +			CPUUpdateRegister(0x36, 0x100);
 59.1006 +		}
 59.1007 +
 59.1008 +		if (flags & 0x20)
 59.1009 +		{
 59.1010 +			int i;
 59.1011 +			for (i = 0; i < 8; i++)
 59.1012 +				CPUUpdateRegister(0x110+i*2, 0);
 59.1013 +			CPUUpdateRegister(0x134, 0x8000);
 59.1014 +			for (i = 0; i < 7; i++)
 59.1015 +				CPUUpdateRegister(0x140+i*2, 0);
 59.1016 +		}
 59.1017 +
 59.1018 +		if (flags & 0x40)
 59.1019 +		{
 59.1020 +			int i;
 59.1021 +			CPUWriteByte(0x4000084, 0);
 59.1022 +			CPUWriteByte(0x4000084, 0x80);
 59.1023 +			CPUWriteMemory(0x4000080, 0x880e0000);
 59.1024 +			CPUUpdateRegister(0x88, CPUReadHalfWord(0x4000088)&0x3ff);
 59.1025 +			CPUWriteByte(0x4000070, 0x70);
 59.1026 +			for (i = 0; i < 8; i++)
 59.1027 +				CPUUpdateRegister(0x90+i*2, 0);
 59.1028 +			CPUWriteByte(0x4000070, 0);
 59.1029 +			for (i = 0; i < 8; i++)
 59.1030 +				CPUUpdateRegister(0x90+i*2, 0);
 59.1031 +			CPUWriteByte(0x4000084, 0);
 59.1032 +		}
 59.1033 +	}
 59.1034 +}
 59.1035 +
 59.1036 +void BIOS_RegisterRamReset()
 59.1037 +{
 59.1038 +#ifdef GBA_LOGGING
 59.1039 +	if (systemVerbose & VERBOSE_SWI)
 59.1040 +	{
 59.1041 +		log("RegisterRamReset: 0x%08x (VCOUNT=%d)\n",
 59.1042 +		    reg[0].I,
 59.1043 +		    VCOUNT);
 59.1044 +	}
 59.1045 +#endif
 59.1046 +
 59.1047 +	BIOS_RegisterRamReset(reg[0].I);
 59.1048 +}
 59.1049 +
 59.1050 +void BIOS_RLUnCompVram()
 59.1051 +{
 59.1052 +#ifdef GBA_LOGGING
 59.1053 +	if (systemVerbose & VERBOSE_SWI)
 59.1054 +	{
 59.1055 +		log("RLUnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n",
 59.1056 +		    reg[0].I,
 59.1057 +		    reg[1].I,
 59.1058 +		    VCOUNT);
 59.1059 +	}
 59.1060 +#endif
 59.1061 +
 59.1062 +	u32 source = reg[0].I;
 59.1063 +	u32 dest   = reg[1].I;
 59.1064 +
 59.1065 +	u32 header = CPUReadMemory(source);
 59.1066 +	source += 4;
 59.1067 +
 59.1068 +	if (((source & 0xe000000) == 0) ||
 59.1069 +	    ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
 59.1070 +		return;
 59.1071 +
 59.1072 +	int len        = header >> 8;
 59.1073 +	int byteCount  = 0;
 59.1074 +	int byteShift  = 0;
 59.1075 +	u32 writeValue = 0;
 59.1076 +
 59.1077 +	while (len > 0)
 59.1078 +	{
 59.1079 +		u8  d = CPUReadByte(source++);
 59.1080 +		int l = d & 0x7F;
 59.1081 +		if (d & 0x80)
 59.1082 +		{
 59.1083 +			u8 data = CPUReadByte(source++);
 59.1084 +			l += 3;
 59.1085 +			for (int i = 0; i < l; i++)
 59.1086 +			{
 59.1087 +				writeValue |= (data << byteShift);
 59.1088 +				byteShift  += 8;
 59.1089 +				byteCount++;
 59.1090 +
 59.1091 +				if (byteCount == 2)
 59.1092 +				{
 59.1093 +					CPUWriteHalfWord(dest, writeValue);
 59.1094 +					dest      += 2;
 59.1095 +					byteCount  = 0;
 59.1096 +					byteShift  = 0;
 59.1097 +					writeValue = 0;
 59.1098 +				}
 59.1099 +				len--;
 59.1100 +				if (len == 0)
 59.1101 +					return;
 59.1102 +			}
 59.1103 +		}
 59.1104 +		else
 59.1105 +		{
 59.1106 +			l++;
 59.1107 +			for (int i = 0; i < l; i++)
 59.1108 +			{
 59.1109 +				writeValue |= (CPUReadByte(source++) << byteShift);
 59.1110 +				byteShift  += 8;
 59.1111 +				byteCount++;
 59.1112 +				if (byteCount == 2)
 59.1113 +				{
 59.1114 +					CPUWriteHalfWord(dest, writeValue);
 59.1115 +					dest      += 2;
 59.1116 +					byteCount  = 0;
 59.1117 +					byteShift  = 0;
 59.1118 +					writeValue = 0;
 59.1119 +				}
 59.1120 +				len--;
 59.1121 +				if (len == 0)
 59.1122 +					return;
 59.1123 +			}
 59.1124 +		}
 59.1125 +	}
 59.1126 +}
 59.1127 +
 59.1128 +void BIOS_RLUnCompWram()
 59.1129 +{
 59.1130 +#ifdef GBA_LOGGING
 59.1131 +	if (systemVerbose & VERBOSE_SWI)
 59.1132 +	{
 59.1133 +		log("RLUnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n",
 59.1134 +		    reg[0].I,
 59.1135 +		    reg[1].I,
 59.1136 +		    VCOUNT);
 59.1137 +	}
 59.1138 +#endif
 59.1139 +
 59.1140 +	u32 source = reg[0].I;
 59.1141 +	u32 dest   = reg[1].I;
 59.1142 +
 59.1143 +	u32 header = CPUReadMemory(source);
 59.1144 +	source += 4;
 59.1145 +
 59.1146 +	if (((source & 0xe000000) == 0) ||
 59.1147 +	    ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
 59.1148 +		return;
 59.1149 +
 59.1150 +	int len = header >> 8;
 59.1151 +
 59.1152 +	while (len > 0)
 59.1153 +	{
 59.1154 +		u8  d = CPUReadByte(source++);
 59.1155 +		int l = d & 0x7F;
 59.1156 +		if (d & 0x80)
 59.1157 +		{
 59.1158 +			u8 data = CPUReadByte(source++);
 59.1159 +			l += 3;
 59.1160 +			for (int i = 0; i < l; i++)
 59.1161 +			{
 59.1162 +				CPUWriteByte(dest++, data);
 59.1163 +				len--;
 59.1164 +				if (len == 0)
 59.1165 +					return;
 59.1166 +			}
 59.1167 +		}
 59.1168 +		else
 59.1169 +		{
 59.1170 +			l++;
 59.1171 +			for (int i = 0; i < l; i++)
 59.1172 +			{
 59.1173 +				CPUWriteByte(dest++,  CPUReadByte(source++));
 59.1174 +				len--;
 59.1175 +				if (len == 0)
 59.1176 +					return;
 59.1177 +			}
 59.1178 +		}
 59.1179 +	}
 59.1180 +}
 59.1181 +
 59.1182 +void BIOS_SoftReset()
 59.1183 +{
 59.1184 +#ifdef GBA_LOGGING
 59.1185 +	if (systemVerbose & VERBOSE_SWI)
 59.1186 +	{
 59.1187 +		log("SoftReset: (VCOUNT=%d)\n", VCOUNT);
 59.1188 +	}
 59.1189 +#endif
 59.1190 +
 59.1191 +	armState        = true;
 59.1192 +	armMode         = 0x1F;
 59.1193 +	armIrqEnable    = false;
 59.1194 +	C_FLAG          = V_FLAG = N_FLAG = Z_FLAG = false;
 59.1195 +	reg[13].I       = 0x03007F00;
 59.1196 +	reg[14].I       = 0x00000000;
 59.1197 +	reg[16].I       = 0x00000000;
 59.1198 +	reg[R13_IRQ].I  = 0x03007FA0;
 59.1199 +	reg[R14_IRQ].I  = 0x00000000;
 59.1200 +	reg[SPSR_IRQ].I = 0x00000000;
 59.1201 +	reg[R13_SVC].I  = 0x03007FE0;
 59.1202 +	reg[R14_SVC].I  = 0x00000000;
 59.1203 +	reg[SPSR_SVC].I = 0x00000000;
 59.1204 +	u8 b = internalRAM[0x7ffa];
 59.1205 +
 59.1206 +	memset(&internalRAM[0x7e00], 0, 0x200);
 59.1207 +
 59.1208 +	if (b)
 59.1209 +	{
 59.1210 +		armNextPC = 0x02000000;
 59.1211 +		reg[15].I = 0x02000004;
 59.1212 +	}
 59.1213 +	else
 59.1214 +	{
 59.1215 +		armNextPC = 0x08000000;
 59.1216 +		reg[15].I = 0x08000004;
 59.1217 +	}
 59.1218 +}
 59.1219 +
 59.1220 +void BIOS_Sqrt()
 59.1221 +{
 59.1222 +#ifdef GBA_LOGGING
 59.1223 +	if (systemVerbose & VERBOSE_SWI)
 59.1224 +	{
 59.1225 +		log("Sqrt: %08x (VCOUNT=%2d)\n",
 59.1226 +		    reg[0].I,
 59.1227 +		    VCOUNT);
 59.1228 +	}
 59.1229 +#endif
 59.1230 +	reg[0].I = (u32)sqrt((double)reg[0].I);
 59.1231 +#ifdef GBA_LOGGING
 59.1232 +	if (systemVerbose & VERBOSE_SWI)
 59.1233 +	{
 59.1234 +		log("Sqrt: return=%08x\n",
 59.1235 +		    reg[0].I);
 59.1236 +	}
 59.1237 +#endif
 59.1238 +}
 59.1239 +
 59.1240 +void BIOS_MidiKey2Freq()
 59.1241 +{
 59.1242 +#ifdef GBA_LOGGING
 59.1243 +	if (systemVerbose & VERBOSE_SWI)
 59.1244 +	{
 59.1245 +		log("MidiKey2Freq: WaveData=%08x mk=%08x fp=%08x\n",
 59.1246 +		    reg[0].I,
 59.1247 +		    reg[1].I,
 59.1248 +		    reg[2].I);
 59.1249 +	}
 59.1250 +#endif
 59.1251 +	int    freq = CPUReadMemory(reg[0].I+4);
 59.1252 +	double tmp;
 59.1253 +	tmp      = ((double)(180 - reg[1].I)) - ((double)reg[2].I / 256.f);
 59.1254 +	tmp      = pow((double)2.f, tmp / 12.f);
 59.1255 +	reg[0].I = (int)((double)freq / tmp);
 59.1256 +
 59.1257 +#ifdef GBA_LOGGING
 59.1258 +	if (systemVerbose & VERBOSE_SWI)
 59.1259 +	{
 59.1260 +		log("MidiKey2Freq: return %08x\n",
 59.1261 +		    reg[0].I);
 59.1262 +	}
 59.1263 +#endif
 59.1264 +}
 59.1265 +
 59.1266 +void BIOS_SndDriverJmpTableCopy()
 59.1267 +{
 59.1268 +#ifdef GBA_LOGGING
 59.1269 +	if (systemVerbose & VERBOSE_SWI)
 59.1270 +	{
 59.1271 +		log("SndDriverJmpTableCopy: dest=%08x\n",
 59.1272 +		    reg[0].I);
 59.1273 +	}
 59.1274 +#endif
 59.1275 +	for (int i = 0; i < 0x24; i++)
 59.1276 +	{
 59.1277 +		CPUWriteMemory(reg[0].I, 0x9c);
 59.1278 +		reg[0].I += 4;
 59.1279 +	}
 59.1280 +}
 59.1281 +
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/src/gba/bios.h	Sun Mar 04 14:33:52 2012 -0600
    60.3 @@ -0,0 +1,34 @@
    60.4 +#ifndef VBA_BIOS_H
    60.5 +#define VBA_BIOS_H
    60.6 +
    60.7 +#if _MSC_VER > 1000
    60.8 +#pragma once
    60.9 +#endif // _MSC_VER > 1000
   60.10 +
   60.11 +#include "../Port.h"
   60.12 +
   60.13 +extern void BIOS_ArcTan();
   60.14 +extern void BIOS_ArcTan2();
   60.15 +extern void BIOS_BitUnPack();
   60.16 +extern void BIOS_BgAffineSet();
   60.17 +extern void BIOS_CpuSet();
   60.18 +extern void BIOS_CpuFastSet();
   60.19 +extern void BIOS_Diff8bitUnFilterWram();
   60.20 +extern void BIOS_Diff8bitUnFilterVram();
   60.21 +extern void BIOS_Diff16bitUnFilter();
   60.22 +extern void BIOS_Div();
   60.23 +extern void BIOS_DivARM();
   60.24 +extern void BIOS_HuffUnComp();
   60.25 +extern void BIOS_LZ77UnCompVram();
   60.26 +extern void BIOS_LZ77UnCompWram();
   60.27 +extern void BIOS_ObjAffineSet();
   60.28 +extern void BIOS_RegisterRamReset();
   60.29 +extern void BIOS_RegisterRamReset(u32);
   60.30 +extern void BIOS_RLUnCompVram();
   60.31 +extern void BIOS_RLUnCompWram();
   60.32 +extern void BIOS_SoftReset();
   60.33 +extern void BIOS_Sqrt();
   60.34 +extern void BIOS_MidiKey2Freq();
   60.35 +extern void BIOS_SndDriverJmpTableCopy();
   60.36 +
   60.37 +#endif // VBA_BIOS_H
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/src/gba/elf.cpp	Sun Mar 04 14:33:52 2012 -0600
    61.3 @@ -0,0 +1,3229 @@
    61.4 +#include <cstdio>
    61.5 +#include <cstdlib>
    61.6 +#include <cstring>
    61.7 +
    61.8 +#include "../Port.h"
    61.9 +#include "../NLS.h"
   61.10 +#include "../common/System.h" // systemMessage
   61.11 +#include "GBAGlobals.h"
   61.12 +#include "elf.h"
   61.13 +
   61.14 +#define elfReadMemory(addr) \
   61.15 +    READ32LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
   61.16 +
   61.17 +#define DW_TAG_array_type             0x01
   61.18 +#define DW_TAG_enumeration_type       0x04
   61.19 +#define DW_TAG_formal_parameter       0x05
   61.20 +#define DW_TAG_label                  0x0a
   61.21 +#define DW_TAG_lexical_block          0x0b
   61.22 +#define DW_TAG_member                 0x0d
   61.23 +#define DW_TAG_pointer_type           0x0f
   61.24 +#define DW_TAG_reference_type         0x10
   61.25 +#define DW_TAG_compile_unit           0x11
   61.26 +#define DW_TAG_structure_type         0x13
   61.27 +#define DW_TAG_subroutine_type        0x15
   61.28 +#define DW_TAG_typedef                0x16
   61.29 +#define DW_TAG_union_type             0x17
   61.30 +#define DW_TAG_unspecified_parameters 0x18
   61.31 +#define DW_TAG_inheritance            0x1c
   61.32 +#define DW_TAG_inlined_subroutine     0x1d
   61.33 +#define DW_TAG_subrange_type          0x21
   61.34 +#define DW_TAG_base_type              0x24
   61.35 +#define DW_TAG_const_type             0x26
   61.36 +#define DW_TAG_enumerator             0x28
   61.37 +#define DW_TAG_subprogram             0x2e
   61.38 +#define DW_TAG_variable               0x34
   61.39 +#define DW_TAG_volatile_type          0x35
   61.40 +
   61.41 +#define DW_AT_sibling              0x01
   61.42 +#define DW_AT_location             0x02
   61.43 +#define DW_AT_name                 0x03
   61.44 +#define DW_AT_byte_size            0x0b
   61.45 +#define DW_AT_bit_offset           0x0c
   61.46 +#define DW_AT_bit_size             0x0d
   61.47 +#define DW_AT_stmt_list            0x10
   61.48 +#define DW_AT_low_pc               0x11
   61.49 +#define DW_AT_high_pc              0x12
   61.50 +#define DW_AT_language             0x13
   61.51 +#define DW_AT_compdir              0x1b
   61.52 +#define DW_AT_const_value          0x1c
   61.53 +#define DW_AT_containing_type      0x1d
   61.54 +#define DW_AT_inline               0x20
   61.55 +#define DW_AT_producer             0x25
   61.56 +#define DW_AT_prototyped           0x27
   61.57 +#define DW_AT_upper_bound          0x2f
   61.58 +#define DW_AT_abstract_origin      0x31
   61.59 +#define DW_AT_accessibility        0x32
   61.60 +#define DW_AT_artificial           0x34
   61.61 +#define DW_AT_data_member_location 0x38
   61.62 +#define DW_AT_decl_file            0x3a
   61.63 +#define DW_AT_decl_line            0x3b
   61.64 +#define DW_AT_declaration          0x3c
   61.65 +#define DW_AT_encoding             0x3e
   61.66 +#define DW_AT_external             0x3f
   61.67 +#define DW_AT_frame_base           0x40
   61.68 +#define DW_AT_macro_info           0x43
   61.69 +#define DW_AT_specification        0x47
   61.70 +#define DW_AT_type                 0x49
   61.71 +#define DW_AT_virtuality           0x4c
   61.72 +#define DW_AT_vtable_elem_location 0x4d
   61.73 +// DWARF 2.1/3.0 extensions
   61.74 +#define DW_AT_entry_pc             0x52
   61.75 +#define DW_AT_ranges               0x55
   61.76 +// ARM Compiler extensions
   61.77 +#define DW_AT_proc_body            0x2000
   61.78 +#define DW_AT_save_offset          0x2001
   61.79 +#define DW_AT_user_2002            0x2002
   61.80 +// MIPS extensions
   61.81 +#define DW_AT_MIPS_linkage_name    0x2007
   61.82 +
   61.83 +#define DW_FORM_addr      0x01
   61.84 +#define DW_FORM_data2     0x05
   61.85 +#define DW_FORM_data4     0x06
   61.86 +#define DW_FORM_string    0x08
   61.87 +#define DW_FORM_block     0x09
   61.88 +#define DW_FORM_block1    0x0a
   61.89 +#define DW_FORM_data1     0x0b
   61.90 +#define DW_FORM_flag      0x0c
   61.91 +#define DW_FORM_sdata     0x0d
   61.92 +#define DW_FORM_strp      0x0e
   61.93 +#define DW_FORM_udata     0x0f
   61.94 +#define DW_FORM_ref_addr  0x10
   61.95 +#define DW_FORM_ref4      0x13
   61.96 +#define DW_FORM_ref_udata 0x15
   61.97 +#define DW_FORM_indirect  0x16
   61.98 +
   61.99 +#define DW_OP_addr        0x03
  61.100 +#define DW_OP_plus_uconst 0x23
  61.101 +#define DW_OP_reg0        0x50
  61.102 +#define DW_OP_reg1        0x51
  61.103 +#define DW_OP_reg2        0x52
  61.104 +#define DW_OP_reg3        0x53
  61.105 +#define DW_OP_reg4        0x54
  61.106 +#define DW_OP_reg5        0x55
  61.107 +#define DW_OP_reg6        0x56
  61.108 +#define DW_OP_reg7        0x57
  61.109 +#define DW_OP_reg8        0x58
  61.110 +#define DW_OP_reg9        0x59
  61.111 +#define DW_OP_reg10       0x5a
  61.112 +#define DW_OP_reg11       0x5b
  61.113 +#define DW_OP_reg12       0x5c
  61.114 +#define DW_OP_reg13       0x5d
  61.115 +#define DW_OP_reg14       0x5e
  61.116 +#define DW_OP_reg15       0x5f
  61.117 +#define DW_OP_fbreg       0x91
  61.118 +
  61.119 +#define DW_LNS_extended_op      0x00
  61.120 +#define DW_LNS_copy             0x01
  61.121 +#define DW_LNS_advance_pc       0x02
  61.122 +#define DW_LNS_advance_line     0x03
  61.123 +#define DW_LNS_set_file         0x04
  61.124 +#define DW_LNS_set_column       0x05
  61.125 +#define DW_LNS_negate_stmt      0x06
  61.126 +#define DW_LNS_set_basic_block  0x07
  61.127 +#define DW_LNS_const_add_pc     0x08
  61.128 +#define DW_LNS_fixed_advance_pc 0x09
  61.129 +
  61.130 +#define DW_LNE_end_sequence 0x01
  61.131 +#define DW_LNE_set_address  0x02
  61.132 +#define DW_LNE_define_file  0x03
  61.133 +
  61.134 +#define DW_CFA_advance_loc      0x01
  61.135 +#define DW_CFA_offset           0x02
  61.136 +#define DW_CFA_restore          0x03
  61.137 +#define DW_CFA_set_loc          0x01
  61.138 +#define DW_CFA_advance_loc1     0x02
  61.139 +#define DW_CFA_advance_loc2     0x03
  61.140 +#define DW_CFA_advance_loc4     0x04
  61.141 +#define DW_CFA_offset_extended  0x05
  61.142 +#define DW_CFA_restore_extended 0x06
  61.143 +#define DW_CFA_undefined        0x07
  61.144 +#define DW_CFA_same_value       0x08
  61.145 +#define DW_CFA_register         0x09
  61.146 +#define DW_CFA_remember_state   0x0a
  61.147 +#define DW_CFA_restore_state    0x0b
  61.148 +#define DW_CFA_def_cfa          0x0c
  61.149 +#define DW_CFA_def_cfa_register 0x0d
  61.150 +#define DW_CFA_def_cfa_offset   0x0e
  61.151 +#define DW_CFA_nop              0x00
  61.152 +
  61.153 +#define CASE_TYPE_TAG \
  61.154 +case DW_TAG_const_type: \
  61.155 +case DW_TAG_volatile_type: \
  61.156 +case DW_TAG_pointer_type: \
  61.157 +case DW_TAG_base_type: \
  61.158 +case DW_TAG_array_type: \
  61.159 +case DW_TAG_structure_type: \
  61.160 +case DW_TAG_union_type: \
  61.161 +case DW_TAG_typedef: \
  61.162 +case DW_TAG_subroutine_type: \
  61.163 +case DW_TAG_enumeration_type: \
  61.164 +case DW_TAG_enumerator: \
  61.165 +case DW_TAG_reference_type
  61.166 +
  61.167 +struct ELFcie
  61.168 +{
  61.169 +	ELFcie *next;
  61.170 +	u32     offset;
  61.171 +	u8 *    augmentation;
  61.172 +	u32     codeAlign;
  61.173 +	s32     dataAlign;
  61.174 +	int     returnAddress;
  61.175 +	u8 *    data;
  61.176 +	u32     dataLen;
  61.177 +};
  61.178 +
  61.179 +struct ELFfde
  61.180 +{
  61.181 +	ELFcie *cie;
  61.182 +	u32     address;
  61.183 +	u32     end;
  61.184 +	u8 *    data;
  61.185 +	u32     dataLen;
  61.186 +};
  61.187 +
  61.188 +enum ELFRegMode
  61.189 +{
  61.190 +	REG_NOT_SET,
  61.191 +	REG_OFFSET,
  61.192 +	REG_REGISTER
  61.193 +};
  61.194 +
  61.195 +struct ELFFrameStateRegister
  61.196 +{
  61.197 +	ELFRegMode mode;
  61.198 +	int        reg;
  61.199 +	s32        offset;
  61.200 +};
  61.201 +
  61.202 +struct ELFFrameStateRegisters
  61.203 +{
  61.204 +	ELFFrameStateRegister   regs[16];
  61.205 +	ELFFrameStateRegisters *previous;
  61.206 +};
  61.207 +
  61.208 +enum ELFCfaMode
  61.209 +{
  61.210 +	CFA_NOT_SET,
  61.211 +	CFA_REG_OFFSET
  61.212 +};
  61.213 +
  61.214 +struct ELFFrameState
  61.215 +{
  61.216 +	ELFFrameStateRegisters registers;
  61.217 +
  61.218 +	ELFCfaMode cfaMode;
  61.219 +	int        cfaRegister;
  61.220 +	s32        cfaOffset;
  61.221 +
  61.222 +	u32 pc;
  61.223 +
  61.224 +	int dataAlign;
  61.225 +	int codeAlign;
  61.226 +	int returnAddress;
  61.227 +};
  61.228 +
  61.229 +extern bool8 cpuIsMultiBoot;
  61.230 +
  61.231 +Symbol *elfSymbols       = NULL;
  61.232 +char *  elfSymbolsStrTab = NULL;
  61.233 +int     elfSymbolsCount  = 0;
  61.234 +
  61.235 +ELFSectionHeader **elfSectionHeaders = NULL;
  61.236 +char *elfSectionHeadersStringTable   = NULL;
  61.237 +int   elfSectionHeadersCount         = 0;
  61.238 +u8 *  elfFileData = NULL;
  61.239 +
  61.240 +CompileUnit *elfCompileUnits = NULL;
  61.241 +DebugInfo *  elfDebugInfo    = NULL;
  61.242 +char *       elfDebugStrings = NULL;
  61.243 +
  61.244 +ELFcie * elfCies     = NULL;
  61.245 +ELFfde **elfFdes     = NULL;
  61.246 +int      elfFdeCount = 0;
  61.247 +
  61.248 +CompileUnit *elfCurrentUnit = NULL;
  61.249 +
  61.250 +u32 elfRead4Bytes(u8 *);
  61.251 +u16 elfRead2Bytes(u8 *);
  61.252 +
  61.253 +CompileUnit *elfGetCompileUnit(u32 addr)
  61.254 +{
  61.255 +	if (elfCompileUnits)
  61.256 +	{
  61.257 +		CompileUnit *unit = elfCompileUnits;
  61.258 +		while (unit)
  61.259 +		{
  61.260 +			if (unit->lowPC)
  61.261 +			{
  61.262 +				if (addr >= unit->lowPC && addr < unit->highPC)
  61.263 +					return unit;
  61.264 +			}
  61.265 +			else
  61.266 +			{
  61.267 +				ARanges *r = unit->ranges;
  61.268 +				if (r)
  61.269 +				{
  61.270 +					int count = r->count;
  61.271 +					for (int j = 0; j < count; j++)
  61.272 +					{
  61.273 +						if (addr >= r->ranges[j].lowPC && addr < r->ranges[j].highPC)
  61.274 +							return unit;
  61.275 +					}
  61.276 +				}
  61.277 +			}
  61.278 +			unit = unit->next;
  61.279 +		}
  61.280 +	}
  61.281 +	return NULL;
  61.282 +}
  61.283 +
  61.284 +char *elfGetAddressSymbol(u32 addr)
  61.285 +{
  61.286 +	static char buffer[256];
  61.287 +
  61.288 +	CompileUnit *unit = elfGetCompileUnit(addr);
  61.289 +	// found unit, need to find function
  61.290 +	if (unit)
  61.291 +	{
  61.292 +		Function *func = unit->functions;
  61.293 +		while (func)
  61.294 +		{
  61.295 +			if (addr >= func->lowPC && addr < func->highPC)
  61.296 +			{
  61.297 +				int   offset = addr - func->lowPC;
  61.298 +				char *name   = func->name;
  61.299 +				if (!name)
  61.300 +					name = "";
  61.301 +				if (offset)
  61.302 +					sprintf(buffer, "%s+%d", name, offset);
  61.303 +				else
  61.304 +					strcpy(buffer, name);
  61.305 +				return buffer;
  61.306 +			}
  61.307 +			func = func->next;
  61.308 +		}
  61.309 +	}
  61.310 +
  61.311 +	if (elfSymbolsCount)
  61.312 +	{
  61.313 +		for (int i = 0; i < elfSymbolsCount; i++)
  61.314 +		{
  61.315 +			Symbol *s = &elfSymbols[i];
  61.316 +			if ((addr >= s->value)  && addr < (s->value+s->size))
  61.317 +			{
  61.318 +				int   offset = addr-s->value;
  61.319 +				char *name   = s->name;
  61.320 +				if (name == NULL)
  61.321 +					name = "";
  61.322 +				if (offset)
  61.323 +					sprintf(buffer, "%s+%d", name, addr-s->value);
  61.324 +				else
  61.325 +					strcpy(buffer, name);
  61.326 +				return buffer;
  61.327 +			}
  61.328 +			else if (addr == s->value)
  61.329 +			{
  61.330 +				if (s->name)
  61.331 +					strcpy(buffer, s->name);
  61.332 +				else
  61.333 +					strcpy(buffer, "");
  61.334 +				return buffer;
  61.335 +			}
  61.336 +		}
  61.337 +	}
  61.338 +
  61.339 +	return "";
  61.340 +}
  61.341 +
  61.342 +bool elfFindLineInModule(u32 *addr, char *name, int line)
  61.343 +{
  61.344 +	CompileUnit *unit = elfCompileUnits;
  61.345 +
  61.346 +	while (unit)
  61.347 +	{
  61.348 +		if (unit->lineInfoTable)
  61.349 +		{
  61.350 +			int   i;
  61.351 +			int   count = unit->lineInfoTable->fileCount;
  61.352 +			char *found = NULL;
  61.353 +			for (i = 0; i < count; i++)
  61.354 +			{
  61.355 +				if (strcmp(name, unit->lineInfoTable->files[i]) == 0)
  61.356 +				{
  61.357 +					found = unit->lineInfoTable->files[i];
  61.358 +					break;
  61.359 +				}
  61.360 +			}
  61.361 +			// found a matching filename... try to find line now
  61.362 +			if (found)
  61.363 +			{
  61.364 +				LineInfoItem *table = unit->lineInfoTable->lines;
  61.365 +				count = unit->lineInfoTable->number;
  61.366 +				for (i = 0; i < count; i++)
  61.367 +				{
  61.368 +					if (table[i].file == found && table[i].line == line)
  61.369 +					{
  61.370 +						*addr = table[i].address;
  61.371 +						return true;
  61.372 +					}
  61.373 +				}
  61.374 +				// we can only find a single match
  61.375 +				return false;
  61.376 +			}
  61.377 +		}
  61.378 +		unit = unit->next;
  61.379 +	}
  61.380 +	return false;
  61.381 +}
  61.382 +
  61.383 +int elfFindLine(CompileUnit *unit, Function * /* func */, u32 addr, char **f)
  61.384 +{
  61.385 +	int currentLine = -1;
  61.386 +	if (unit->hasLineInfo)
  61.387 +	{
  61.388 +		int count = unit->lineInfoTable->number;
  61.389 +		LineInfoItem *table = unit->lineInfoTable->lines;
  61.390 +		int i;
  61.391 +		for (i = 0; i < count; i++)
  61.392 +		{
  61.393 +			if (addr <= table[i].address)
  61.394 +				break;
  61.395 +		}
  61.396 +		if (i == count)
  61.397 +			i--;
  61.398 +		*f = table[i].file;
  61.399 +		currentLine = table[i].line;
  61.400 +	}
  61.401 +	return currentLine;
  61.402 +}
  61.403 +
  61.404 +bool elfFindLineInUnit(u32 *addr, CompileUnit *unit, int line)
  61.405 +{
  61.406 +	if (unit->hasLineInfo)
  61.407 +	{
  61.408 +		int count = unit->lineInfoTable->number;
  61.409 +		LineInfoItem *table = unit->lineInfoTable->lines;
  61.410 +		int i;
  61.411 +		for (i = 0; i < count; i++)
  61.412 +		{
  61.413 +			if (line == table[i].line)
  61.414 +			{
  61.415 +				*addr = table[i].address;
  61.416 +				return true;
  61.417 +			}
  61.418 +		}
  61.419 +	}
  61.420 +	return false;
  61.421 +}
  61.422 +
  61.423 +bool elfGetCurrentFunction(u32 addr, Function **f, CompileUnit **u)
  61.424 +{
  61.425 +	CompileUnit *unit = elfGetCompileUnit(addr);
  61.426 +	// found unit, need to find function
  61.427 +	if (unit)
  61.428 +	{
  61.429 +		Function *func = unit->functions;
  61.430 +		while (func)
  61.431 +		{
  61.432 +			if (addr >= func->lowPC && addr < func->highPC)
  61.433 +			{
  61.434 +				*f = func;
  61.435 +				*u = unit;
  61.436 +				return true;
  61.437 +			}
  61.438 +			func = func->next;
  61.439 +		}
  61.440 +	}
  61.441 +	return false;
  61.442 +}
  61.443 +
  61.444 +bool elfGetObject(char *name, Function *f, CompileUnit *u, Object **o)
  61.445 +{
  61.446 +	if (f && u)
  61.447 +	{
  61.448 +		Object *v = f->variables;
  61.449 +
  61.450 +		while (v)
  61.451 +		{
  61.452 +			if (strcmp(name, v->name) == 0)
  61.453 +			{
  61.454 +				*o = v;
  61.455 +				return true;
  61.456 +			}
  61.457 +			v = v->next;
  61.458 +		}
  61.459 +		v = f->parameters;
  61.460 +		while (v)
  61.461 +		{
  61.462 +			if (strcmp(name, v->name) == 0)
  61.463 +			{
  61.464 +				*o = v;
  61.465 +				return true;
  61.466 +			}
  61.467 +			v = v->next;
  61.468 +		}
  61.469 +		v = u->variables;
  61.470 +		while (v)
  61.471 +		{
  61.472 +			if (strcmp(name, v->name) == 0)
  61.473 +			{
  61.474 +				*o = v;
  61.475 +				return true;
  61.476 +			}
  61.477 +			v = v->next;
  61.478 +		}
  61.479 +	}
  61.480 +
  61.481 +	CompileUnit *c = elfCompileUnits;
  61.482 +
  61.483 +	while (c)
  61.484 +	{
  61.485 +		if (c != u)
  61.486 +		{
  61.487 +			Object *v = c->variables;
  61.488 +			while (v)
  61.489 +			{
  61.490 +				if (strcmp(name, v->name) == 0)
  61.491 +				{
  61.492 +					*o = v;
  61.493 +					return true;
  61.494 +				}
  61.495 +				v = v->next;
  61.496 +			}
  61.497 +		}
  61.498 +		c = c->next;
  61.499 +	}
  61.500 +
  61.501 +	return false;
  61.502 +}
  61.503 +
  61.504 +char *elfGetSymbol(int i, u32 *value, u32 *size, int *type)
  61.505 +{
  61.506 +	if (i < elfSymbolsCount)
  61.507 +	{
  61.508 +		Symbol *s = &elfSymbols[i];
  61.509 +		*value = s->value;
  61.510 +		*size  = s->size;
  61.511 +		*type  = s->type;
  61.512 +		return s->name;
  61.513 +	}
  61.514 +	return NULL;
  61.515 +}
  61.516 +
  61.517 +bool elfGetSymbolAddress(char *sym, u32 *addr, u32 *size, int *type)
  61.518 +{
  61.519 +	if (elfSymbolsCount)
  61.520 +	{
  61.521 +		for (int i = 0; i < elfSymbolsCount; i++)
  61.522 +		{
  61.523 +			Symbol *s = &elfSymbols[i];
  61.524 +			if (strcmp(sym, s->name) == 0)
  61.525 +			{
  61.526 +				*addr = s->value;
  61.527 +				*size = s->size;
  61.528 +				*type = s->type;
  61.529 +				return true;
  61.530 +			}
  61.531 +		}
  61.532 +	}
  61.533 +	return false;
  61.534 +}
  61.535 +
  61.536 +ELFfde *elfGetFde(u32 address)
  61.537 +{
  61.538 +	if (elfFdes)
  61.539 +	{
  61.540 +		int i;
  61.541 +		for (i = 0; i < elfFdeCount; i++)
  61.542 +		{
  61.543 +			if (address >= elfFdes[i]->address &&
  61.544 +			    address < elfFdes[i]->end)
  61.545 +			{
  61.546 +				return elfFdes[i];
  61.547 +			}
  61.548 +		}
  61.549 +	}
  61.550 +
  61.551 +	return NULL;
  61.552 +}
  61.553 +
  61.554 +void elfExecuteCFAInstructions(ELFFrameState *state, u8 *data, u32 len,
  61.555 +                               u32 pc)
  61.556 +{
  61.557 +	u8 *end = data + len;
  61.558 +	int bytes;
  61.559 +	int reg;
  61.560 +	ELFFrameStateRegisters *fs;
  61.561 +
  61.562 +	while (data < end && state->pc < pc)
  61.563 +	{
  61.564 +		u8 op = *data++;
  61.565 +
  61.566 +		switch (op >> 6)
  61.567 +		{
  61.568 +		case DW_CFA_advance_loc:
  61.569 +			state->pc += (op & 0x3f) * state->codeAlign;
  61.570 +			break;
  61.571 +		case DW_CFA_offset:
  61.572 +			reg = op & 0x3f;
  61.573 +			state->registers.regs[reg].mode   = REG_OFFSET;
  61.574 +			state->registers.regs[reg].offset = state->dataAlign *
  61.575 +			                                    (s32)elfReadLEB128(data, &bytes);
  61.576 +			data += bytes;
  61.577 +			break;
  61.578 +		case DW_CFA_restore:
  61.579 +			// we don't care much about the other possible settings,
  61.580 +			// so just setting to unset is enough for now
  61.581 +			state->registers.regs[op & 0x3f].mode = REG_NOT_SET;
  61.582 +			break;
  61.583 +		case 0:
  61.584 +			switch (op & 0x3f)
  61.585 +			{
  61.586 +			case DW_CFA_nop:
  61.587 +				break;
  61.588 +			case DW_CFA_advance_loc1:
  61.589 +				state->pc += state->codeAlign * (*data++);
  61.590 +				break;
  61.591 +			case DW_CFA_advance_loc2:
  61.592 +				state->pc += state->codeAlign * elfRead2Bytes(data);
  61.593 +				data      += 2;
  61.594 +				break;
  61.595 +			case DW_CFA_advance_loc4:
  61.596 +				state->pc += state->codeAlign * elfRead4Bytes(data);
  61.597 +				data      += 4;
  61.598 +				break;
  61.599 +			case DW_CFA_offset_extended:
  61.600 +				reg   = elfReadLEB128(data, &bytes);
  61.601 +				data += bytes;
  61.602 +				state->registers.regs[reg].mode   = REG_OFFSET;
  61.603 +				state->registers.regs[reg].offset = state->dataAlign *
  61.604 +				                                    (s32)elfReadLEB128(data, &bytes);
  61.605 +				data += bytes;
  61.606 +				break;
  61.607 +			case DW_CFA_restore_extended:
  61.608 +			case DW_CFA_undefined:
  61.609 +			case DW_CFA_same_value:
  61.610 +				reg   = elfReadLEB128(data, &bytes);
  61.611 +				data += bytes;
  61.612 +				state->registers.regs[reg].mode = REG_NOT_SET;
  61.613 +				break;
  61.614 +			case DW_CFA_register:
  61.615 +				reg   = elfReadLEB128(data, &bytes);
  61.616 +				data += bytes;
  61.617 +				state->registers.regs[reg].mode = REG_REGISTER;
  61.618 +				state->registers.regs[reg].reg  = elfReadLEB128(data, &bytes);
  61.619 +				data += bytes;
  61.620 +				break;
  61.621 +			case DW_CFA_remember_state:
  61.622 +				fs = (ELFFrameStateRegisters *)calloc(1,
  61.623 +				                                      sizeof(ELFFrameStateRegisters));
  61.624 +				memcpy(fs, &state->registers, sizeof(ELFFrameStateRegisters));
  61.625 +				state->registers.previous = fs;
  61.626 +				break;
  61.627 +			case DW_CFA_restore_state:
  61.628 +				if (state->registers.previous == NULL)
  61.629 +				{
  61.630 +					printf("Error: previous frame state is NULL.\n");
  61.631 +					return;
  61.632 +				}
  61.633 +				fs = state->registers.previous;
  61.634 +				memcpy(&state->registers, fs, sizeof(ELFFrameStateRegisters));
  61.635 +				free(fs);
  61.636 +				break;
  61.637 +			case DW_CFA_def_cfa:
  61.638 +				state->cfaRegister = elfReadLEB128(data, &bytes);
  61.639 +				data += bytes;
  61.640 +				state->cfaOffset = (s32)elfReadLEB128(data, &bytes);
  61.641 +				data += bytes;
  61.642 +				state->cfaMode = CFA_REG_OFFSET;
  61.643 +				break;
  61.644 +			case DW_CFA_def_cfa_register:
  61.645 +				state->cfaRegister = elfReadLEB128(data, &bytes);
  61.646 +				data += bytes;
  61.647 +				state->cfaMode = CFA_REG_OFFSET;
  61.648 +				break;
  61.649 +			case DW_CFA_def_cfa_offset:
  61.650 +				state->cfaOffset = (s32)elfReadLEB128(data, &bytes);
  61.651 +				data += bytes;
  61.652 +				state->cfaMode = CFA_REG_OFFSET;
  61.653 +				break;
  61.654 +			default:
  61.655 +				printf("Unknown CFA opcode %08x\n", op);
  61.656 +				return;
  61.657 +			}
  61.658 +			break;
  61.659 +		default:
  61.660 +			printf("Unknown CFA opcode %08x\n", op);
  61.661 +			return;
  61.662 +		}
  61.663 +	}
  61.664 +}
  61.665 +
  61.666 +ELFFrameState *elfGetFrameState(ELFfde *fde, u32 address)
  61.667 +{
  61.668 +	ELFFrameState *state = (ELFFrameState *)calloc(1, sizeof(ELFFrameState));
  61.669 +	state->pc            = fde->address;
  61.670 +	state->dataAlign     = fde->cie->dataAlign;
  61.671 +	state->codeAlign     = fde->cie->codeAlign;
  61.672 +	state->returnAddress = fde->cie->returnAddress;
  61.673 +
  61.674 +	elfExecuteCFAInstructions(state,
  61.675 +	                          fde->cie->data,
  61.676 +	                          fde->cie->dataLen,
  61.677 +	                          0xffffffff);
  61.678 +	elfExecuteCFAInstructions(state,
  61.679 +	                          fde->data,
  61.680 +	                          fde->dataLen,
  61.681 +	                          address);
  61.682 +
  61.683 +	return state;
  61.684 +}
  61.685 +
  61.686 +void elfPrintCallChain(u32 address)
  61.687 +{
  61.688 +	int count = 1;
  61.689 +
  61.690 +	reg_pair regs[15];
  61.691 +	reg_pair newRegs[15];
  61.692 +
  61.693 +	memcpy(&regs[0], &reg[0], sizeof(reg_pair) * 15);
  61.694 +
  61.695 +	while (count < 20)
  61.696 +	{
  61.697 +		char *addr = elfGetAddressSymbol(address);
  61.698 +		if (*addr == 0)
  61.699 +			addr = "???";
  61.700 +
  61.701 +		printf("%08x %s\n", address, addr);
  61.702 +
  61.703 +		ELFfde *fde = elfGetFde(address);
  61.704 +
  61.705 +		if (fde == NULL)
  61.706 +		{
  61.707 +			break;
  61.708 +		}
  61.709 +
  61.710 +		ELFFrameState *state = elfGetFrameState(fde, address);
  61.711 +
  61.712 +		if (!state)
  61.713 +		{
  61.714 +			break;
  61.715 +		}
  61.716 +
  61.717 +		if (state->cfaMode == CFA_REG_OFFSET)
  61.718 +		{
  61.719 +			memcpy(&newRegs[0], &regs[0], sizeof(reg_pair) * 15);
  61.720 +			u32 addr = 0;
  61.721 +			for (int i = 0; i < 15; i++)
  61.722 +			{
  61.723 +				ELFFrameStateRegister *r = &state->registers.
  61.724 +				                           regs[i];
  61.725 +
  61.726 +				switch (r->mode)
  61.727 +				{
  61.728 +				case REG_NOT_SET:
  61.729 +					newRegs[i].I = regs[i].I;
  61.730 +					break;
  61.731 +				case REG_OFFSET:
  61.732 +					newRegs[i].I = elfReadMemory(regs[state->cfaRegister].I +
  61.733 +					                             state->cfaOffset +
  61.734 +					                             r->offset);
  61.735 +					break;
  61.736 +				case REG_REGISTER:
  61.737 +					newRegs[i].I = regs[r->reg].I;
  61.738 +					break;
  61.739 +				default:
  61.740 +					printf("Unknown register mode: %d\n", r->mode);
  61.741 +					break;
  61.742 +				}
  61.743 +			}
  61.744 +			memcpy(regs, newRegs, sizeof(reg_pair)*15);
  61.745 +			addr    = newRegs[14].I;
  61.746 +			addr   &= 0xfffffffe;
  61.747 +			address = addr;
  61.748 +			count++;
  61.749 +		}
  61.750 +		else
  61.751 +		{
  61.752 +			printf("CFA not set\n");
  61.753 +			break;
  61.754 +		}
  61.755 +		if (state->registers.previous)
  61.756 +		{
  61.757 +			ELFFrameStateRegisters *prev = state->registers.previous;
  61.758 +
  61.759 +			while (prev)
  61.760 +			{
  61.761 +				ELFFrameStateRegisters *p = prev->previous;
  61.762 +				free(prev);
  61.763 +				prev = p;
  61.764 +			}
  61.765 +		}
  61.766 +		free(state);
  61.767 +	}
  61.768 +}
  61.769 +
  61.770 +u32 elfDecodeLocation(Function *f, ELFBlock *o, LocationType *type, u32 base)
  61.771 +{
  61.772 +	u32 framebase = 0;
  61.773 +	if (f && f->frameBase)
  61.774 +	{
  61.775 +		ELFBlock *b = f->frameBase;
  61.776 +		switch (*b->data)
  61.777 +		{
  61.778 +		case DW_OP_reg0:
  61.779 +		case DW_OP_reg1:
  61.780 +		case DW_OP_reg2:
  61.781 +		case DW_OP_reg3:
  61.782 +		case DW_OP_reg4:
  61.783 +		case DW_OP_reg5:
  61.784 +		case DW_OP_reg6:
  61.785 +		case DW_OP_reg7:
  61.786 +		case DW_OP_reg8:
  61.787 +		case DW_OP_reg9:
  61.788 +		case DW_OP_reg10:
  61.789 +		case DW_OP_reg11:
  61.790 +		case DW_OP_reg12:
  61.791 +		case DW_OP_reg13:
  61.792 +		case DW_OP_reg14:
  61.793 +		case DW_OP_reg15:
  61.794 +			framebase = reg[*b->data-0x50].I;
  61.795 +			break;
  61.796 +		default:
  61.797 +			fprintf(stderr, "Unknown frameBase %02x\n", *b->data);
  61.798 +			break;
  61.799 +		}
  61.800 +	}
  61.801 +
  61.802 +	ELFBlock *loc      = o;
  61.803 +	u32       location = 0;
  61.804 +	int       bytes    = 0;
  61.805 +	if (loc)
  61.806 +	{
  61.807 +		switch (*loc->data)
  61.808 +		{
  61.809 +		case DW_OP_addr:
  61.810 +			location = elfRead4Bytes(loc->data+1);
  61.811 +			*type    = LOCATION_memory;
  61.812 +			break;
  61.813 +		case DW_OP_plus_uconst:
  61.814 +			location = base + elfReadLEB128(loc->data+1, &bytes);
  61.815 +			*type    = LOCATION_memory;
  61.816 +			break;
  61.817 +		case DW_OP_reg0:
  61.818 +		case DW_OP_reg1:
  61.819 +		case DW_OP_reg2:
  61.820 +		case DW_OP_reg3:
  61.821 +		case DW_OP_reg4:
  61.822 +		case DW_OP_reg5:
  61.823 +		case DW_OP_reg6:
  61.824 +		case DW_OP_reg7:
  61.825 +		case DW_OP_reg8:
  61.826 +		case DW_OP_reg9:
  61.827 +		case DW_OP_reg10:
  61.828 +		case DW_OP_reg11:
  61.829 +		case DW_OP_reg12:
  61.830 +		case DW_OP_reg13:
  61.831 +		case DW_OP_reg14:
  61.832 +		case DW_OP_reg15:
  61.833 +			location = *loc->data - 0x50;
  61.834 +			*type    = LOCATION_register;
  61.835 +			break;
  61.836 +		case DW_OP_fbreg:
  61.837 +		{
  61.838 +			int bytes;
  61.839 +			s32 off = elfReadSignedLEB128(loc->data+1, &bytes);
  61.840 +			location = framebase + off;
  61.841 +			*type    = LOCATION_memory;
  61.842 +			break;
  61.843 +		}
  61.844 +		default:
  61.845 +			fprintf(stderr, "Unknown location %02x\n", *loc->data);
  61.846 +			break;
  61.847 +		}
  61.848 +	}
  61.849 +	return location;
  61.850 +}
  61.851 +
  61.852 +u32 elfDecodeLocation(Function *f, ELFBlock *o, LocationType *type)
  61.853 +{
  61.854 +	return elfDecodeLocation(f, o, type, 0);
  61.855 +}
  61.856 +
  61.857 +// reading function
  61.858 +
  61.859 +u32 elfRead4Bytes(u8 *data)
  61.860 +{
  61.861 +	u32 value = *data++;
  61.862 +	value |= (*data++ << 8);
  61.863 +	value |= (*data++ << 16);
  61.864 +	value |= (*data << 24);
  61.865 +	return value;
  61.866 +}
  61.867 +
  61.868 +u16 elfRead2Bytes(u8 *data)
  61.869 +{
  61.870 +	u16 value = *data++;
  61.871 +	value |= (*data << 8);
  61.872 +	return value;
  61.873 +}
  61.874 +
  61.875 +char *elfReadString(u8 *data, int *bytesRead)
  61.876 +{
  61.877 +	if (*data == 0)
  61.878 +	{
  61.879 +		*bytesRead = 1;
  61.880 +		return NULL;
  61.881 +	}
  61.882 +	*bytesRead = strlen((char *)data) + 1;
  61.883 +	return (char *)data;
  61.884 +}
  61.885 +
  61.886 +s32 elfReadSignedLEB128(u8 *data, int *bytesRead)
  61.887 +{
  61.888 +	s32 result = 0;
  61.889 +	int shift  = 0;
  61.890 +	int count  = 0;
  61.891 +
  61.892 +	u8 byte;
  61.893 +	do
  61.894 +	{
  61.895 +		byte = *data++;
  61.896 +		count++;
  61.897 +		result |= (byte & 0x7f) << shift;
  61.898 +		shift  += 7;
  61.899 +	}
  61.900 +	while (byte & 0x80);
  61.901 +	if ((shift < 32) && (byte & 0x40))
  61.902 +		result |= -(1 << shift);
  61.903 +	*bytesRead = count;
  61.904 +	return result;
  61.905 +}
  61.906 +
  61.907 +u32 elfReadLEB128(u8 *data, int *bytesRead)
  61.908 +{
  61.909 +	u32 result = 0;
  61.910 +	int shift  = 0;
  61.911 +	int count  = 0;
  61.912 +	u8  byte;
  61.913 +	do
  61.914 +	{
  61.915 +		byte = *data++;
  61.916 +		count++;
  61.917 +		result |= (byte & 0x7f) << shift;
  61.918 +		shift  += 7;
  61.919 +	}
  61.920 +	while (byte & 0x80);
  61.921 +	*bytesRead = count;
  61.922 +	return result;
  61.923 +}
  61.924 +
  61.925 +u8 *elfReadSection(u8 *data, ELFSectionHeader *sh)
  61.926 +{
  61.927 +	return data + READ32LE(&sh->offset);
  61.928 +}
  61.929 +
  61.930 +ELFSectionHeader *elfGetSectionByName(char *name)
  61.931 +{
  61.932 +	for (int i = 0; i < elfSectionHeadersCount; i++)
  61.933 +	{
  61.934 +		if (strcmp(name,
  61.935 +		           &elfSectionHeadersStringTable[READ32LE(&elfSectionHeaders[i]->
  61.936 +		                                                  name)]) == 0)
  61.937 +		{
  61.938 +			return elfSectionHeaders[i];
  61.939 +		}
  61.940 +	}
  61.941 +	return NULL;
  61.942 +}
  61.943 +
  61.944 +ELFSectionHeader *elfGetSectionByNumber(int number)
  61.945 +{
  61.946 +	if (number < elfSectionHeadersCount)
  61.947 +	{
  61.948 +		return elfSectionHeaders[number];
  61.949 +	}
  61.950 +	return NULL;
  61.951 +}
  61.952 +
  61.953 +CompileUnit *elfGetCompileUnitForData(u8 *data)
  61.954 +{
  61.955 +	u8 *end = elfCurrentUnit->top + 4 + elfCurrentUnit->length;
  61.956 +
  61.957 +	if (data >= elfCurrentUnit->top && data < end)
  61.958 +		return elfCurrentUnit;
  61.959 +
  61.960 +	CompileUnit *unit = elfCompileUnits;
  61.961 +
  61.962 +	while (unit)
  61.963 +	{
  61.964 +		end = unit->top + 4 + unit->length;
  61.965 +
  61.966 +		if (data >= unit->top && data < end)
  61.967 +			return unit;
  61.968 +
  61.969 +		unit = unit->next;
  61.970 +	}
  61.971 +
  61.972 +	printf("Error: cannot find reference to compile unit at offset %08x\n",
  61.973 +	       (int)(data - elfDebugInfo->infodata));
  61.974 +	exit(-1);
  61.975 +}
  61.976 +
  61.977 +u8 *elfReadAttribute(u8 *data, ELFAttr *attr)
  61.978 +{
  61.979 +	int bytes;
  61.980 +	int form = attr->form;
  61.981 +start:
  61.982 +	switch (form)
  61.983 +	{
  61.984 +	case DW_FORM_addr:
  61.985 +		attr->value = elfRead4Bytes(data);
  61.986 +		data       += 4;
  61.987 +		break;
  61.988 +	case DW_FORM_data2:
  61.989 +		attr->value = elfRead2Bytes(data);
  61.990 +		data       += 2;
  61.991 +		break;
  61.992 +	case DW_FORM_data4:
  61.993 +		attr->value = elfRead4Bytes(data);
  61.994 +		data       += 4;
  61.995 +		break;
  61.996 +	case DW_FORM_string:
  61.997 +		attr->string = (char *)data;
  61.998 +		data        += strlen(attr->string)+1;
  61.999 +		break;
 61.1000 +	case DW_FORM_strp:
 61.1001 +		attr->string = elfDebugStrings + elfRead4Bytes(data);
 61.1002 +		data        += 4;
 61.1003 +		break;
 61.1004 +	case DW_FORM_block:
 61.1005 +		attr->block         = (ELFBlock *)malloc(sizeof(ELFBlock));
 61.1006 +		attr->block->length = elfReadLEB128(data, &bytes);
 61.1007 +		data += bytes;
 61.1008 +		attr->block->data = data;
 61.1009 +		data += attr->block->length;
 61.1010 +		break;
 61.1011 +	case DW_FORM_block1:
 61.1012 +		attr->block         = (ELFBlock *)malloc(sizeof(ELFBlock));
 61.1013 +		attr->block->length = *data++;
 61.1014 +		attr->block->data   = data;
 61.1015 +		data += attr->block->length;
 61.1016 +		break;
 61.1017 +	case DW_FORM_data1:
 61.1018 +		attr->value = *data++;
 61.1019 +		break;
 61.1020 +	case DW_FORM_flag:
 61.1021 +		attr->flag = (*data++) ? true : false;
 61.1022 +		break;
 61.1023 +	case DW_FORM_sdata:
 61.1024 +		attr->value = elfReadSignedLEB128(data, &bytes);
 61.1025 +		data       += bytes;
 61.1026 +		break;
 61.1027 +	case DW_FORM_udata:
 61.1028 +		attr->value = elfReadLEB128(data, &bytes);
 61.1029 +		data       += bytes;
 61.1030 +		break;
 61.1031 +	case DW_FORM_ref_addr:
 61.1032 +		attr->value = (elfDebugInfo->infodata + elfRead4Bytes(data)) -
 61.1033 +		              elfGetCompileUnitForData(data)->top;
 61.1034 +		data += 4;
 61.1035 +		break;
 61.1036 +	case DW_FORM_ref4:
 61.1037 +		attr->value = elfRead4Bytes(data);
 61.1038 +		data       += 4;
 61.1039 +		break;
 61.1040 +	case DW_FORM_ref_udata:
 61.1041 +		attr->value = (elfDebugInfo->infodata +
 61.1042 +		               (elfGetCompileUnitForData(data)->top -
 61.1043 +		                elfDebugInfo->infodata) +
 61.1044 +		               elfReadLEB128(data, &bytes)) -
 61.1045 +		              elfCurrentUnit->top;
 61.1046 +		data += bytes;
 61.1047 +		break;
 61.1048 +	case DW_FORM_indirect:
 61.1049 +		form  = elfReadLEB128(data, &bytes);
 61.1050 +		data += bytes;
 61.1051 +		goto start;
 61.1052 +	default:
 61.1053 +		fprintf(stderr, "Unsupported FORM %02x\n", form);
 61.1054 +		exit(-1);
 61.1055 +	}
 61.1056 +	return data;
 61.1057 +}
 61.1058 +
 61.1059 +ELFAbbrev *elfGetAbbrev(ELFAbbrev **table, u32 number)
 61.1060 +{
 61.1061 +	int hash = number % 121;
 61.1062 +
 61.1063 +	ELFAbbrev *abbrev = table[hash];
 61.1064 +
 61.1065 +	while (abbrev)
 61.1066 +	{
 61.1067 +		if (abbrev->number == number)
 61.1068 +			return abbrev;
 61.1069 +		abbrev = abbrev->next;
 61.1070 +	}
 61.1071 +	return NULL;
 61.1072 +}
 61.1073 +
 61.1074 +ELFAbbrev * *elfReadAbbrevs(u8 *data, u32 offset)
 61.1075 +{
 61.1076 +	data += offset;
 61.1077 +	ELFAbbrev **abbrevs = (ELFAbbrev * *)calloc(sizeof(ELFAbbrev *)*121, 1);
 61.1078 +	int         bytes   = 0;
 61.1079 +	u32         number  = elfReadLEB128(data, &bytes);
 61.1080 +	data += bytes;
 61.1081 +	while (number)
 61.1082 +	{
 61.1083 +		ELFAbbrev *abbrev = (ELFAbbrev *)calloc(sizeof(ELFAbbrev), 1);
 61.1084 +
 61.1085 +		// read tag information
 61.1086 +		abbrev->number = number;
 61.1087 +		abbrev->tag    = elfReadLEB128(data, &bytes);
 61.1088 +		data += bytes;
 61.1089 +		abbrev->hasChildren = *data++ ? true : false;
 61.1090 +
 61.1091 +		// read attributes
 61.1092 +		int name = elfReadLEB128(data, &bytes);
 61.1093 +		data += bytes;
 61.1094 +		int form = elfReadLEB128(data, &bytes);
 61.1095 +		data += bytes;
 61.1096 +
 61.1097 +		while (name)
 61.1098 +		{
 61.1099 +			if ((abbrev->numAttrs % 4) == 0)
 61.1100 +			{
 61.1101 +				abbrev->attrs = (ELFAttr *)realloc(abbrev->attrs,
 61.1102 +				                                   (abbrev->numAttrs + 4) *
 61.1103 +				                                   sizeof(ELFAttr));
 61.1104 +			}
 61.1105 +			abbrev->attrs[abbrev->numAttrs].name   = name;
 61.1106 +			abbrev->attrs[abbrev->numAttrs++].form = form;
 61.1107 +
 61.1108 +			name  = elfReadLEB128(data, &bytes);
 61.1109 +			data += bytes;
 61.1110 +			form  = elfReadLEB128(data, &bytes);
 61.1111 +			data += bytes;
 61.1112 +		}
 61.1113 +
 61.1114 +		int hash = number % 121;
 61.1115 +		abbrev->next  = abbrevs[hash];
 61.1116 +		abbrevs[hash] = abbrev;
 61.1117 +
 61.1118 +		number = elfReadLEB128(data, &bytes);
 61.1119 +		data  += bytes;
 61.1120 +
 61.1121 +		if (elfGetAbbrev(abbrevs, number) != NULL)
 61.1122 +			break;
 61.1123 +	}
 61.1124 +
 61.1125 +	return abbrevs;
 61.1126 +}
 61.1127 +
 61.1128 +void elfParseCFA(u8 *top)
 61.1129 +{
 61.1130 +	ELFSectionHeader *h = elfGetSectionByName(".debug_frame");
 61.1131 +
 61.1132 +	if (h == NULL)
 61.1133 +	{
 61.1134 +		return;
 61.1135 +	}
 61.1136 +
 61.1137 +	u8 *data = elfReadSection(top, h);
 61.1138 +
 61.1139 +	u8 *topOffset = data;
 61.1140 +
 61.1141 +	u8 *end = data + READ32LE(&h->size);
 61.1142 +
 61.1143 +	ELFcie *cies = NULL;
 61.1144 +
 61.1145 +	while (data < end)
 61.1146 +	{
 61.1147 +		u32 offset = data - topOffset;
 61.1148 +		u32 len    = elfRead4Bytes(data);
 61.1149 +		data += 4;
 61.1150 +
 61.1151 +		u8 *dataEnd = data + len;
 61.1152 +
 61.1153 +		u32 id = elfRead4Bytes(data);
 61.1154 +		data += 4;
 61.1155 +
 61.1156 +		if (id == 0xffffffff)
 61.1157 +		{
 61.1158 +			// skip version
 61.1159 +			*data++;
 61.1160 +
 61.1161 +			ELFcie *cie = (ELFcie *)calloc(1, sizeof(ELFcie));
 61.1162 +
 61.1163 +			cie->next = cies;
 61.1164 +			cies      = cie;
 61.1165 +
 61.1166 +			cie->offset = offset;
 61.1167 +
 61.1168 +			cie->augmentation = data;
 61.1169 +			while (*data)
 61.1170 +				data++;
 61.1171 +			data++;
 61.1172 +
 61.1173 +			if (*cie->augmentation)
 61.1174 +			{
 61.1175 +				fprintf(stderr, "Error: augmentation not supported\n");
 61.1176 +				exit(-1);
 61.1177 +			}
 61.1178 +
 61.1179 +			int bytes;
 61.1180 +			cie->codeAlign = elfReadLEB128(data, &bytes);
 61.1181 +			data += bytes;
 61.1182 +
 61.1183 +			cie->dataAlign = elfReadSignedLEB128(data, &bytes);
 61.1184 +			data += bytes;
 61.1185 +
 61.1186 +			cie->returnAddress = *data++;
 61.1187 +
 61.1188 +			cie->data    = data;
 61.1189 +			cie->dataLen = dataEnd - data;
 61.1190 +		}
 61.1191 +		else
 61.1192 +		{
 61.1193 +			ELFfde *fde = (ELFfde *)calloc(1, sizeof(ELFfde));
 61.1194 +
 61.1195 +			ELFcie *cie = cies;
 61.1196 +
 61.1197 +			while (cie != NULL)
 61.1198 +			{
 61.1199 +				if (cie->offset == id)
 61.1200 +					break;
 61.1201 +				cie = cie->next;
 61.1202 +			}
 61.1203 +
 61.1204 +			if (!cie)
 61.1205 +			{
 61.1206 +				fprintf(stderr, "Cannot find CIE %08x\n", id);
 61.1207 +				exit(-1);
 61.1208 +			}
 61.1209 +
 61.1210 +			fde->cie = cie;
 61.1211 +
 61.1212 +			fde->address = elfRead4Bytes(data);
 61.1213 +			data        += 4;
 61.1214 +
 61.1215 +			fde->end = fde->address + elfRead4Bytes(data);
 61.1216 +			data    += 4;
 61.1217 +
 61.1218 +			fde->data    = data;
 61.1219 +			fde->dataLen = dataEnd - data;
 61.1220 +
 61.1221 +			if ((elfFdeCount %10) == 0)
 61.1222 +			{
 61.1223 +				elfFdes = (ELFfde * *)realloc(elfFdes, (elfFdeCount+10) *
 61.1224 +				                              sizeof(ELFfde *));
 61.1225 +			}
 61.1226 +			elfFdes[elfFdeCount++] = fde;
 61.1227 +		}
 61.1228 +		data = dataEnd;
 61.1229 +	}
 61.1230 +
 61.1231 +	elfCies = cies;
 61.1232 +}
 61.1233 +
 61.1234 +void elfAddLine(LineInfo *l, u32 a, int file, int line, int *max)
 61.1235 +{
 61.1236 +	if (l->number == *max)
 61.1237 +	{
 61.1238 +		*max    += 1000;
 61.1239 +		l->lines = (LineInfoItem *)realloc(l->lines, *max*sizeof(LineInfoItem));
 61.1240 +	}
 61.1241 +	LineInfoItem *li = &l->lines[l->number];
 61.1242 +	li->file    = l->files[file-1];
 61.1243 +	li->address = a;
 61.1244 +	li->line    = line;
 61.1245 +	l->number++;
 61.1246 +}
 61.1247 +
 61.1248 +void elfParseLineInfo(CompileUnit *unit, u8 *top)
 61.1249 +{
 61.1250 +	ELFSectionHeader *h = elfGetSectionByName(".debug_line");
 61.1251 +	if (h == NULL)
 61.1252 +	{
 61.1253 +		fprintf(stderr, "No line information found\n");
 61.1254 +		return;
 61.1255 +	}
 61.1256 +	LineInfo *l = unit->lineInfoTable = (LineInfo *)calloc(1, sizeof(LineInfo));
 61.1257 +	l->number = 0;
 61.1258 +	int max = 1000;
 61.1259 +	l->lines = (LineInfoItem *)malloc(1000*sizeof(LineInfoItem));
 61.1260 +
 61.1261 +	u8 *data = elfReadSection(top, h);
 61.1262 +	data += unit->lineInfo;
 61.1263 +	u32 totalLen = elfRead4Bytes(data);
 61.1264 +	data += 4;
 61.1265 +	u8 *end = data + totalLen;
 61.1266 +	//  u16 version = elfRead2Bytes(data);
 61.1267 +	data += 2;
 61.1268 +	//  u32 offset = elfRead4Bytes(data);
 61.1269 +	data += 4;
 61.1270 +	int minInstrSize  = *data++;
 61.1271 +	int defaultIsStmt = *data++;
 61.1272 +	int lineBase      = (s8)*data++;
 61.1273 +	int lineRange     = *data++;
 61.1274 +	int opcodeBase    = *data++;
 61.1275 +	u8 *stdOpLen      = (u8 *)malloc(opcodeBase * sizeof(u8));
 61.1276 +	stdOpLen[0] = 1;
 61.1277 +	int i;
 61.1278 +	for (i = 1; i < opcodeBase; i++)
 61.1279 +		stdOpLen[i] = *data++;
 61.1280 +
 61.1281 +	free(stdOpLen); // todo
 61.1282 +	int bytes = 0;
 61.1283 +
 61.1284 +	char *s;
 61.1285 +	while ((s = elfReadString(data, &bytes)) != NULL)
 61.1286 +	{
 61.1287 +		data += bytes;
 61.1288 +		//    fprintf(stderr, "Directory is %s\n", s);
 61.1289 +	}
 61.1290 +	data += bytes;
 61.1291 +	int count = 4;
 61.1292 +	int index = 0;
 61.1293 +	l->files = (char * *)malloc(sizeof(char *)*count);
 61.1294 +
 61.1295 +	while ((s = elfReadString(data, &bytes)) != NULL)
 61.1296 +	{
 61.1297 +		l->files[index++] = s;
 61.1298 +
 61.1299 +		data += bytes;
 61.1300 +		// directory
 61.1301 +		elfReadLEB128(data, &bytes);
 61.1302 +		data += bytes;
 61.1303 +		// time
 61.1304 +		elfReadLEB128(data, &bytes);
 61.1305 +		data += bytes;
 61.1306 +		// size
 61.1307 +		elfReadLEB128(data, &bytes);
 61.1308 +		data += bytes;
 61.1309 +		//    fprintf(stderr, "File is %s\n", s);
 61.1310 +		if (index == count)
 61.1311 +		{
 61.1312 +			count   += 4;
 61.1313 +			l->files = (char * *)realloc(l->files, sizeof(char *)*count);
 61.1314 +		}
 61.1315 +	}
 61.1316 +	l->fileCount = index;
 61.1317 +	data        += bytes;
 61.1318 +
 61.1319 +	while (data < end)
 61.1320 +	{
 61.1321 +		u32 address    = 0;
 61.1322 +		int file       = 1;
 61.1323 +		int line       = 1;
 61.1324 +		int col        = 0;
 61.1325 +		int isStmt     = defaultIsStmt;
 61.1326 +		int basicBlock = 0;
 61.1327 +		int endSeq     = 0;
 61.1328 +
 61.1329 +		while (!endSeq)
 61.1330 +		{
 61.1331 +			int op = *data++;
 61.1332 +			switch (op)
 61.1333 +			{
 61.1334 +			case DW_LNS_extended_op:
 61.1335 +			{
 61.1336 +				data++;
 61.1337 +				op = *data++;
 61.1338 +				switch (op)
 61.1339 +				{
 61.1340 +				case DW_LNE_end_sequence:
 61.1341 +					endSeq = 1;
 61.1342 +					break;
 61.1343 +				case DW_LNE_set_address:
 61.1344 +					address = elfRead4Bytes(data);
 61.1345 +					data   += 4;
 61.1346 +					break;
 61.1347 +				default:
 61.1348 +					fprintf(stderr, "Unknown extended LINE opcode %02x\n", op);
 61.1349 +					exit(-1);
 61.1350 +				}
 61.1351 +				break;
 61.1352 +			}
 61.1353 +			case DW_LNS_copy:
 61.1354 +				//      fprintf(stderr, "Address %08x line %d (%d)\n", address, line, file);
 61.1355 +				elfAddLine(l, address, file, line, &max);
 61.1356 +				basicBlock = 0;
 61.1357 +				break;
 61.1358 +			case DW_LNS_advance_pc:
 61.1359 +				address += minInstrSize * elfReadLEB128(data, &bytes);
 61.1360 +				data    += bytes;
 61.1361 +				break;
 61.1362 +			case DW_LNS_advance_line:
 61.1363 +				line += elfReadSignedLEB128(data, &bytes);
 61.1364 +				data += bytes;
 61.1365 +				break;
 61.1366 +			case DW_LNS_set_file:
 61.1367 +				file  = elfReadLEB128(data, &bytes);
 61.1368 +				data += bytes;
 61.1369 +				break;
 61.1370 +			case DW_LNS_set_column:
 61.1371 +				col   = elfReadLEB128(data, &bytes);
 61.1372 +				data += bytes;
 61.1373 +				break;
 61.1374 +			case DW_LNS_negate_stmt:
 61.1375 +				isStmt = !isStmt;
 61.1376 +				break;
 61.1377 +			case DW_LNS_set_basic_block:
 61.1378 +				basicBlock = 1;
 61.1379 +				break;
 61.1380 +			case DW_LNS_const_add_pc:
 61.1381 +				address += (minInstrSize *((255 - opcodeBase)/lineRange));
 61.1382 +				break;
 61.1383 +			case DW_LNS_fixed_advance_pc:
 61.1384 +				address += elfRead2Bytes(data);
 61.1385 +				data    += 2;
 61.1386 +				break;
 61.1387 +			default:
 61.1388 +				op       = op - opcodeBase;
 61.1389 +				address += (op / lineRange) * minInstrSize;
 61.1390 +				line    += lineBase + (op % lineRange);
 61.1391 +				elfAddLine(l, address, file, line, &max);
 61.1392 +				//        fprintf(stderr, "Address %08x line %d (%d)\n", address, line,file);
 61.1393 +				basicBlock = 1;
 61.1394 +				break;
 61.1395 +			}
 61.1396 +		}
 61.1397 +	}
 61.1398 +	l->lines = (LineInfoItem *)realloc(l->lines, l->number*sizeof(LineInfoItem));
 61.1399 +}
 61.1400 +
 61.1401 +u8 *elfSkipData(u8 *data, ELFAbbrev *abbrev, ELFAbbrev **abbrevs)
 61.1402 +{
 61.1403 +	int i;
 61.1404 +	int bytes;
 61.1405 +
 61.1406 +	for (i = 0; i < abbrev->numAttrs; i++)
 61.1407 +	{
 61.1408 +		data = elfReadAttribute(data,  &abbrev->attrs[i]);
 61.1409 +		if (abbrev->attrs[i].form == DW_FORM_block1)
 61.1410 +			free(abbrev->attrs[i].block);
 61.1411 +	}
 61.1412 +
 61.1413 +	if (abbrev->hasChildren)
 61.1414 +	{
 61.1415 +		int nesting = 1;
 61.1416 +		while (nesting)
 61.1417 +		{
 61.1418 +			u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.1419 +			data += bytes;
 61.1420 +
 61.1421 +			if (!abbrevNum)
 61.1422 +			{
 61.1423 +				nesting--;
 61.1424 +				continue;
 61.1425 +			}
 61.1426 +
 61.1427 +			abbrev = elfGetAbbrev(abbrevs, abbrevNum);
 61.1428 +
 61.1429 +			for (i = 0; i < abbrev->numAttrs; i++)
 61.1430 +			{
 61.1431 +				data = elfReadAttribute(data,  &abbrev->attrs[i]);
 61.1432 +				if (abbrev->attrs[i].form == DW_FORM_block1)
 61.1433 +					free(abbrev->attrs[i].block);
 61.1434 +			}
 61.1435 +
 61.1436 +			if (abbrev->hasChildren)
 61.1437 +			{
 61.1438 +				nesting++;
 61.1439 +			}
 61.1440 +		}
 61.1441 +	}
 61.1442 +	return data;
 61.1443 +}
 61.1444 +
 61.1445 +Type *elfParseType(CompileUnit *unit, u32);
 61.1446 +u8 *elfParseObject(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit,
 61.1447 +                   Object **object);
 61.1448 +u8 *elfParseFunction(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit,
 61.1449 +                     Function **function);
 61.1450 +void elfCleanUp(Function *);
 61.1451 +
 61.1452 +void elfAddType(Type *type, CompileUnit *unit, u32 offset)
 61.1453 +{
 61.1454 +	if (type->next == NULL)
 61.1455 +	{
 61.1456 +		if (unit->types != type && type->offset == 0)
 61.1457 +		{
 61.1458 +			type->offset = offset;
 61.1459 +			type->next   = unit->types;
 61.1460 +			unit->types  = type;
 61.1461 +		}
 61.1462 +	}
 61.1463 +}
 61.1464 +
 61.1465 +void elfParseType(u8 *data, u32 offset, ELFAbbrev *abbrev, CompileUnit *unit,
 61.1466 +                  Type **type)
 61.1467 +{
 61.1468 +	switch (abbrev->tag)
 61.1469 +	{
 61.1470 +	case DW_TAG_typedef:
 61.1471 +	{
 61.1472 +		u32   typeref = 0;
 61.1473 +		char *name    = NULL;
 61.1474 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1475 +		{
 61.1476 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1477 +			data = elfReadAttribute(data, attr);
 61.1478 +			switch (attr->name)
 61.1479 +			{
 61.1480 +			case DW_AT_name:
 61.1481 +				name = attr->string;
 61.1482 +				break;
 61.1483 +			case DW_AT_type:
 61.1484 +				typeref = attr->value;
 61.1485 +				break;
 61.1486 +			case DW_AT_decl_file:
 61.1487 +			case DW_AT_decl_line:
 61.1488 +				break;
 61.1489 +			default:
 61.1490 +				fprintf(stderr, "Unknown attribute for typedef %02x\n", attr->name);
 61.1491 +				break;
 61.1492 +			}
 61.1493 +		}
 61.1494 +		if (abbrev->hasChildren)
 61.1495 +			fprintf(stderr, "Unexpected children for typedef\n");
 61.1496 +		*type = elfParseType(unit, typeref);
 61.1497 +		if (name)
 61.1498 +			(*type)->name = name;
 61.1499 +		return;
 61.1500 +		break;
 61.1501 +	}
 61.1502 +	case DW_TAG_union_type:
 61.1503 +	case DW_TAG_structure_type:
 61.1504 +	{
 61.1505 +		Type *t = (Type *)calloc(sizeof(Type), 1);
 61.1506 +		if (abbrev->tag == DW_TAG_structure_type)
 61.1507 +			t->type = TYPE_struct;
 61.1508 +		else
 61.1509 +			t->type = TYPE_union;
 61.1510 +
 61.1511 +		Struct *s = (Struct *)calloc(sizeof(Struct), 1);
 61.1512 +		t->structure = s;
 61.1513 +		elfAddType(t, unit, offset);
 61.1514 +
 61.1515 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1516 +		{
 61.1517 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1518 +			data = elfReadAttribute(data, attr);
 61.1519 +			switch (attr->name)
 61.1520 +			{
 61.1521 +			case DW_AT_name:
 61.1522 +				t->name = attr->string;
 61.1523 +				break;
 61.1524 +			case DW_AT_byte_size:
 61.1525 +				t->size = attr->value;
 61.1526 +				break;
 61.1527 +			case DW_AT_decl_file:
 61.1528 +			case DW_AT_decl_line:
 61.1529 +			case DW_AT_sibling:
 61.1530 +			case DW_AT_containing_type: // todo?
 61.1531 +			case DW_AT_declaration:
 61.1532 +			case DW_AT_specification: // TODO:
 61.1533 +				break;
 61.1534 +			default:
 61.1535 +				fprintf(stderr, "Unknown attribute for struct %02x\n", attr->name);
 61.1536 +				break;
 61.1537 +			}
 61.1538 +		}
 61.1539 +		if (abbrev->hasChildren)
 61.1540 +		{
 61.1541 +			int bytes;
 61.1542 +			u32 num = elfReadLEB128(data, &bytes);
 61.1543 +			data += bytes;
 61.1544 +			int index = 0;
 61.1545 +			while (num)
 61.1546 +			{
 61.1547 +				ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num);
 61.1548 +
 61.1549 +				switch (abbr->tag)
 61.1550 +				{
 61.1551 +				case DW_TAG_member:
 61.1552 +				{
 61.1553 +					if ((index % 4) == 0)
 61.1554 +						s->members = (Member *)realloc(s->members,
 61.1555 +						                               sizeof(Member)*(index+4));
 61.1556 +					Member *m = &s->members[index];
 61.1557 +					m->location  = NULL;
 61.1558 +					m->bitOffset = 0;
 61.1559 +					m->bitSize   = 0;
 61.1560 +					m->byteSize  = 0;
 61.1561 +					for (int i = 0; i < abbr->numAttrs; i++)
 61.1562 +					{
 61.1563 +						ELFAttr *attr = &abbr->attrs[i];
 61.1564 +						data = elfReadAttribute(data, attr);
 61.1565 +						switch (attr->name)
 61.1566 +						{
 61.1567 +						case DW_AT_name:
 61.1568 +							m->name = attr->string;
 61.1569 +							break;
 61.1570 +						case DW_AT_type:
 61.1571 +							m->type = elfParseType(unit, attr->value);
 61.1572 +							break;
 61.1573 +						case DW_AT_data_member_location:
 61.1574 +							m->location = attr->block;
 61.1575 +							break;
 61.1576 +						case DW_AT_byte_size:
 61.1577 +							m->byteSize = attr->value;
 61.1578 +							break;
 61.1579 +						case DW_AT_bit_offset:
 61.1580 +							m->bitOffset = attr->value;
 61.1581 +							break;
 61.1582 +						case DW_AT_bit_size:
 61.1583 +							m->bitSize = attr->value;
 61.1584 +							break;
 61.1585 +						case DW_AT_decl_file:
 61.1586 +						case DW_AT_decl_line:
 61.1587 +						case DW_AT_accessibility:
 61.1588 +						case DW_AT_artificial: // todo?
 61.1589 +							break;
 61.1590 +						default:
 61.1591 +							fprintf(stderr, "Unknown member attribute %02x\n",
 61.1592 +							        attr->name);
 61.1593 +						}
 61.1594 +					}
 61.1595 +					index++;
 61.1596 +					break;
 61.1597 +				}
 61.1598 +				case DW_TAG_subprogram:
 61.1599 +				{
 61.1600 +					Function *fnc = NULL;
 61.1601 +					data = elfParseFunction(data, abbr, unit, &fnc);
 61.1602 +					if (fnc != NULL)
 61.1603 +					{
 61.1604 +						if (unit->lastFunction)
 61.1605 +							unit->lastFunction->next = fnc;
 61.1606 +						else
 61.1607 +							unit->functions = fnc;
 61.1608 +						unit->lastFunction = fnc;
 61.1609 +					}
 61.1610 +					break;
 61.1611 +				}
 61.1612 +				case DW_TAG_inheritance:
 61.1613 +					// TODO: add support
 61.1614 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1615 +					break;
 61.1616 +CASE_TYPE_TAG:
 61.1617 +					// skip types... parsed only when used
 61.1618 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1619 +					break;
 61.1620 +				case DW_TAG_variable:
 61.1621 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1622 +					break;
 61.1623 +				default:
 61.1624 +					fprintf(stderr, "Unknown struct tag %02x %s\n", abbr->tag, t->name);
 61.1625 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1626 +					break;
 61.1627 +				}
 61.1628 +				num   = elfReadLEB128(data, &bytes);
 61.1629 +				data += bytes;
 61.1630 +			}
 61.1631 +			s->memberCount = index;
 61.1632 +		}
 61.1633 +		*type = t;
 61.1634 +		return;
 61.1635 +		break;
 61.1636 +	}
 61.1637 +	case DW_TAG_base_type:
 61.1638 +	{
 61.1639 +		Type *t = (Type *)calloc(sizeof(Type), 1);
 61.1640 +
 61.1641 +		t->type = TYPE_base;
 61.1642 +		elfAddType(t, unit, offset);
 61.1643 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1644 +		{
 61.1645 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1646 +			data = elfReadAttribute(data, attr);
 61.1647 +			switch (attr->name)
 61.1648 +			{
 61.1649 +			case DW_AT_name:
 61.1650 +				t->name = attr->string;
 61.1651 +				break;
 61.1652 +			case DW_AT_encoding:
 61.1653 +				t->encoding = attr->value;
 61.1654 +				break;
 61.1655 +			case DW_AT_byte_size:
 61.1656 +				t->size = attr->value;
 61.1657 +				break;
 61.1658 +			case DW_AT_bit_size:
 61.1659 +				t->bitSize = attr->value;
 61.1660 +				break;
 61.1661 +			default:
 61.1662 +				fprintf(stderr, "Unknown attribute for base type %02x\n",
 61.1663 +				        attr->name);
 61.1664 +				break;
 61.1665 +			}
 61.1666 +		}
 61.1667 +		if (abbrev->hasChildren)
 61.1668 +			fprintf(stderr, "Unexpected children for base type\n");
 61.1669 +		*type = t;
 61.1670 +		return;
 61.1671 +		break;
 61.1672 +	}
 61.1673 +	case DW_TAG_pointer_type:
 61.1674 +	{
 61.1675 +		Type *t = (Type *)calloc(sizeof(Type), 1);
 61.1676 +
 61.1677 +		t->type = TYPE_pointer;
 61.1678 +
 61.1679 +		elfAddType(t, unit, offset);
 61.1680 +
 61.1681 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1682 +		{
 61.1683 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1684 +			data = elfReadAttribute(data, attr);
 61.1685 +			switch (attr->name)
 61.1686 +			{
 61.1687 +			case DW_AT_type:
 61.1688 +				t->pointer = elfParseType(unit, attr->value);
 61.1689 +				break;
 61.1690 +			case DW_AT_byte_size:
 61.1691 +				t->size = attr->value;
 61.1692 +				break;
 61.1693 +			default:
 61.1694 +				fprintf(stderr, "Unknown pointer type attribute %02x\n", attr->name);
 61.1695 +				break;
 61.1696 +			}
 61.1697 +		}
 61.1698 +		if (abbrev->hasChildren)
 61.1699 +			fprintf(stderr, "Unexpected children for pointer type\n");
 61.1700 +		*type = t;
 61.1701 +		return;
 61.1702 +		break;
 61.1703 +	}
 61.1704 +	case DW_TAG_reference_type:
 61.1705 +	{
 61.1706 +		Type *t = (Type *)calloc(sizeof(Type), 1);
 61.1707 +
 61.1708 +		t->type = TYPE_reference;
 61.1709 +
 61.1710 +		elfAddType(t, unit, offset);
 61.1711 +
 61.1712 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1713 +		{
 61.1714 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1715 +			data = elfReadAttribute(data, attr);
 61.1716 +			switch (attr->name)
 61.1717 +			{
 61.1718 +			case DW_AT_type:
 61.1719 +				t->pointer = elfParseType(unit, attr->value);
 61.1720 +				break;
 61.1721 +			case DW_AT_byte_size:
 61.1722 +				t->size = attr->value;
 61.1723 +				break;
 61.1724 +			default:
 61.1725 +				fprintf(stderr, "Unknown ref type attribute %02x\n", attr->name);
 61.1726 +				break;
 61.1727 +			}
 61.1728 +		}
 61.1729 +		if (abbrev->hasChildren)
 61.1730 +			fprintf(stderr, "Unexpected children for ref type\n");
 61.1731 +		*type = t;
 61.1732 +		return;
 61.1733 +		break;
 61.1734 +	}
 61.1735 +	case DW_TAG_volatile_type:
 61.1736 +	{
 61.1737 +		u32 typeref = 0;
 61.1738 +
 61.1739 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1740 +		{
 61.1741 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1742 +			data = elfReadAttribute(data, attr);
 61.1743 +			switch (attr->name)
 61.1744 +			{
 61.1745 +			case DW_AT_type:
 61.1746 +				typeref = attr->value;
 61.1747 +				break;
 61.1748 +			default:
 61.1749 +				fprintf(stderr, "Unknown volatile attribute for type %02x\n",
 61.1750 +				        attr->name);
 61.1751 +				break;
 61.1752 +			}
 61.1753 +		}
 61.1754 +		if (abbrev->hasChildren)
 61.1755 +			fprintf(stderr, "Unexpected children for volatile type\n");
 61.1756 +		*type = elfParseType(unit, typeref);
 61.1757 +		return;
 61.1758 +		break;
 61.1759 +	}
 61.1760 +	case DW_TAG_const_type:
 61.1761 +	{
 61.1762 +		u32 typeref = 0;
 61.1763 +
 61.1764 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1765 +		{
 61.1766 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1767 +			data = elfReadAttribute(data, attr);
 61.1768 +			switch (attr->name)
 61.1769 +			{
 61.1770 +			case DW_AT_type:
 61.1771 +				typeref = attr->value;
 61.1772 +				break;
 61.1773 +			default:
 61.1774 +				fprintf(stderr, "Unknown const attribute for type %02x\n",
 61.1775 +				        attr->name);
 61.1776 +				break;
 61.1777 +			}
 61.1778 +		}
 61.1779 +		if (abbrev->hasChildren)
 61.1780 +			fprintf(stderr, "Unexpected children for const type\n");
 61.1781 +		*type = elfParseType(unit, typeref);
 61.1782 +		return;
 61.1783 +		break;
 61.1784 +	}
 61.1785 +	case DW_TAG_enumeration_type:
 61.1786 +	{
 61.1787 +		Type *t = (Type *)calloc(sizeof(Type), 1);
 61.1788 +		t->type = TYPE_enum;
 61.1789 +		Enum *e = (Enum *)calloc(sizeof(Enum), 1);
 61.1790 +		t->enumeration = e;
 61.1791 +		elfAddType(t, unit, offset);
 61.1792 +		int count = 0;
 61.1793 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1794 +		{
 61.1795 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1796 +			data = elfReadAttribute(data, attr);
 61.1797 +			switch (attr->name)
 61.1798 +			{
 61.1799 +			case DW_AT_name:
 61.1800 +				t->name = attr->string;
 61.1801 +				break;
 61.1802 +			case DW_AT_byte_size:
 61.1803 +				t->size = attr->value;
 61.1804 +				break;
 61.1805 +			case DW_AT_sibling:
 61.1806 +			case DW_AT_decl_file:
 61.1807 +			case DW_AT_decl_line:
 61.1808 +				break;
 61.1809 +			default:
 61.1810 +				fprintf(stderr, "Unknown enum attribute %02x\n", attr->name);
 61.1811 +			}
 61.1812 +		}
 61.1813 +		if (abbrev->hasChildren)
 61.1814 +		{
 61.1815 +			int bytes;
 61.1816 +			u32 num = elfReadLEB128(data, &bytes);
 61.1817 +			data += bytes;
 61.1818 +			while (num)
 61.1819 +			{
 61.1820 +				ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num);
 61.1821 +
 61.1822 +				switch (abbr->tag)
 61.1823 +				{
 61.1824 +				case DW_TAG_enumerator:
 61.1825 +				{
 61.1826 +					count++;
 61.1827 +					e->members = (EnumMember *)realloc(e->members,
 61.1828 +					                                   count*sizeof(EnumMember));
 61.1829 +					EnumMember *m = &e->members[count-1];
 61.1830 +					for (int i = 0; i < abbr->numAttrs; i++)
 61.1831 +					{
 61.1832 +						ELFAttr *attr = &abbr->attrs[i];
 61.1833 +						data = elfReadAttribute(data, attr);
 61.1834 +						switch (attr->name)
 61.1835 +						{
 61.1836 +						case DW_AT_name:
 61.1837 +							m->name = attr->string;
 61.1838 +							break;
 61.1839 +						case DW_AT_const_value:
 61.1840 +							m->value = attr->value;
 61.1841 +							break;
 61.1842 +						default:
 61.1843 +							fprintf(stderr, "Unknown sub param attribute %02x\n",
 61.1844 +							        attr->name);
 61.1845 +						}
 61.1846 +					}
 61.1847 +					break;
 61.1848 +				}
 61.1849 +				default:
 61.1850 +					fprintf(stderr, "Unknown enum tag %02x\n", abbr->tag);
 61.1851 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1852 +					break;
 61.1853 +				}
 61.1854 +				num   = elfReadLEB128(data, &bytes);
 61.1855 +				data += bytes;
 61.1856 +			}
 61.1857 +		}
 61.1858 +		e->count = count;
 61.1859 +		*type    = t;
 61.1860 +		return;
 61.1861 +		break;
 61.1862 +	}
 61.1863 +	case DW_TAG_subroutine_type:
 61.1864 +	{
 61.1865 +		Type *t = (Type *)calloc(sizeof(Type), 1);
 61.1866 +		t->type = TYPE_function;
 61.1867 +		FunctionType *f = (FunctionType *)calloc(sizeof(FunctionType), 1);
 61.1868 +		t->function = f;
 61.1869 +		elfAddType(t, unit, offset);
 61.1870 +		for (int i = 0; i < abbrev->numAttrs; i++)
 61.1871 +		{
 61.1872 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1873 +			data = elfReadAttribute(data, attr);
 61.1874 +			switch (attr->name)
 61.1875 +			{
 61.1876 +			case DW_AT_prototyped:
 61.1877 +			case DW_AT_sibling:
 61.1878 +				break;
 61.1879 +			case DW_AT_type:
 61.1880 +				f->returnType = elfParseType(unit, attr->value);
 61.1881 +				break;
 61.1882 +			default:
 61.1883 +				fprintf(stderr, "Unknown subroutine attribute %02x\n", attr->name);
 61.1884 +			}
 61.1885 +		}
 61.1886 +		if (abbrev->hasChildren)
 61.1887 +		{
 61.1888 +			int bytes;
 61.1889 +			u32 num = elfReadLEB128(data, &bytes);
 61.1890 +			data += bytes;
 61.1891 +			Object *lastVar = NULL;
 61.1892 +			while (num)
 61.1893 +			{
 61.1894 +				ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num);
 61.1895 +
 61.1896 +				switch (abbr->tag)
 61.1897 +				{
 61.1898 +				case DW_TAG_formal_parameter:
 61.1899 +				{
 61.1900 +					Object *o;
 61.1901 +					data = elfParseObject(data, abbr, unit, &o);
 61.1902 +					if (f->args)
 61.1903 +						lastVar->next = o;
 61.1904 +					else
 61.1905 +						f->args = o;
 61.1906 +					lastVar = o;
 61.1907 +					break;
 61.1908 +				}
 61.1909 +				case DW_TAG_unspecified_parameters:
 61.1910 +					// no use in the debugger yet
 61.1911 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1912 +					break;
 61.1913 +CASE_TYPE_TAG:
 61.1914 +					// skip types... parsed only when used
 61.1915 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1916 +					break;
 61.1917 +				default:
 61.1918 +					fprintf(stderr, "Unknown subroutine tag %02x\n", abbr->tag);
 61.1919 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1920 +					break;
 61.1921 +				}
 61.1922 +				num   = elfReadLEB128(data, &bytes);
 61.1923 +				data += bytes;
 61.1924 +			}
 61.1925 +		}
 61.1926 +		*type = t;
 61.1927 +		return;
 61.1928 +		break;
 61.1929 +	}
 61.1930 +	case DW_TAG_array_type:
 61.1931 +	{
 61.1932 +		u32    typeref = 0;
 61.1933 +		int    i;
 61.1934 +		Array *array = (Array *)calloc(sizeof(Array), 1);
 61.1935 +		Type * t     = (Type *)calloc(sizeof(Type), 1);
 61.1936 +		t->type = TYPE_array;
 61.1937 +		elfAddType(t, unit, offset);
 61.1938 +
 61.1939 +		for (i = 0; i < abbrev->numAttrs; i++)
 61.1940 +		{
 61.1941 +			ELFAttr *attr = &abbrev->attrs[i];
 61.1942 +			data = elfReadAttribute(data, attr);
 61.1943 +			switch (attr->name)
 61.1944 +			{
 61.1945 +			case DW_AT_sibling:
 61.1946 +				break;
 61.1947 +			case DW_AT_type:
 61.1948 +				typeref     = attr->value;
 61.1949 +				array->type = elfParseType(unit, typeref);
 61.1950 +				break;
 61.1951 +			default:
 61.1952 +				fprintf(stderr, "Unknown array attribute %02x\n", attr->name);
 61.1953 +			}
 61.1954 +		}
 61.1955 +		if (abbrev->hasChildren)
 61.1956 +		{
 61.1957 +			int bytes;
 61.1958 +			u32 num = elfReadLEB128(data, &bytes);
 61.1959 +			data += bytes;
 61.1960 +			int index     = 0;
 61.1961 +			int maxBounds = 0;
 61.1962 +			while (num)
 61.1963 +			{
 61.1964 +				ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num);
 61.1965 +
 61.1966 +				switch (abbr->tag)
 61.1967 +				{
 61.1968 +				case DW_TAG_subrange_type:
 61.1969 +				{
 61.1970 +					if (maxBounds == index)
 61.1971 +					{
 61.1972 +						maxBounds    += 4;
 61.1973 +						array->bounds = (int *)realloc(array->bounds,
 61.1974 +						                               sizeof(int)*maxBounds);
 61.1975 +					}
 61.1976 +					for (int i = 0; i < abbr->numAttrs; i++)
 61.1977 +					{
 61.1978 +						ELFAttr *attr = &abbr->attrs[i];
 61.1979 +						data = elfReadAttribute(data, attr);
 61.1980 +						switch (attr->name)
 61.1981 +						{
 61.1982 +						case DW_AT_upper_bound:
 61.1983 +							array->bounds[index] = attr->value+1;
 61.1984 +							break;
 61.1985 +						case DW_AT_type: // ignore
 61.1986 +							break;
 61.1987 +						default:
 61.1988 +							fprintf(stderr, "Unknown subrange attribute %02x\n",
 61.1989 +							        attr->name);
 61.1990 +						}
 61.1991 +					}
 61.1992 +					index++;
 61.1993 +					break;
 61.1994 +				}
 61.1995 +				default:
 61.1996 +					fprintf(stderr, "Unknown array tag %02x\n", abbr->tag);
 61.1997 +					data = elfSkipData(data, abbr, unit->abbrevs);
 61.1998 +					break;
 61.1999 +				}
 61.2000 +				num   = elfReadLEB128(data, &bytes);
 61.2001 +				data += bytes;
 61.2002 +			}
 61.2003 +			array->maxBounds = index;
 61.2004 +		}
 61.2005 +		t->size = array->type->size;
 61.2006 +		for (i = 0; i < array->maxBounds; i++)
 61.2007 +			t->size *= array->bounds[i];
 61.2008 +		t->array = array;
 61.2009 +		*type    = t;
 61.2010 +		return;
 61.2011 +		break;
 61.2012 +	}
 61.2013 +	default:
 61.2014 +		fprintf(stderr, "Unknown type TAG %02x\n", abbrev->tag);
 61.2015 +		exit(-1);
 61.2016 +	}
 61.2017 +}
 61.2018 +
 61.2019 +Type *elfParseType(CompileUnit *unit, u32 offset)
 61.2020 +{
 61.2021 +	Type *t = unit->types;
 61.2022 +
 61.2023 +	while (t)
 61.2024 +	{
 61.2025 +		if (t->offset == offset)
 61.2026 +			return t;
 61.2027 +		t = t->next;
 61.2028 +	}
 61.2029 +	if (offset == 0)
 61.2030 +	{
 61.2031 +		Type *t = (Type *)calloc(sizeof(Type), 1);
 61.2032 +		t->type   = TYPE_void;
 61.2033 +		t->offset = 0;
 61.2034 +		elfAddType(t, unit, 0);
 61.2035 +		return t;
 61.2036 +	}
 61.2037 +	u8 *data = unit->top + offset;
 61.2038 +	int bytes;
 61.2039 +	int abbrevNum = elfReadLEB128(data, &bytes);
 61.2040 +	data += bytes;
 61.2041 +	Type *type = NULL;
 61.2042 +
 61.2043 +	ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum);
 61.2044 +
 61.2045 +	elfParseType(data, offset, abbrev, unit, &type);
 61.2046 +	return type;
 61.2047 +}
 61.2048 +
 61.2049 +void elfGetObjectAttributes(CompileUnit *unit, u32 offset, Object *o)
 61.2050 +{
 61.2051 +	u8 *data = unit->top + offset;
 61.2052 +	int bytes;
 61.2053 +	u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.2054 +	data += bytes;
 61.2055 +
 61.2056 +	if (!abbrevNum)
 61.2057 +	{
 61.2058 +		return;
 61.2059 +	}
 61.2060 +
 61.2061 +	ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum);
 61.2062 +
 61.2063 +	for (int i = 0; i < abbrev->numAttrs; i++)
 61.2064 +	{
 61.2065 +		ELFAttr *attr = &abbrev->attrs[i];
 61.2066 +		data = elfReadAttribute(data, attr);
 61.2067 +		switch (attr->name)
 61.2068 +		{
 61.2069 +		case DW_AT_location:
 61.2070 +			o->location = attr->block;
 61.2071 +			break;
 61.2072 +		case DW_AT_name:
 61.2073 +			if (o->name == NULL)
 61.2074 +				o->name = attr->string;
 61.2075 +			break;
 61.2076 +		case DW_AT_MIPS_linkage_name:
 61.2077 +			o->name = attr->string;
 61.2078 +			break;
 61.2079 +		case DW_AT_decl_file:
 61.2080 +			o->file = attr->value;
 61.2081 +			break;
 61.2082 +		case DW_AT_decl_line:
 61.2083 +			o->line = attr->value;
 61.2084 +			break;
 61.2085 +		case DW_AT_type:
 61.2086 +			o->type = elfParseType(unit, attr->value);
 61.2087 +			break;
 61.2088 +		case DW_AT_external:
 61.2089 +			o->external = attr->flag;
 61.2090 +			break;
 61.2091 +		case DW_AT_const_value:
 61.2092 +		case DW_AT_abstract_origin:
 61.2093 +		case DW_AT_declaration:
 61.2094 +		case DW_AT_artificial:
 61.2095 +			// todo
 61.2096 +			break;
 61.2097 +		case DW_AT_specification:
 61.2098 +			// TODO:
 61.2099 +			break;
 61.2100 +		default:
 61.2101 +			fprintf(stderr, "Unknown object attribute %02x\n", attr->name);
 61.2102 +			break;
 61.2103 +		}
 61.2104 +	}
 61.2105 +}
 61.2106 +
 61.2107 +u8 *elfParseObject(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit,
 61.2108 +                   Object **object)
 61.2109 +{
 61.2110 +	Object *o = (Object *)calloc(sizeof(Object), 1);
 61.2111 +
 61.2112 +	o->next = NULL;
 61.2113 +
 61.2114 +	for (int i = 0; i < abbrev->numAttrs; i++)
 61.2115 +	{
 61.2116 +		ELFAttr *attr = &abbrev->attrs[i];
 61.2117 +		data = elfReadAttribute(data, attr);
 61.2118 +		switch (attr->name)
 61.2119 +		{
 61.2120 +		case DW_AT_location:
 61.2121 +			o->location = attr->block;
 61.2122 +			break;
 61.2123 +		case DW_AT_name:
 61.2124 +			if (o->name == NULL)
 61.2125 +				o->name = attr->string;
 61.2126 +			break;
 61.2127 +		case DW_AT_MIPS_linkage_name:
 61.2128 +			o->name = attr->string;
 61.2129 +			break;
 61.2130 +		case DW_AT_decl_file:
 61.2131 +			o->file = attr->value;
 61.2132 +			break;
 61.2133 +		case DW_AT_decl_line:
 61.2134 +			o->line = attr->value;
 61.2135 +			break;
 61.2136 +		case DW_AT_type:
 61.2137 +			o->type = elfParseType(unit, attr->value);
 61.2138 +			break;
 61.2139 +		case DW_AT_external:
 61.2140 +			o->external = attr->flag;
 61.2141 +			break;
 61.2142 +		case DW_AT_abstract_origin:
 61.2143 +			elfGetObjectAttributes(unit, attr->value, o);
 61.2144 +			break;
 61.2145 +		case DW_AT_const_value:
 61.2146 +		case DW_AT_declaration:
 61.2147 +		case DW_AT_artificial:
 61.2148 +			break;
 61.2149 +		case DW_AT_specification:
 61.2150 +			// TODO:
 61.2151 +			break;
 61.2152 +		default:
 61.2153 +			fprintf(stderr, "Unknown object attribute %02x\n", attr->name);
 61.2154 +			break;
 61.2155 +		}
 61.2156 +	}
 61.2157 +	*object = o;
 61.2158 +	return data;
 61.2159 +}
 61.2160 +
 61.2161 +u8 *elfParseBlock(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit,
 61.2162 +                  Function *func, Object **lastVar)
 61.2163 +{
 61.2164 +	int bytes;
 61.2165 +	u32 start = func->lowPC;
 61.2166 +	u32 end   = func->highPC;
 61.2167 +
 61.2168 +	for (int i = 0; i < abbrev->numAttrs; i++)
 61.2169 +	{
 61.2170 +		ELFAttr *attr = &abbrev->attrs[i];
 61.2171 +		data = elfReadAttribute(data, attr);
 61.2172 +		switch (attr->name)
 61.2173 +		{
 61.2174 +		case DW_AT_sibling:
 61.2175 +			break;
 61.2176 +		case DW_AT_low_pc:
 61.2177 +			start = attr->value;
 61.2178 +			break;
 61.2179 +		case DW_AT_high_pc:
 61.2180 +			end = attr->value;
 61.2181 +			break;
 61.2182 +		case DW_AT_ranges: // ignore for now
 61.2183 +			break;
 61.2184 +		default:
 61.2185 +			fprintf(stderr, "Unknown block attribute %02x\n", attr->name);
 61.2186 +			break;
 61.2187 +		}
 61.2188 +	}
 61.2189 +
 61.2190 +	if (abbrev->hasChildren)
 61.2191 +	{
 61.2192 +		int nesting = 1;
 61.2193 +
 61.2194 +		while (nesting)
 61.2195 +		{
 61.2196 +			u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.2197 +			data += bytes;
 61.2198 +
 61.2199 +			if (!abbrevNum)
 61.2200 +			{
 61.2201 +				nesting--;
 61.2202 +				continue;
 61.2203 +			}
 61.2204 +
 61.2205 +			abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum);
 61.2206 +
 61.2207 +			switch (abbrev->tag)
 61.2208 +			{
 61.2209 +CASE_TYPE_TAG:       // types only parsed when used
 61.2210 +			case DW_TAG_label: // not needed
 61.2211 +				data = elfSkipData(data, abbrev, unit->abbrevs);
 61.2212 +				break;
 61.2213 +			case DW_TAG_lexical_block:
 61.2214 +				data = elfParseBlock(data, abbrev, unit, func, lastVar);
 61.2215 +				break;
 61.2216 +			case DW_TAG_subprogram:
 61.2217 +			{
 61.2218 +				Function *f = NULL;
 61.2219 +				data = elfParseFunction(data, abbrev, unit, &f);
 61.2220 +				if (f != NULL)
 61.2221 +				{
 61.2222 +					if (unit->lastFunction)
 61.2223 +						unit->lastFunction->next = f;
 61.2224 +					else
 61.2225 +						unit->functions = f;
 61.2226 +					unit->lastFunction = f;
 61.2227 +				}
 61.2228 +				break;
 61.2229 +			}
 61.2230 +			case DW_TAG_variable:
 61.2231 +			{
 61.2232 +				Object *o;
 61.2233 +				data = elfParseObject(data, abbrev, unit, &o);
 61.2234 +				if (o->startScope == 0)
 61.2235 +					o->startScope = start;
 61.2236 +				if (o->endScope == 0)
 61.2237 +					o->endScope = 0;
 61.2238 +				if (func->variables)
 61.2239 +					(*lastVar)->next = o;
 61.2240 +				else
 61.2241 +					func->variables = o;
 61.2242 +				*lastVar = o;
 61.2243 +				break;
 61.2244 +			}
 61.2245 +			case DW_TAG_inlined_subroutine:
 61.2246 +				// TODO:
 61.2247 +				data = elfSkipData(data, abbrev, unit->abbrevs);
 61.2248 +				break;
 61.2249 +			default:
 61.2250 +			{
 61.2251 +				fprintf(stderr, "Unknown block TAG %02x\n", abbrev->tag);
 61.2252 +				data = elfSkipData(data, abbrev, unit->abbrevs);
 61.2253 +				break;
 61.2254 +			}
 61.2255 +			}
 61.2256 +		}
 61.2257 +	}
 61.2258 +	return data;
 61.2259 +}
 61.2260 +
 61.2261 +void elfGetFunctionAttributes(CompileUnit *unit, u32 offset, Function *func)
 61.2262 +{
 61.2263 +	u8 *data = unit->top + offset;
 61.2264 +	int bytes;
 61.2265 +	u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.2266 +	data += bytes;
 61.2267 +
 61.2268 +	if (!abbrevNum)
 61.2269 +	{
 61.2270 +		return;
 61.2271 +	}
 61.2272 +
 61.2273 +	ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum);
 61.2274 +
 61.2275 +	for (int i = 0; i < abbrev->numAttrs; i++)
 61.2276 +	{
 61.2277 +		ELFAttr *attr = &abbrev->attrs[i];
 61.2278 +		data = elfReadAttribute(data, attr);
 61.2279 +
 61.2280 +		switch (attr->name)
 61.2281 +		{
 61.2282 +		case DW_AT_sibling:
 61.2283 +			break;
 61.2284 +		case DW_AT_name:
 61.2285 +			if (func->name == NULL)
 61.2286 +				func->name = attr->string;
 61.2287 +			break;
 61.2288 +		case DW_AT_MIPS_linkage_name:
 61.2289 +			func->name = attr->string;
 61.2290 +			break;
 61.2291 +		case DW_AT_low_pc:
 61.2292 +			func->lowPC = attr->value;
 61.2293 +			break;
 61.2294 +		case DW_AT_high_pc:
 61.2295 +			func->highPC = attr->value;
 61.2296 +			break;
 61.2297 +		case DW_AT_decl_file:
 61.2298 +			func->file = attr->value;
 61.2299 +			break;
 61.2300 +		case DW_AT_decl_line:
 61.2301 +			func->line = attr->value;
 61.2302 +			break;
 61.2303 +		case DW_AT_external:
 61.2304 +			func->external = attr->flag;
 61.2305 +			break;
 61.2306 +		case DW_AT_frame_base:
 61.2307 +			func->frameBase = attr->block;
 61.2308 +			break;
 61.2309 +		case DW_AT_type:
 61.2310 +			func->returnType = elfParseType(unit, attr->value);
 61.2311 +			break;
 61.2312 +		case DW_AT_inline:
 61.2313 +		case DW_AT_specification:
 61.2314 +		case DW_AT_declaration:
 61.2315 +		case DW_AT_artificial:
 61.2316 +		case DW_AT_prototyped:
 61.2317 +		case DW_AT_proc_body:
 61.2318 +		case DW_AT_save_offset:
 61.2319 +		case DW_AT_user_2002:
 61.2320 +		case DW_AT_virtuality:
 61.2321 +		case DW_AT_containing_type:
 61.2322 +		case DW_AT_accessibility:
 61.2323 +			// todo;
 61.2324 +			break;
 61.2325 +		case DW_AT_vtable_elem_location:
 61.2326 +			free(attr->block);
 61.2327 +			break;
 61.2328 +		default:
 61.2329 +			fprintf(stderr, "Unknown function attribute %02x\n", attr->name);
 61.2330 +			break;
 61.2331 +		}
 61.2332 +	}
 61.2333 +
 61.2334 +	return;
 61.2335 +}
 61.2336 +
 61.2337 +u8 *elfParseFunction(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit,
 61.2338 +                     Function **f)
 61.2339 +{
 61.2340 +	Function *func = (Function *)calloc(sizeof(Function), 1);
 61.2341 +	*f = func;
 61.2342 +
 61.2343 +	int  bytes;
 61.2344 +	bool mangled     = false;
 61.2345 +	bool declaration = false;
 61.2346 +	for (int i = 0; i < abbrev->numAttrs; i++)
 61.2347 +	{
 61.2348 +		ELFAttr *attr = &abbrev->attrs[i];
 61.2349 +		data = elfReadAttribute(data, attr);
 61.2350 +		switch (attr->name)
 61.2351 +		{
 61.2352 +		case DW_AT_sibling:
 61.2353 +			break;
 61.2354 +		case DW_AT_name:
 61.2355 +			if (func->name == NULL)
 61.2356 +				func->name = attr->string;
 61.2357 +			break;
 61.2358 +		case DW_AT_MIPS_linkage_name:
 61.2359 +			func->name = attr->string;
 61.2360 +			mangled    = true;
 61.2361 +			break;
 61.2362 +		case DW_AT_low_pc:
 61.2363 +			func->lowPC = attr->value;
 61.2364 +			break;
 61.2365 +		case DW_AT_high_pc:
 61.2366 +			func->highPC = attr->value;
 61.2367 +			break;
 61.2368 +		case DW_AT_prototyped:
 61.2369 +			break;
 61.2370 +		case DW_AT_decl_file:
 61.2371 +			func->file = attr->value;
 61.2372 +			break;
 61.2373 +		case DW_AT_decl_line:
 61.2374 +			func->line = attr->value;
 61.2375 +			break;
 61.2376 +		case DW_AT_external:
 61.2377 +			func->external = attr->flag;
 61.2378 +			break;
 61.2379 +		case DW_AT_frame_base:
 61.2380 +			func->frameBase = attr->block;
 61.2381 +			break;
 61.2382 +		case DW_AT_type:
 61.2383 +			func->returnType = elfParseType(unit, attr->value);
 61.2384 +			break;
 61.2385 +		case DW_AT_abstract_origin:
 61.2386 +			elfGetFunctionAttributes(unit, attr->value, func);
 61.2387 +			break;
 61.2388 +		case DW_AT_declaration:
 61.2389 +			declaration = attr->flag;
 61.2390 +			break;
 61.2391 +		case DW_AT_inline:
 61.2392 +		case DW_AT_specification:
 61.2393 +		case DW_AT_artificial:
 61.2394 +		case DW_AT_proc_body:
 61.2395 +		case DW_AT_save_offset:
 61.2396 +		case DW_AT_user_2002:
 61.2397 +		case DW_AT_virtuality:
 61.2398 +		case DW_AT_containing_type:
 61.2399 +		case DW_AT_accessibility:
 61.2400 +			// todo;
 61.2401 +			break;
 61.2402 +		case DW_AT_vtable_elem_location:
 61.2403 +			free(attr->block);
 61.2404 +			break;
 61.2405 +		default:
 61.2406 +			fprintf(stderr, "Unknown function attribute %02x\n", attr->name);
 61.2407 +			break;
 61.2408 +		}
 61.2409 +	}
 61.2410 +
 61.2411 +	if (declaration)
 61.2412 +	{
 61.2413 +		elfCleanUp(func);
 61.2414 +		free(func);
 61.2415 +		*f = NULL;
 61.2416 +
 61.2417 +		while (1)
 61.2418 +		{
 61.2419 +			u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.2420 +			data += bytes;
 61.2421 +
 61.2422 +			if (!abbrevNum)
 61.2423 +			{
 61.2424 +				return data;
 61.2425 +			}
 61.2426 +
 61.2427 +			abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum);
 61.2428 +
 61.2429 +			data = elfSkipData(data, abbrev, unit->abbrevs);
 61.2430 +		}
 61.2431 +	}
 61.2432 +
 61.2433 +	if (abbrev->hasChildren)
 61.2434 +	{
 61.2435 +		int     nesting   = 1;
 61.2436 +		Object *lastParam = NULL;
 61.2437 +		Object *lastVar   = NULL;
 61.2438 +
 61.2439 +		while (nesting)
 61.2440 +		{
 61.2441 +			u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.2442 +			data += bytes;
 61.2443 +
 61.2444 +			if (!abbrevNum)
 61.2445 +			{
 61.2446 +				nesting--;
 61.2447 +				continue;
 61.2448 +			}
 61.2449 +
 61.2450 +			abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum);
 61.2451 +
 61.2452 +			switch (abbrev->tag)
 61.2453 +			{
 61.2454 +CASE_TYPE_TAG:       // no need to parse types. only parsed when used
 61.2455 +			case DW_TAG_label: // not needed
 61.2456 +				data = elfSkipData(data, abbrev, unit->abbrevs);
 61.2457 +				break;
 61.2458 +			case DW_TAG_subprogram:
 61.2459 +			{
 61.2460 +				Function *fnc = NULL;
 61.2461 +				data = elfParseFunction(data, abbrev, unit, &fnc);
 61.2462 +				if (fnc != NULL)
 61.2463 +				{
 61.2464 +					if (unit->lastFunction == NULL)
 61.2465 +						unit->functions = fnc;
 61.2466 +					else
 61.2467 +						unit->lastFunction->next = fnc;
 61.2468 +					unit->lastFunction = fnc;
 61.2469 +				}
 61.2470 +				break;
 61.2471 +			}
 61.2472 +			case DW_TAG_lexical_block:
 61.2473 +			{
 61.2474 +				data = elfParseBlock(data, abbrev, unit, func, &lastVar);
 61.2475 +				break;
 61.2476 +			}
 61.2477 +			case DW_TAG_formal_parameter:
 61.2478 +			{
 61.2479 +				Object *o;
 61.2480 +				data = elfParseObject(data, abbrev, unit, &o);
 61.2481 +				if (func->parameters)
 61.2482 +					lastParam->next = o;
 61.2483 +				else
 61.2484 +					func->parameters = o;
 61.2485 +				lastParam = o;
 61.2486 +				break;
 61.2487 +			}
 61.2488 +			case DW_TAG_variable:
 61.2489 +			{
 61.2490 +				Object *o;
 61.2491 +				data = elfParseObject(data, abbrev, unit, &o);
 61.2492 +				if (func->variables)
 61.2493 +					lastVar->next = o;
 61.2494 +				else
 61.2495 +					func->variables = o;
 61.2496 +				lastVar = o;
 61.2497 +				break;
 61.2498 +			}
 61.2499 +			case DW_TAG_unspecified_parameters:
 61.2500 +			case DW_TAG_inlined_subroutine:
 61.2501 +			{
 61.2502 +				// todo
 61.2503 +				for (int i = 0; i < abbrev->numAttrs; i++)
 61.2504 +				{
 61.2505 +					data = elfReadAttribute(data,  &abbrev->attrs[i]);
 61.2506 +					if (abbrev->attrs[i].form == DW_FORM_block1)
 61.2507 +						free(abbrev->attrs[i].block);
 61.2508 +				}
 61.2509 +
 61.2510 +				if (abbrev->hasChildren)
 61.2511 +					nesting++;
 61.2512 +				break;
 61.2513 +			}
 61.2514 +			default:
 61.2515 +			{
 61.2516 +				fprintf(stderr, "Unknown function TAG %02x\n", abbrev->tag);
 61.2517 +				data = elfSkipData(data, abbrev, unit->abbrevs);
 61.2518 +				break;
 61.2519 +			}
 61.2520 +			}
 61.2521 +		}
 61.2522 +	}
 61.2523 +	return data;
 61.2524 +}
 61.2525 +
 61.2526 +u8 *elfParseUnknownData(u8 *data, ELFAbbrev *abbrev, ELFAbbrev **abbrevs)
 61.2527 +{
 61.2528 +	int i;
 61.2529 +	int bytes;
 61.2530 +	//  switch(abbrev->tag) {
 61.2531 +	//  default:
 61.2532 +	fprintf(stderr, "Unknown TAG %02x\n", abbrev->tag);
 61.2533 +
 61.2534 +	for (i = 0; i < abbrev->numAttrs; i++)
 61.2535 +	{
 61.2536 +		data = elfReadAttribute(data,  &abbrev->attrs[i]);
 61.2537 +		if (abbrev->attrs[i].form == DW_FORM_block1)
 61.2538 +			free(abbrev->attrs[i].block);
 61.2539 +	}
 61.2540 +
 61.2541 +	if (abbrev->hasChildren)
 61.2542 +	{
 61.2543 +		int nesting = 1;
 61.2544 +		while (nesting)
 61.2545 +		{
 61.2546 +			u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.2547 +			data += bytes;
 61.2548 +
 61.2549 +			if (!abbrevNum)
 61.2550 +			{
 61.2551 +				nesting--;
 61.2552 +				continue;
 61.2553 +			}
 61.2554 +
 61.2555 +			abbrev = elfGetAbbrev(abbrevs, abbrevNum);
 61.2556 +
 61.2557 +			fprintf(stderr, "Unknown TAG %02x\n", abbrev->tag);
 61.2558 +
 61.2559 +			for (i = 0; i < abbrev->numAttrs; i++)
 61.2560 +			{
 61.2561 +				data = elfReadAttribute(data,  &abbrev->attrs[i]);
 61.2562 +				if (abbrev->attrs[i].form == DW_FORM_block1)
 61.2563 +					free(abbrev->attrs[i].block);
 61.2564 +			}
 61.2565 +
 61.2566 +			if (abbrev->hasChildren)
 61.2567 +			{
 61.2568 +				nesting++;
 61.2569 +			}
 61.2570 +		}
 61.2571 +	}
 61.2572 +	//  }
 61.2573 +	return data;
 61.2574 +}
 61.2575 +
 61.2576 +u8 *elfParseCompileUnitChildren(u8 *data, CompileUnit *unit)
 61.2577 +{
 61.2578 +	int bytes;
 61.2579 +	u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.2580 +	data += bytes;
 61.2581 +	Object *lastObj = NULL;
 61.2582 +	while (abbrevNum)
 61.2583 +	{
 61.2584 +		ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum);
 61.2585 +		switch (abbrev->tag)
 61.2586 +		{
 61.2587 +		case DW_TAG_subprogram:
 61.2588 +		{
 61.2589 +			Function *func = NULL;
 61.2590 +			data = elfParseFunction(data, abbrev, unit, &func);
 61.2591 +			if (func != NULL)
 61.2592 +			{
 61.2593 +				if (unit->lastFunction)
 61.2594 +					unit->lastFunction->next = func;
 61.2595 +				else
 61.2596 +					unit->functions = func;
 61.2597 +				unit->lastFunction = func;
 61.2598 +			}
 61.2599 +			break;
 61.2600 +		}
 61.2601 +CASE_TYPE_TAG:
 61.2602 +			data = elfSkipData(data, abbrev, unit->abbrevs);
 61.2603 +			break;
 61.2604 +		case DW_TAG_variable:
 61.2605 +		{
 61.2606 +			Object *var = NULL;
 61.2607 +			data = elfParseObject(data, abbrev, unit, &var);
 61.2608 +			if (lastObj)
 61.2609 +				lastObj->next = var;
 61.2610 +			else
 61.2611 +				unit->variables = var;
 61.2612 +			lastObj = var;
 61.2613 +			break;
 61.2614 +		}
 61.2615 +		default:
 61.2616 +			data = elfParseUnknownData(data, abbrev, unit->abbrevs);
 61.2617 +			break;
 61.2618 +		}
 61.2619 +
 61.2620 +		abbrevNum = elfReadLEB128(data, &bytes);
 61.2621 +		data     += bytes;
 61.2622 +	}
 61.2623 +	return data;
 61.2624 +}
 61.2625 +
 61.2626 +CompileUnit *elfParseCompUnit(u8 *data, u8 *abbrevData)
 61.2627 +{
 61.2628 +	int bytes;
 61.2629 +	u8 *top = data;
 61.2630 +
 61.2631 +	u32 length = elfRead4Bytes(data);
 61.2632 +	data += 4;
 61.2633 +
 61.2634 +	u16 version = elfRead2Bytes(data);
 61.2635 +	data += 2;
 61.2636 +
 61.2637 +	u32 offset = elfRead4Bytes(data);
 61.2638 +	data += 4;
 61.2639 +
 61.2640 +	u8 addrSize = *data++;
 61.2641 +
 61.2642 +	if (version != 2)
 61.2643 +	{
 61.2644 +		fprintf(stderr, "Unsupported debugging information version %d\n", version);
 61.2645 +		return NULL;
 61.2646 +	}
 61.2647 +
 61.2648 +	if (addrSize != 4)
 61.2649 +	{
 61.2650 +		fprintf(stderr, "Unsupported address size %d\n", addrSize);
 61.2651 +		return NULL;
 61.2652 +	}
 61.2653 +
 61.2654 +	ELFAbbrev **abbrevs = elfReadAbbrevs(abbrevData, offset);
 61.2655 +
 61.2656 +	u32 abbrevNum = elfReadLEB128(data, &bytes);
 61.2657 +	data += bytes;
 61.2658 +
 61.2659 +	ELFAbbrev *abbrev = elfGetAbbrev(abbrevs, abbrevNum);
 61.2660 +
 61.2661 +	CompileUnit *unit = (CompileUnit *)calloc(sizeof(CompileUnit), 1);
 61.2662 +	unit->top     = top;
 61.2663 +	unit->length  = length;
 61.2664 +	unit->abbrevs = abbrevs;
 61.2665 +	unit->next    = NULL;
 61.2666 +
 61.2667 +	elfCurrentUnit = unit;
 61.2668 +
 61.2669 +	int i;
 61.2670 +
 61.2671 +	for (i = 0; i < abbrev->numAttrs; i++)
 61.2672 +	{
 61.2673 +		ELFAttr *attr = &abbrev->attrs[i];
 61.2674 +		data = elfReadAttribute(data, attr);
 61.2675 +
 61.2676 +		switch (attr->name)
 61.2677 +		{
 61.2678 +		case DW_AT_name:
 61.2679 +			unit->name = attr->string;
 61.2680 +			break;
 61.2681 +		case DW_AT_stmt_list:
 61.2682 +			unit->hasLineInfo = true;
 61.2683 +			unit->lineInfo    = attr->value;
 61.2684 +			break;
 61.2685 +		case DW_AT_low_pc:
 61.2686 +			unit->lowPC = attr->value;
 61.2687 +			break;
 61.2688 +		case DW_AT_high_pc:
 61.2689 +			unit->highPC = attr->value;
 61.2690 +			break;
 61.2691 +		case DW_AT_compdir:
 61.2692 +			unit->compdir = attr->string;
 61.2693 +			break;
 61.2694 +		// ignore
 61.2695 +		case DW_AT_language:
 61.2696 +		case DW_AT_producer:
 61.2697 +		case DW_AT_macro_info:
 61.2698 +		case DW_AT_entry_pc:
 61.2699 +			break;
 61.2700 +		default:
 61.2701 +			fprintf(stderr, "Unknown attribute %02x\n", attr->name);
 61.2702 +			break;
 61.2703 +		}
 61.2704 +	}
 61.2705 +
 61.2706 +	if (abbrev->hasChildren)
 61.2707 +		elfParseCompileUnitChildren(data, unit);
 61.2708 +
 61.2709 +	return unit;
 61.2710 +}
 61.2711 +
 61.2712 +void elfParseAranges(u8 *data)
 61.2713 +{
 61.2714 +	ELFSectionHeader *sh = elfGetSectionByName(".debug_aranges");
 61.2715 +	if (sh == NULL)
 61.2716 +	{
 61.2717 +		fprintf(stderr, "No aranges found\n");
 61.2718 +		return;
 61.2719 +	}
 61.2720 +
 61.2721 +	data = elfReadSection(data, sh);
 61.2722 +	u8 *end = data + READ32LE(&sh->size);
 61.2723 +
 61.2724 +	int      max    = 4;
 61.2725 +	ARanges *ranges = (ARanges *)calloc(sizeof(ARanges), 4);
 61.2726 +
 61.2727 +	int index = 0;
 61.2728 +
 61.2729 +	while (data < end)
 61.2730 +	{
 61.2731 +		u32 len = elfRead4Bytes(data);
 61.2732 +		data += 4;
 61.2733 +		//    u16 version = elfRead2Bytes(data);
 61.2734 +		data += 2;
 61.2735 +		u32 offset = elfRead4Bytes(data);
 61.2736 +		data += 4;
 61.2737 +		//    u8 addrSize = *data++;
 61.2738 +		//    u8 segSize = *data++;
 61.2739 +		data += 2; // remove if uncommenting above
 61.2740 +		data += 4;
 61.2741 +		ranges[index].count  = (len-20)/8;
 61.2742 +		ranges[index].offset = offset;
 61.2743 +		ranges[index].ranges = (ARange *)calloc(sizeof(ARange), (len-20)/8);
 61.2744 +		int i = 0;
 61.2745 +		while (true)
 61.2746 +		{
 61.2747 +			u32 addr = elfRead4Bytes(data);
 61.2748 +			data += 4;
 61.2749 +			u32 len = elfRead4Bytes(data);
 61.2750 +			data += 4;
 61.2751 +			if (addr == 0 && len == 0)
 61.2752 +				break;
 61.2753 +			ranges[index].ranges[i].lowPC  = addr;
 61.2754 +			ranges[index].ranges[i].highPC = addr+len;
 61.2755 +			i++;
 61.2756 +		}
 61.2757 +		index++;
 61.2758 +		if (index == max)
 61.2759 +		{
 61.2760 +			max   += 4;
 61.2761 +			ranges = (ARanges *)realloc(ranges, max*sizeof(ARanges));
 61.2762 +		}
 61.2763 +	}
 61.2764 +	elfDebugInfo->numRanges = index;
 61.2765 +	elfDebugInfo->ranges    = ranges;
 61.2766 +}
 61.2767 +
 61.2768 +void elfReadSymtab(u8 *data)
 61.2769 +{
 61.2770 +	ELFSectionHeader *sh = elfGetSectionByName(".symtab");
 61.2771 +	int table = READ32LE(&sh->link);
 61.2772 +
 61.2773 +	char *strtable = (char *)elfReadSection(data, elfGetSectionByNumber(table));
 61.2774 +
 61.2775 +	ELFSymbol *symtab = (ELFSymbol *)elfReadSection(data, sh);
 61.2776 +
 61.2777 +	int count = READ32LE(&sh->size) / sizeof(ELFSymbol);
 61.2778 +	elfSymbolsCount = 0;
 61.2779 +
 61.2780 +	elfSymbols = (Symbol *)malloc(sizeof(Symbol)*count);
 61.2781 +
 61.2782 +	int i;
 61.2783 +
 61.2784 +	for (i = 0; i < count; i++)
 61.2785 +	{
 61.2786 +		ELFSymbol *s       = &symtab[i];
 61.2787 +		int        type    = s->info & 15;
 61.2788 +		int        binding = s->info >> 4;
 61.2789 +
 61.2790 +		if (binding)
 61.2791 +		{
 61.2792 +			Symbol *sym = &elfSymbols[elfSymbolsCount];
 61.2793 +			sym->name    = &strtable[READ32LE(&s->name)];
 61.2794 +			sym->binding = binding;
 61.2795 +			sym->type    = type;
 61.2796 +			sym->value   = READ32LE(&s->value);
 61.2797 +			sym->size    = READ32LE(&s->size);
 61.2798 +			elfSymbolsCount++;
 61.2799 +		}
 61.2800 +	}
 61.2801 +	for (i = 0; i < count; i++)
 61.2802 +	{
 61.2803 +		ELFSymbol *s    = &symtab[i];
 61.2804 +		int        bind = s->info>>4;
 61.2805 +		int        type = s->info & 15;
 61.2806 +
 61.2807 +		if (!bind)
 61.2808 +		{
 61.2809 +			Symbol *sym = &elfSymbols[elfSymbolsCount];
 61.2810 +			sym->name    = &strtable[READ32LE(&s->name)];
 61.2811 +			sym->binding = (s->info >> 4);
 61.2812 +			sym->type    = type;
 61.2813 +			sym->value   = READ32LE(&s->value);
 61.2814 +			sym->size    = READ32LE(&s->size);
 61.2815 +			elfSymbolsCount++;
 61.2816 +		}
 61.2817 +	}
 61.2818 +	elfSymbolsStrTab = strtable;
 61.2819 +	//  free(symtab);
 61.2820 +}
 61.2821 +
 61.2822 +bool elfReadProgram(ELFHeader *eh, u8 *data, int& size, bool parseDebug)
 61.2823 +{
 61.2824 +	int count = READ16LE(&eh->e_phnum);
 61.2825 +	int i;
 61.2826 +
 61.2827 +	if (READ32LE(&eh->e_entry) == 0x2000000)
 61.2828 +		cpuIsMultiBoot = true;
 61.2829 +
 61.2830 +	// read program headers... should probably move this code down
 61.2831 +	u8 *p = data + READ32LE(&eh->e_phoff);
 61.2832 +	size = 0;
 61.2833 +	for (i = 0; i < count; i++)
 61.2834 +	{
 61.2835 +		ELFProgramHeader *ph = (ELFProgramHeader *)p;
 61.2836 +		p += sizeof(ELFProgramHeader);
 61.2837 +		if (READ16LE(&eh->e_phentsize) != sizeof(ELFProgramHeader))
 61.2838 +		{
 61.2839 +			p += READ16LE(&eh->e_phentsize) - sizeof(ELFProgramHeader);
 61.2840 +		}
 61.2841 +
 61.2842 +		//    printf("PH %d %08x %08x %08x %08x %08x %08x %08x %08x\n",
 61.2843 +		//     i, ph->type, ph->offset, ph->vaddr, ph->paddr,
 61.2844 +		//     ph->filesz, ph->memsz, ph->flags, ph->align);
 61.2845 +		if (cpuIsMultiBoot)
 61.2846 +		{
 61.2847 +			if (READ32LE(&ph->paddr) >= 0x2000000 &&
 61.2848 +			    READ32LE(&ph->paddr) <= 0x203ffff)
 61.2849 +			{
 61.2850 +				memcpy(&workRAM[READ32LE(&ph->paddr) & 0x3ffff],
 61.2851 +				       data + READ32LE(&ph->offset),
 61.2852 +				       READ32LE(&ph->filesz));
 61.2853 +			}
 61.2854 +		}
 61.2855 +		else
 61.2856 +		{
 61.2857 +			if (READ32LE(&ph->paddr) >= 0x8000000 &&
 61.2858 +			    READ32LE(&ph->paddr) <= 0x9ffffff)
 61.2859 +			{
 61.2860 +				memcpy(&rom[READ32LE(&ph->paddr) & 0x1ffffff],
 61.2861 +				       data + READ32LE(&ph->offset),
 61.2862 +				       READ32LE(&ph->filesz));
 61.2863 +				size += READ32LE(&ph->filesz);
 61.2864 +			}
 61.2865 +		}
 61.2866 +	}
 61.2867 +
 61.2868 +	char *stringTable = NULL;
 61.2869 +
 61.2870 +	// read section headers
 61.2871 +	p     = data + READ32LE(&eh->e_shoff);
 61.2872 +	count = READ16LE(&eh->e_shnum);
 61.2873 +
 61.2874 +	ELFSectionHeader **sh = (ELFSectionHeader * *)
 61.2875 +	                        malloc(sizeof(ELFSectionHeader *) * count);
 61.2876 +
 61.2877 +	for (i = 0; i < count; i++)
 61.2878 +	{
 61.2879 +		sh[i] = (ELFSectionHeader *)p;
 61.2880 +		p    += sizeof(ELFSectionHeader);
 61.2881 +		if (READ16LE(&eh->e_shentsize) != sizeof(ELFSectionHeader))
 61.2882 +			p += READ16LE(&eh->e_shentsize) - sizeof(ELFSectionHeader);
 61.2883 +	}
 61.2884 +
 61.2885 +	if (READ16LE(&eh->e_shstrndx) != 0)
 61.2886 +	{
 61.2887 +		stringTable = (char *)elfReadSection(data,
 61.2888 +		                                     sh[READ16LE(&eh->e_shstrndx)]);
 61.2889 +	}
 61.2890 +
 61.2891 +	elfSectionHeaders = sh;
 61.2892 +	elfSectionHeadersStringTable = stringTable;
 61.2893 +	elfSectionHeadersCount       = count;
 61.2894 +
 61.2895 +	for (i = 0; i < count; i++)
 61.2896 +	{
 61.2897 +		//    printf("SH %d %-20s %08x %08x %08x %08x %08x %08x %08x %08x\n",
 61.2898 +		//   i, &stringTable[sh[i]->name], sh[i]->name, sh[i]->type,
 61.2899 +		//   sh[i]->flags, sh[i]->addr, sh[i]->offset, sh[i]->size,
 61.2900 +		//   sh[i]->link, sh[i]->info);
 61.2901 +		if (READ32LE(&sh[i]->flags) & 2) // load section
 61.2902 +		{
 61.2903 +			if (cpuIsMultiBoot)
 61.2904 +			{
 61.2905 +				if (READ32LE(&sh[i]->addr) >= 0x2000000 &&
 61.2906 +				    READ32LE(&sh[i]->addr) <= 0x203ffff)
 61.2907 +				{
 61.2908 +					memcpy(&workRAM[READ32LE(&sh[i]->addr) & 0x3ffff], data +
 61.2909 +					       READ32LE(&sh[i]->offset),
 61.2910 +					       READ32LE(&sh[i]->size));
 61.2911 +				}
 61.2912 +			}
 61.2913 +			else
 61.2914 +			{
 61.2915 +				if (READ32LE(&sh[i]->addr) >= 0x8000000 &&
 61.2916 +				    READ32LE(&sh[i]->addr) <= 0x9ffffff)
 61.2917 +				{
 61.2918 +					memcpy(&rom[READ32LE(&sh[i]->addr) & 0x1ffffff],
 61.2919 +					       data + READ32LE(&sh[i]->offset),
 61.2920 +					       READ32LE(&sh[i]->size));
 61.2921 +					size += READ32LE(&sh[i]->size);
 61.2922 +				}
 61.2923 +			}
 61.2924 +		}
 61.2925 +	}
 61.2926 +
 61.2927 +	if (parseDebug)
 61.2928 +	{
 61.2929 +		fprintf(stderr, "Parsing debug info\n");
 61.2930 +
 61.2931 +		ELFSectionHeader *dbgHeader = elfGetSectionByName(".debug_info");
 61.2932 +		if (dbgHeader == NULL)
 61.2933 +		{
 61.2934 +			fprintf(stderr, "Cannot find debug information\n");
 61.2935 +			goto end;
 61.2936 +		}
 61.2937 +
 61.2938 +		ELFSectionHeader *h = elfGetSectionByName(".debug_abbrev");
 61.2939 +		if (h == NULL)
 61.2940 +		{
 61.2941 +			fprintf(stderr, "Cannot find abbreviation table\n");
 61.2942 +			goto end;
 61.2943 +		}
 61.2944 +
 61.2945 +		elfDebugInfo = (DebugInfo *)calloc(sizeof(DebugInfo), 1);
 61.2946 +		u8 *abbrevdata = elfReadSection(data, h);
 61.2947 +
 61.2948 +		h = elfGetSectionByName(".debug_str");
 61.2949 +
 61.2950 +		if (h == NULL)
 61.2951 +			elfDebugStrings = NULL;
 61.2952 +		else
 61.2953 +			elfDebugStrings = (char *)elfReadSection(data, h);
 61.2954 +
 61.2955 +		u8 *debugdata = elfReadSection(data, dbgHeader);
 61.2956 +
 61.2957 +		elfDebugInfo->debugdata = data;
 61.2958 +		elfDebugInfo->infodata  = debugdata;
 61.2959 +
 61.2960 +		u32 total = READ32LE(&dbgHeader->size);
 61.2961 +		u8 *end   = debugdata + total;
 61.2962 +		u8 *ddata = debugdata;
 61.2963 +
 61.2964 +		CompileUnit *last = NULL;
 61.2965 +		CompileUnit *unit = NULL;
 61.2966 +
 61.2967 +		while (ddata < end)
 61.2968 +		{
 61.2969 +			unit         = elfParseCompUnit(ddata, abbrevdata);
 61.2970 +			unit->offset = ddata-debugdata;
 61.2971 +			elfParseLineInfo(unit, data);
 61.2972 +			if (last == NULL)
 61.2973 +				elfCompileUnits = unit;
 61.2974 +			else
 61.2975 +				last->next = unit;
 61.2976 +			last   = unit;
 61.2977 +			ddata += 4 + unit->length;
 61.2978 +		}
 61.2979 +		elfParseAranges(data);
 61.2980 +		CompileUnit *comp = elfCompileUnits;
 61.2981 +		while (comp)
 61.2982 +		{
 61.2983 +			ARanges *r = elfDebugInfo->ranges;
 61.2984 +			for (int i = 0; i < elfDebugInfo->numRanges; i++)
 61.2985 +				if (r[i].offset == comp->offset)
 61.2986 +				{
 61.2987 +					comp->ranges = &r[i];
 61.2988 +					break;
 61.2989 +				}
 61.2990 +			comp = comp->next;
 61.2991 +		}
 61.2992 +		elfParseCFA(data);
 61.2993 +		elfReadSymtab(data);
 61.2994 +	}
 61.2995 +end:
 61.2996 +	if (sh)
 61.2997 +	{
 61.2998 +		free(sh);
 61.2999 +	}
 61.3000 +
 61.3001 +	elfSectionHeaders = NULL;
 61.3002 +	elfSectionHeadersStringTable = NULL;
 61.3003 +	elfSectionHeadersCount       = 0;
 61.3004 +
 61.3005 +	return true;
 61.3006 +}
 61.3007 +
 61.3008 +extern bool8 parseDebug;
 61.3009 +
 61.3010 +bool elfRead(const char *name, int& siz, FILE *f)
 61.3011 +{
 61.3012 +	fseek(f, 0, SEEK_END);
 61.3013 +	long size = ftell(f);
 61.3014 +	elfFileData = (u8 *)malloc(size);
 61.3015 +	fseek(f, 0, SEEK_SET);
 61.3016 +	fread(elfFileData, 1, size, f);
 61.3017 +	fclose(f);
 61.3018 +
 61.3019 +	ELFHeader *header = (ELFHeader *)elfFileData;
 61.3020 +
 61.3021 +	if (READ32LE(&header->magic) != 0x464C457F ||
 61.3022 +	    READ16LE(&header->e_machine) != 40 ||
 61.3023 +	    header->clazz != 1)
 61.3024 +	{
 61.3025 +		systemMessage(0, N_("Not a valid ELF file %s"), name);
 61.3026 +		free(elfFileData);
 61.3027 +		elfFileData = NULL;
 61.3028 +		return false;
 61.3029 +	}
 61.3030 +
 61.3031 +	if (!elfReadProgram(header, elfFileData, siz, parseDebug))
 61.3032 +	{
 61.3033 +		free(elfFileData);
 61.3034 +		elfFileData = NULL;
 61.3035 +		return false;
 61.3036 +	}
 61.3037 +
 61.3038 +	return true;
 61.3039 +}
 61.3040 +
 61.3041 +void elfCleanUp(Object *o)
 61.3042 +{
 61.3043 +	free(o->location);
 61.3044 +}
 61.3045 +
 61.3046 +void elfCleanUp(Function *func)
 61.3047 +{
 61.3048 +	Object *o = func->parameters;
 61.3049 +	while (o)
 61.3050 +	{
 61.3051 +		elfCleanUp(o);
 61.3052 +		Object *next = o->next;
 61.3053 +		free(o);
 61.3054 +		o = next;
 61.3055 +	}
 61.3056 +
 61.3057 +	o = func->variables;
 61.3058 +	while (o)
 61.3059 +	{
 61.3060 +		elfCleanUp(o);
 61.3061 +		Object *next = o->next;
 61.3062 +		free(o);
 61.3063 +		o = next;
 61.3064 +	}
 61.3065 +	free(func->frameBase);
 61.3066 +}
 61.3067 +
 61.3068 +void elfCleanUp(ELFAbbrev **abbrevs)
 61.3069 +{
 61.3070 +	for (int i = 0; i < 121; i++)
 61.3071 +	{
 61.3072 +		ELFAbbrev *abbrev = abbrevs[i];
 61.3073 +
 61.3074 +		while (abbrev)
 61.3075 +		{
 61.3076 +			free(abbrev->attrs);
 61.3077 +			ELFAbbrev *next = abbrev->next;
 61.3078 +			free(abbrev);
 61.3079 +
 61.3080 +			abbrev = next;
 61.3081 +		}
 61.3082 +	}
 61.3083 +}
 61.3084 +
 61.3085 +void elfCleanUp(Type *t)
 61.3086 +{
 61.3087 +	switch (t->type)
 61.3088 +	{
 61.3089 +	case TYPE_function:
 61.3090 +		if (t->function)
 61.3091 +		{
 61.3092 +			Object *o = t->function->args;
 61.3093 +			while (o)
 61.3094 +			{
 61.3095 +				elfCleanUp(o);
 61.3096 +				Object *next = o->next;
 61.3097 +				free(o);
 61.3098 +				o = next;
 61.3099 +			}
 61.3100 +			free(t->function);
 61.3101 +		}
 61.3102 +		break;
 61.3103 +	case TYPE_array:
 61.3104 +		if (t->array)
 61.3105 +		{
 61.3106 +			free(t->array->bounds);
 61.3107 +			free(t->array);
 61.3108 +		}
 61.3109 +		break;
 61.3110 +	case TYPE_struct:
 61.3111 +	case TYPE_union:
 61.3112 +		if (t->structure)
 61.3113 +		{
 61.3114 +			for (int i = 0; i < t->structure->memberCount; i++)
 61.3115 +			{
 61.3116 +				free(t->structure->members[i].location);
 61.3117 +			}
 61.3118 +			free(t->structure->members);
 61.3119 +			free(t->structure);
 61.3120 +		}
 61.3121 +		break;
 61.3122 +	case TYPE_enum:
 61.3123 +		if (t->enumeration)
 61.3124 +		{
 61.3125 +			free(t->enumeration->members);
 61.3126 +			free(t->enumeration);
 61.3127 +		}
 61.3128 +		break;
 61.3129 +	case TYPE_base:
 61.3130 +	case TYPE_pointer:
 61.3131 +	case TYPE_void:
 61.3132 +	case TYPE_reference:
 61.3133 +		break; // nothing to do
 61.3134 +	}
 61.3135 +}
 61.3136 +
 61.3137 +void elfCleanUp(CompileUnit *comp)
 61.3138 +{
 61.3139 +	elfCleanUp(comp->abbrevs);
 61.3140 +	free(comp->abbrevs);
 61.3141 +	Function *func = comp->functions;
 61.3142 +	while (func)
 61.3143 +	{
 61.3144 +		elfCleanUp(func);
 61.3145 +		Function *next = func->next;
 61.3146 +		free(func);
 61.3147 +		func = next;
 61.3148 +	}
 61.3149 +	Type *t = comp->types;
 61.3150 +	while (t)
 61.3151 +	{
 61.3152 +		elfCleanUp(t);
 61.3153 +		Type *next = t->next;
 61.3154 +		free(t);
 61.3155 +		t = next;
 61.3156 +	}
 61.3157 +	Object *o = comp->variables;
 61.3158 +	while (o)
 61.3159 +	{
 61.3160 +		elfCleanUp(o);
 61.3161 +		Object *next = o->next;
 61.3162 +		free(o);
 61.3163 +		o = next;
 61.3164 +	}
 61.3165 +	if (comp->lineInfoTable)
 61.3166 +	{
 61.3167 +		free(comp->lineInfoTable->lines);
 61.3168 +		free(comp->lineInfoTable->files);
 61.3169 +		free(comp->lineInfoTable);
 61.3170 +	}
 61.3171 +}
 61.3172 +
 61.3173 +void elfCleanUp()
 61.3174 +{
 61.3175 +	CompileUnit *comp = elfCompileUnits;
 61.3176 +
 61.3177 +	while (comp)
 61.3178 +	{
 61.3179 +		elfCleanUp(comp);
 61.3180 +		CompileUnit *next = comp->next;
 61.3181 +		free(comp);
 61.3182 +		comp = next;
 61.3183 +	}
 61.3184 +	elfCompileUnits = NULL;
 61.3185 +	free(elfSymbols);
 61.3186 +	elfSymbols = NULL;
 61.3187 +	//  free(elfSymbolsStrTab);
 61.3188 +	elfSymbolsStrTab = NULL;
 61.3189 +
 61.3190 +	elfDebugStrings = NULL;
 61.3191 +	if (elfDebugInfo)
 61.3192 +	{
 61.3193 +		int num = elfDebugInfo->numRanges;
 61.3194 +		int i;
 61.3195 +		for (i = 0; i < num; i++)
 61.3196 +		{
 61.3197 +			free(elfDebugInfo->ranges[i].ranges);
 61.3198 +		}
 61.3199 +		free(elfDebugInfo->ranges);
 61.3200 +		free(elfDebugInfo);
 61.3201 +		elfDebugInfo = NULL;
 61.3202 +	}
 61.3203 +
 61.3204 +	if (elfFdes)
 61.3205 +	{
 61.3206 +		if (elfFdeCount)
 61.3207 +		{
 61.3208 +			for (int i = 0; i < elfFdeCount; i++)
 61.3209 +				free(elfFdes[i]);
 61.3210 +		}
 61.3211 +		free(elfFdes);
 61.3212 +
 61.3213 +		elfFdes     = NULL;
 61.3214 +		elfFdeCount = 0;
 61.3215 +	}
 61.3216 +
 61.3217 +	ELFcie *cie = elfCies;
 61.3218 +	while (cie)
 61.3219 +	{
 61.3220 +		ELFcie *next = cie->next;
 61.3221 +		free(cie);
 61.3222 +		cie = next;
 61.3223 +	}
 61.3224 +	elfCies = NULL;
 61.3225 +
 61.3226 +	if (elfFileData)
 61.3227 +	{
 61.3228 +		free(elfFileData);
 61.3229 +		elfFileData = NULL;
 61.3230 +	}
 61.3231 +}
 61.3232 +
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/src/gba/elf.h	Sun Mar 04 14:33:52 2012 -0600
    62.3 @@ -0,0 +1,296 @@
    62.4 +#ifndef VBA_ELF_H
    62.5 +#define VBA_ELF_H
    62.6 +
    62.7 +#if _MSC_VER > 1000
    62.8 +#pragma once
    62.9 +#endif // _MSC_VER > 1000
   62.10 +
   62.11 +enum LocationType
   62.12 +{
   62.13 +	LOCATION_register,
   62.14 +	LOCATION_memory,
   62.15 +	LOCATION_value
   62.16 +};
   62.17 +
   62.18 +#define DW_ATE_boolean       0x02
   62.19 +#define DW_ATE_signed        0x05
   62.20 +#define DW_ATE_unsigned      0x07
   62.21 +#define DW_ATE_unsigned_char 0x08
   62.22 +
   62.23 +struct ELFHeader
   62.24 +{
   62.25 +	u32 magic;
   62.26 +	u8  clazz;
   62.27 +	u8  data;
   62.28 +	u8  version;
   62.29 +	u8  pad[9];
   62.30 +	u16 e_type;
   62.31 +	u16 e_machine;
   62.32 +	u32 e_version;
   62.33 +	u32 e_entry;
   62.34 +	u32 e_phoff;
   62.35 +	u32 e_shoff;
   62.36 +	u32 e_flags;
   62.37 +	u16 e_ehsize;
   62.38 +	u16 e_phentsize;
   62.39 +	u16 e_phnum;
   62.40 +	u16 e_shentsize;
   62.41 +	u16 e_shnum;
   62.42 +	u16 e_shstrndx;
   62.43 +};
   62.44 +
   62.45 +struct ELFProgramHeader
   62.46 +{
   62.47 +	u32 type;
   62.48 +	u32 offset;
   62.49 +	u32 vaddr;
   62.50 +	u32 paddr;
   62.51 +	u32 filesz;
   62.52 +	u32 memsz;
   62.53 +	u32 flags;
   62.54 +	u32 align;
   62.55 +};
   62.56 +
   62.57 +struct ELFSectionHeader
   62.58 +{
   62.59 +	u32 name;
   62.60 +	u32 type;
   62.61 +	u32 flags;
   62.62 +	u32 addr;
   62.63 +	u32 offset;
   62.64 +	u32 size;
   62.65 +	u32 link;
   62.66 +	u32 info;
   62.67 +	u32 addralign;
   62.68 +	u32 entsize;
   62.69 +};
   62.70 +
   62.71 +struct ELFSymbol
   62.72 +{
   62.73 +	u32 name;
   62.74 +	u32 value;
   62.75 +	u32 size;
   62.76 +	u8  info;
   62.77 +	u8  other;
   62.78 +	u16 shndx;
   62.79 +};
   62.80 +
   62.81 +struct ELFBlock
   62.82 +{
   62.83 +	int length;
   62.84 +	u8 *data;
   62.85 +};
   62.86 +
   62.87 +struct ELFAttr
   62.88 +{
   62.89 +	u32 name;
   62.90 +	u32 form;
   62.91 +	union
   62.92 +	{
   62.93 +		u32       value;
   62.94 +		char *    string;
   62.95 +		u8 *      data;
   62.96 +		bool      flag;
   62.97 +		ELFBlock *block;
   62.98 +	};
   62.99 +};
  62.100 +
  62.101 +struct ELFAbbrev
  62.102 +{
  62.103 +	u32        number;
  62.104 +	u32        tag;
  62.105 +	bool       hasChildren;
  62.106 +	int        numAttrs;
  62.107 +	ELFAttr *  attrs;
  62.108 +	ELFAbbrev *next;
  62.109 +};
  62.110 +
  62.111 +enum TypeEnum
  62.112 +{
  62.113 +	TYPE_base,
  62.114 +	TYPE_pointer,
  62.115 +	TYPE_function,
  62.116 +	TYPE_void,
  62.117 +	TYPE_array,
  62.118 +	TYPE_struct,
  62.119 +	TYPE_reference,
  62.120 +	TYPE_enum,
  62.121 +	TYPE_union
  62.122 +};
  62.123 +
  62.124 +struct Type;
  62.125 +struct Object;
  62.126 +
  62.127 +struct FunctionType
  62.128 +{
  62.129 +	Type *  returnType;
  62.130 +	Object *args;
  62.131 +};
  62.132 +
  62.133 +struct Member
  62.134 +{
  62.135 +	char *    name;
  62.136 +	Type *    type;
  62.137 +	int       bitSize;
  62.138 +	int       bitOffset;
  62.139 +	int       byteSize;
  62.140 +	ELFBlock *location;
  62.141 +};
  62.142 +
  62.143 +struct Struct
  62.144 +{
  62.145 +	int     memberCount;
  62.146 +	Member *members;
  62.147 +};
  62.148 +
  62.149 +struct Array
  62.150 +{
  62.151 +	Type *type;
  62.152 +	int   maxBounds;
  62.153 +	int * bounds;
  62.154 +};
  62.155 +
  62.156 +struct EnumMember
  62.157 +{
  62.158 +	char *name;
  62.159 +	u32   value;
  62.160 +};
  62.161 +
  62.162 +struct Enum
  62.163 +{
  62.164 +	int         count;
  62.165 +	EnumMember *members;
  62.166 +};
  62.167 +
  62.168 +struct Type
  62.169 +{
  62.170 +	u32      offset;
  62.171 +	TypeEnum type;
  62.172 +	char *   name;
  62.173 +	int      encoding;
  62.174 +	int      size;
  62.175 +	int      bitSize;
  62.176 +	union
  62.177 +	{
  62.178 +		Type *        pointer;
  62.179 +		FunctionType *function;
  62.180 +		Array *       array;
  62.181 +		Struct *      structure;
  62.182 +		Enum *        enumeration;
  62.183 +	};
  62.184 +	Type *next;
  62.185 +};
  62.186 +
  62.187 +struct Object
  62.188 +{
  62.189 +	char *    name;
  62.190 +	int       file;
  62.191 +	int       line;
  62.192 +	bool      external;
  62.193 +	Type *    type;
  62.194 +	ELFBlock *location;
  62.195 +	u32       startScope;
  62.196 +	u32       endScope;
  62.197 +	Object *  next;
  62.198 +};
  62.199 +
  62.200 +struct Function
  62.201 +{
  62.202 +	char *    name;
  62.203 +	u32       lowPC;
  62.204 +	u32       highPC;
  62.205 +	int       file;
  62.206 +	int       line;
  62.207 +	bool      external;
  62.208 +	Type *    returnType;
  62.209 +	Object *  parameters;
  62.210 +	Object *  variables;
  62.211 +	ELFBlock *frameBase;
  62.212 +	Function *next;
  62.213 +};
  62.214 +
  62.215 +struct LineInfoItem
  62.216 +{
  62.217 +	u32   address;
  62.218 +	char *file;
  62.219 +	int   line;
  62.220 +};
  62.221 +
  62.222 +struct LineInfo
  62.223 +{
  62.224 +	int           fileCount;
  62.225 +	char **       files;
  62.226 +	int           number;
  62.227 +	LineInfoItem *lines;
  62.228 +};
  62.229 +
  62.230 +struct ARange
  62.231 +{
  62.232 +	u32 lowPC;
  62.233 +	u32 highPC;
  62.234 +};
  62.235 +
  62.236 +struct ARanges
  62.237 +{
  62.238 +	u32     offset;
  62.239 +	int     count;
  62.240 +	ARange *ranges;
  62.241 +};
  62.242 +
  62.243 +struct CompileUnit
  62.244 +{
  62.245 +	u32          length;
  62.246 +	u8 *         top;
  62.247 +	u32          offset;
  62.248 +	ELFAbbrev ** abbrevs;
  62.249 +	ARanges *    ranges;
  62.250 +	char *       name;
  62.251 +	char *       compdir;
  62.252 +	u32          lowPC;
  62.253 +	u32          highPC;
  62.254 +	bool         hasLineInfo;
  62.255 +	u32          lineInfo;
  62.256 +	LineInfo *   lineInfoTable;
  62.257 +	Function *   functions;
  62.258 +	Function *   lastFunction;
  62.259 +	Object *     variables;
  62.260 +	Type *       types;
  62.261 +	CompileUnit *next;
  62.262 +};
  62.263 +
  62.264 +struct DebugInfo
  62.265 +{
  62.266 +	u8 *     debugfile;
  62.267 +	u8 *     abbrevdata;
  62.268 +	u8 *     debugdata;
  62.269 +	u8 *     infodata;
  62.270 +	int      numRanges;
  62.271 +	ARanges *ranges;
  62.272 +};
  62.273 +
  62.274 +struct Symbol
  62.275 +{
  62.276 +	char *name;
  62.277 +	int   type;
  62.278 +	int   binding;
  62.279 +	u32   address;
  62.280 +	u32   value;
  62.281 +	u32   size;
  62.282 +};
  62.283 +
  62.284 +extern u32 elfReadLEB128(u8 *, int *);
  62.285 +extern s32 elfReadSignedLEB128(u8 *, int *);
  62.286 +extern bool elfRead(const char *, int &, FILE *f);
  62.287 +extern bool elfGetSymbolAddress(char *, u32 *, u32 *, int *);
  62.288 +extern char *elfGetAddressSymbol(u32);
  62.289 +extern char *elfGetSymbol(int, u32 *, u32 *, int *);
  62.290 +extern void elfCleanUp();
  62.291 +extern bool elfGetCurrentFunction(u32, Function **, CompileUnit **c);
  62.292 +extern bool elfGetObject(char *, Function *, CompileUnit *, Object * *);
  62.293 +extern bool elfFindLineInUnit(u32 *, CompileUnit *, int);
  62.294 +extern bool elfFindLineInModule(u32 *, char *, int);
  62.295 +u32 elfDecodeLocation(Function *, ELFBlock *, LocationType *);
  62.296 +u32 elfDecodeLocation(Function *, ELFBlock *, LocationType *, u32);
  62.297 +int elfFindLine(CompileUnit *unit, Function *func, u32 addr, char * *);
  62.298 +
  62.299 +#endif // VBA_ELF_H
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/src/gba/remote.cpp	Sun Mar 04 14:33:52 2012 -0600
    63.3 @@ -0,0 +1,712 @@
    63.4 +#include <cstdlib>
    63.5 +#include <cstdio>
    63.6 +#include <cstring>
    63.7 +
    63.8 +#ifndef WIN32
    63.9 +# include <unistd.h>
   63.10 +# include <sys/socket.h>
   63.11 +# include <netdb.h>
   63.12 +# ifdef HAVE_NETINET_IN_H
   63.13 +#  include <netinet/in.h>
   63.14 +# endif // HAVE_NETINET_IN_H
   63.15 +# ifdef HAVE_ARPA_INET_H
   63.16 +#  include <arpa/inet.h>
   63.17 +# else // ! HAVE_ARPA_INET_H
   63.18 +#  define socklen_t int
   63.19 +# endif // ! HAVE_ARPA_INET_H
   63.20 +#else // WIN32
   63.21 +# include "../win32/stdafx.h"
   63.22 +# include <winsock.h>
   63.23 +# include <io.h>
   63.24 +# define socklen_t int
   63.25 +# define close closesocket
   63.26 +# define read _read
   63.27 +# define write _write
   63.28 +#endif // WIN32
   63.29 +
   63.30 +#include "GBA.h"
   63.31 +#include "GBAGlobals.h"
   63.32 +
   63.33 +extern bool debugger;
   63.34 +extern void CPUUpdateCPSR();
   63.35 +#ifdef SDL
   63.36 +extern void (*dbgMain)();
   63.37 +extern void (*dbgSignal)(int, int);
   63.38 +extern void debuggerMain();
   63.39 +extern void debuggerSignal(int, int);
   63.40 +#endif
   63.41 +
   63.42 +int  remotePort         = 55555;
   63.43 +int  remoteSignal       = 5;
   63.44 +int  remoteSocket       = -1;
   63.45 +int  remoteListenSocket = -1;
   63.46 +bool remoteConnected    = false;
   63.47 +bool remoteResumed      = false;
   63.48 +
   63.49 +int  (*remoteSendFnc)(char *, int) = NULL;
   63.50 +int  (*remoteRecvFnc)(char *, int) = NULL;
   63.51 +bool (*remoteInitFnc)()    = NULL;
   63.52 +void (*remoteCleanUpFnc)() = NULL;
   63.53 +
   63.54 +#if (defined WIN32 && !defined SDL)
   63.55 +void remoteSetSockets(SOCKET l, SOCKET r)
   63.56 +{
   63.57 +	remoteSocket       = r;
   63.58 +	remoteListenSocket = l;
   63.59 +}
   63.60 +
   63.61 +#endif
   63.62 +
   63.63 +int remoteTcpSend(char *data, int len)
   63.64 +{
   63.65 +	return send(remoteSocket, data, len, 0);
   63.66 +}
   63.67 +
   63.68 +int remoteTcpRecv(char *data, int len)
   63.69 +{
   63.70 +	return recv(remoteSocket, data, len, 0);
   63.71 +}
   63.72 +
   63.73 +bool remoteTcpInit()
   63.74 +{
   63.75 +	if (remoteSocket == -1)
   63.76 +	{
   63.77 +#ifdef WIN32
   63.78 +		WSADATA wsaData;
   63.79 +		int     error = WSAStartup(MAKEWORD(1, 1), &wsaData);
   63.80 +#endif // WIN32
   63.81 +		int s = socket(PF_INET, SOCK_STREAM, 0);
   63.82 +
   63.83 +		remoteListenSocket = s;
   63.84 +
   63.85 +		if (s < 0)
   63.86 +		{
   63.87 +			fprintf(stderr, "Error opening socket\n");
   63.88 +			exit(-1);
   63.89 +		}
   63.90 +		int tmp = 1;
   63.91 +		setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof(tmp));
   63.92 +
   63.93 +		//    char hostname[256];
   63.94 +		//    gethostname(hostname, 256);
   63.95 +
   63.96 +		//    hostent *ent = gethostbyname(hostname);
   63.97 +		//    unsigned long a = *((unsigned long *)ent->h_addr);
   63.98 +
   63.99 +		sockaddr_in addr;
  63.100 +		addr.sin_family      = AF_INET;
  63.101 +		addr.sin_port        = htons(remotePort);
  63.102 +		addr.sin_addr.s_addr = htonl(0);
  63.103 +		int count = 0;
  63.104 +		while (count < 3)
  63.105 +		{
  63.106 +			if (bind(s, (sockaddr *)&addr, sizeof(addr)))
  63.107 +			{
  63.108 +				addr.sin_port = htons(ntohs(addr.sin_port)+1);
  63.109 +			}
  63.110 +			else
  63.111 +				break;
  63.112 +		}
  63.113 +		if (count == 3)
  63.114 +		{
  63.115 +			fprintf(stderr, "Error binding \n");
  63.116 +			exit(-1);
  63.117 +		}
  63.118 +
  63.119 +		fprintf(stderr, "Listening for a connection at port %d\n",
  63.120 +		        ntohs(addr.sin_port));
  63.121 +
  63.122 +		if (listen(s, 1))
  63.123 +		{
  63.124 +			fprintf(stderr, "Error listening\n");
  63.125 +			exit(-1);
  63.126 +		}
  63.127 +		socklen_t len = sizeof(addr);
  63.128 +
  63.129 +#ifdef WIN32
  63.130 +		int flag = 0;
  63.131 +		ioctlsocket(s, FIONBIO, (unsigned long *)&flag);
  63.132 +#endif // WIN32
  63.133 +		int s2 = accept(s, (sockaddr *)&addr, &len);
  63.134 +		if (s2 > 0)
  63.135 +		{
  63.136 +			fprintf(stderr, "Got a connection from %s %d\n",
  63.137 +			        inet_ntoa((in_addr)addr.sin_addr),
  63.138 +			        ntohs(addr.sin_port));
  63.139 +		}
  63.140 +		else
  63.141 +		{
  63.142 +#ifdef WIN32
  63.143 +			int error = WSAGetLastError();
  63.144 +#endif // WIN32
  63.145 +		}
  63.146 +		char dummy;
  63.147 +		recv(s2, &dummy, 1, 0);
  63.148 +		if (dummy != '+')
  63.149 +		{
  63.150 +			fprintf(stderr, "ACK not received\n");
  63.151 +			exit(-1);
  63.152 +		}
  63.153 +		remoteSocket = s2;
  63.154 +		//    close(s);
  63.155 +	}
  63.156 +	return true;
  63.157 +}
  63.158 +
  63.159 +void remoteTcpCleanUp()
  63.160 +{
  63.161 +	if (remoteSocket > 0)
  63.162 +	{
  63.163 +		fprintf(stderr, "Closing remote socket\n");
  63.164 +		close(remoteSocket);
  63.165 +		remoteSocket = -1;
  63.166 +	}
  63.167 +	if (remoteListenSocket > 0)
  63.168 +	{
  63.169 +		fprintf(stderr, "Closing listen socket\n");
  63.170 +		close(remoteListenSocket);
  63.171 +		remoteListenSocket = -1;
  63.172 +	}
  63.173 +}
  63.174 +
  63.175 +int remotePipeSend(char *data, int len)
  63.176 +{
  63.177 +	int res = write(1, data, len);
  63.178 +	return res;
  63.179 +}
  63.180 +
  63.181 +int remotePipeRecv(char *data, int len)
  63.182 +{
  63.183 +	int res = read(0, data, len);
  63.184 +	return res;
  63.185 +}
  63.186 +
  63.187 +bool remotePipeInit()
  63.188 +{
  63.189 +	char dummy;
  63.190 +	read(0, &dummy, 1);
  63.191 +	if (dummy != '+')
  63.192 +	{
  63.193 +		fprintf(stderr, "ACK not received\n");
  63.194 +		exit(-1);
  63.195 +	}
  63.196 +
  63.197 +	return true;
  63.198 +}
  63.199 +
  63.200 +void remotePipeCleanUp()
  63.201 +{}
  63.202 +
  63.203 +void remoteSetPort(int port)
  63.204 +{
  63.205 +	remotePort = port;
  63.206 +}
  63.207 +
  63.208 +void remoteSetProtocol(int p)
  63.209 +{
  63.210 +	if (p == 0)
  63.211 +	{
  63.212 +		remoteSendFnc    = remoteTcpSend;
  63.213 +		remoteRecvFnc    = remoteTcpRecv;
  63.214 +		remoteInitFnc    = remoteTcpInit;
  63.215 +		remoteCleanUpFnc = remoteTcpCleanUp;
  63.216 +	}
  63.217 +	else
  63.218 +	{
  63.219 +		remoteSendFnc    = remotePipeSend;
  63.220 +		remoteRecvFnc    = remotePipeRecv;
  63.221 +		remoteInitFnc    = remotePipeInit;
  63.222 +		remoteCleanUpFnc = remotePipeCleanUp;
  63.223 +	}
  63.224 +}
  63.225 +
  63.226 +void remoteInit()
  63.227 +{
  63.228 +	if (remoteInitFnc)
  63.229 +		remoteInitFnc();
  63.230 +}
  63.231 +
  63.232 +void remotePutPacket(char *packet)
  63.233 +{
  63.234 +	char *hex = "0123456789abcdef";
  63.235 +	char  buffer[1024];
  63.236 +
  63.237 +	int count = strlen(packet);
  63.238 +
  63.239 +	unsigned char csum = 0;
  63.240 +
  63.241 +	char *p = buffer;
  63.242 +	*p++ = '$';
  63.243 +
  63.244 +	for (int i = 0; i < count; i++)
  63.245 +	{
  63.246 +		csum += packet[i];
  63.247 +		*p++  = packet[i];
  63.248 +	}
  63.249 +	*p++ = '#';
  63.250 +	*p++ = hex[csum>>4];
  63.251 +	*p++ = hex[csum & 15];
  63.252 +	*p++ = 0;
  63.253 +	//  printf("Sending %s\n", buffer);
  63.254 +	remoteSendFnc(buffer, count + 4);
  63.255 +
  63.256 +	char c = 0;
  63.257 +	remoteRecvFnc(&c, 1);
  63.258 +	/*
  63.259 +	   if(c == '+')
  63.260 +	   printf("ACK\n");
  63.261 +	   else if(c=='-')
  63.262 +	   printf("NACK\n");
  63.263 +	 */
  63.264 +}
  63.265 +
  63.266 +void remoteOutput(char *s, u32 addr)
  63.267 +{
  63.268 +	char buffer[16384];
  63.269 +
  63.270 +	char *d = buffer;
  63.271 +	*d++ = 'O';
  63.272 +
  63.273 +	if (s)
  63.274 +	{
  63.275 +		char c = *s++;
  63.276 +		while (c)
  63.277 +		{
  63.278 +			sprintf(d, "%02x", c);
  63.279 +			d += 2;
  63.280 +			c  = *s++;
  63.281 +		}
  63.282 +	}
  63.283 +	else
  63.284 +	{
  63.285 +		char c = debuggerReadByte(addr);
  63.286 +		addr++;
  63.287 +		while (c)
  63.288 +		{
  63.289 +			sprintf(d, "%02x", c);
  63.290 +			d += 2;
  63.291 +			c  = debuggerReadByte(addr);
  63.292 +			addr++;
  63.293 +		}
  63.294 +	}
  63.295 +	remotePutPacket(buffer);
  63.296 +	//  fprintf(stderr, "Output sent %s\n", buffer);
  63.297 +}
  63.298 +
  63.299 +void remoteSendSignal()
  63.300 +{
  63.301 +	char buffer[1024];
  63.302 +	sprintf(buffer, "S%02x", remoteSignal);
  63.303 +	remotePutPacket(buffer);
  63.304 +}
  63.305 +
  63.306 +void remoteSendStatus()
  63.307 +{
  63.308 +	char buffer[1024];
  63.309 +	sprintf(buffer, "T%02x", remoteSignal);
  63.310 +	char *s = buffer;
  63.311 +	s += 3;
  63.312 +	for (int i = 0; i < 15; i++)
  63.313 +	{
  63.314 +		u32 v = reg[i].I;
  63.315 +		sprintf(s, "%02x:%02x%02x%02x%02x;", i,
  63.316 +		        (v & 255),
  63.317 +		        (v >> 8) & 255,
  63.318 +		        (v >> 16) & 255,
  63.319 +		        (v >> 24) & 255);
  63.320 +		s += 12;
  63.321 +	}
  63.322 +	u32 v = armNextPC;
  63.323 +	sprintf(s, "0f:%02x%02x%02x%02x;", (v & 255),
  63.324 +	        (v >> 8) & 255,
  63.325 +	        (v >> 16) & 255,
  63.326 +	        (v >> 24) & 255);
  63.327 +	s += 12;
  63.328 +	CPUUpdateCPSR();
  63.329 +	v = reg[16].I;
  63.330 +	sprintf(s, "19:%02x%02x%02x%02x;", (v & 255),
  63.331 +	        (v >> 8) & 255,
  63.332 +	        (v >> 16) & 255,
  63.333 +	        (v >> 24) & 255);
  63.334 +	s += 12;
  63.335 +	*s = 0;
  63.336 +	//  printf("Sending %s\n", buffer);
  63.337 +	remotePutPacket(buffer);
  63.338 +}
  63.339 +
  63.340 +void remoteBinaryWrite(char *p)
  63.341 +{
  63.342 +	u32 address;
  63.343 +	int count;
  63.344 +	sscanf(p, "%x,%x:", &address, &count);
  63.345 +	//  printf("Binary write for %08x %d\n", address, count);
  63.346 +
  63.347 +	p = strchr(p, ':');
  63.348 +	p++;
  63.349 +	for (int i = 0; i < count; i++)
  63.350 +	{
  63.351 +		u8 b = *p++;
  63.352 +		switch (b)
  63.353 +		{
  63.354 +		case 0x7d:
  63.355 +			b = *p++;
  63.356 +			debuggerWriteByte(address, (b^0x20));
  63.357 +			address++;
  63.358 +			break;
  63.359 +		default:
  63.360 +			debuggerWriteByte(address, b);
  63.361 +			address++;
  63.362 +			break;
  63.363 +		}
  63.364 +	}
  63.365 +	//  printf("ROM is %08x\n", debuggerReadMemory(0x8000254));
  63.366 +	remotePutPacket("OK");
  63.367 +}
  63.368 +
  63.369 +void remoteMemoryWrite(char *p)
  63.370 +{
  63.371 +	u32 address;
  63.372 +	int count;
  63.373 +	sscanf(p, "%x,%x:", &address, &count);
  63.374 +	//  printf("Memory write for %08x %d\n", address, count);
  63.375 +
  63.376 +	p = strchr(p, ':');
  63.377 +	p++;
  63.378 +	for (int i = 0; i < count; i++)
  63.379 +	{
  63.380 +		u8   v = 0;
  63.381 +		char c = *p++;
  63.382 +		if (c <= '9')
  63.383 +			v = (c - '0') << 4;
  63.384 +		else
  63.385 +			v = (c + 10 - 'a') << 4;
  63.386 +		c = *p++;
  63.387 +		if (c <= '9')
  63.388 +			v += (c - '0');
  63.389 +		else
  63.390 +			v += (c + 10 - 'a');
  63.391 +		debuggerWriteByte(address, v);
  63.392 +		address++;
  63.393 +	}
  63.394 +	//  printf("ROM is %08x\n", debuggerReadMemory(0x8000254));
  63.395 +	remotePutPacket("OK");
  63.396 +}
  63.397 +
  63.398 +void remoteMemoryRead(char *p)
  63.399 +{
  63.400 +	u32 address;
  63.401 +	int count;
  63.402 +	sscanf(p, "%x,%x:", &address, &count);
  63.403 +	//  printf("Memory read for %08x %d\n", address, count);
  63.404 +
  63.405 +	char buffer[1024];
  63.406 +
  63.407 +	char *s = buffer;
  63.408 +	for (int i = 0; i < count; i++)
  63.409 +	{
  63.410 +		u8 b = debuggerReadByte(address);
  63.411 +		sprintf(s, "%02x", b);
  63.412 +		address++;
  63.413 +		s += 2;
  63.414 +	}
  63.415 +	*s = 0;
  63.416 +	remotePutPacket(buffer);
  63.417 +}
  63.418 +
  63.419 +void remoteStepOverRange(char *p)
  63.420 +{
  63.421 +	u32 address;
  63.422 +	u32 final;
  63.423 +	sscanf(p, "%x,%x", &address, &final);
  63.424 +
  63.425 +	remotePutPacket("OK");
  63.426 +
  63.427 +	remoteResumed = true;
  63.428 +	do
  63.429 +	{
  63.430 +		CPULoop(1);
  63.431 +		if (debugger)
  63.432 +			break;
  63.433 +	}
  63.434 +	while (armNextPC >= address && armNextPC < final);
  63.435 +
  63.436 +	remoteResumed = false;
  63.437 +
  63.438 +	remoteSendStatus();
  63.439 +}
  63.440 +
  63.441 +void remoteWriteWatch(char *p, bool active)
  63.442 +{
  63.443 +	u32 address;
  63.444 +	int count;
  63.445 +	sscanf(p, ",%x,%x#", &address, &count);
  63.446 +
  63.447 +	fprintf(stderr, "Write watch for %08x %d\n", address, count);
  63.448 +
  63.449 +	if (address < 0x2000000 || address > 0x3007fff)
  63.450 +	{
  63.451 +		remotePutPacket("E01");
  63.452 +		return;
  63.453 +	}
  63.454 +
  63.455 +	if (address > 0x203ffff && address < 0x3000000)
  63.456 +	{
  63.457 +		remotePutPacket("E01");
  63.458 +		return;
  63.459 +	}
  63.460 +
  63.461 +	u32 final = address + count;
  63.462 +
  63.463 +	if (address < 0x2040000 && final > 0x2040000)
  63.464 +	{
  63.465 +		remotePutPacket("E01");
  63.466 +		return;
  63.467 +	}
  63.468 +	else if (address < 0x3008000 && final > 0x3008000)
  63.469 +	{
  63.470 +		remotePutPacket("E01");
  63.471 +		return;
  63.472 +	}
  63.473 +
  63.474 +	for (int i = 0; i < count; i++)
  63.475 +	{
  63.476 +		if ((address >> 24) == 2)
  63.477 +			freezeWorkRAM[address & 0x3ffff] = active;
  63.478 +		else
  63.479 +			freezeInternalRAM[address & 0x7fff] = active;
  63.480 +		address++;
  63.481 +	}
  63.482 +
  63.483 +	remotePutPacket("OK");
  63.484 +}
  63.485 +
  63.486 +void remoteReadRegisters(char *p)
  63.487 +{
  63.488 +	char buffer[1024];
  63.489 +
  63.490 +	char *s = buffer;
  63.491 +	int   i;
  63.492 +	// regular registers
  63.493 +	for (i = 0; i < 15; i++)
  63.494 +	{
  63.495 +		u32 v = reg[i].I;
  63.496 +		sprintf(s, "%02x%02x%02x%02x",  v & 255, (v >> 8) & 255,
  63.497 +		        (v >> 16) & 255, (v >> 24) & 255);
  63.498 +		s += 8;
  63.499 +	}
  63.500 +	// PC
  63.501 +	u32 pc = armNextPC;
  63.502 +	sprintf(s, "%02x%02x%02x%02x", pc & 255, (pc >> 8) & 255,
  63.503 +	        (pc >> 16) & 255, (pc >> 24) & 255);
  63.504 +	s += 8;
  63.505 +
  63.506 +	// floating point registers (24-bit)
  63.507 +	for (i = 0; i < 8; i++)
  63.508 +	{
  63.509 +		sprintf(s, "000000000000000000000000");
  63.510 +		s += 24;
  63.511 +	}
  63.512 +
  63.513 +	// FP status register
  63.514 +	sprintf(s, "00000000");
  63.515 +	s += 8;
  63.516 +	// CPSR
  63.517 +	CPUUpdateCPSR();
  63.518 +	u32 v = reg[16].I;
  63.519 +	sprintf(s, "%02x%02x%02x%02x",  v & 255, (v >> 8) & 255,
  63.520 +	        (v >> 16) & 255, (v >> 24) & 255);
  63.521 +	s += 8;
  63.522 +	*s = 0;
  63.523 +	remotePutPacket(buffer);
  63.524 +}
  63.525 +
  63.526 +void remoteWriteRegister(char *p)
  63.527 +{
  63.528 +	int r;
  63.529 +
  63.530 +	sscanf(p, "%x=", &r);
  63.531 +
  63.532 +	p = strchr(p, '=');
  63.533 +	p++;
  63.534 +
  63.535 +	char c = *p++;
  63.536 +
  63.537 +	u32 v = 0;
  63.538 +
  63.539 +	u8 data[4] = {0, 0, 0, 0};
  63.540 +
  63.541 +	int i = 0;
  63.542 +
  63.543 +	while (c != '#')
  63.544 +	{
  63.545 +		u8 b = 0;
  63.546 +		if (c <= '9')
  63.547 +			b = (c - '0') << 4;
  63.548 +		else
  63.549 +			b = (c + 10 - 'a') << 4;
  63.550 +		c = *p++;
  63.551 +		if (c <= '9')
  63.552 +			b += (c - '0');
  63.553 +		else
  63.554 +			b += (c + 10 - 'a');
  63.555 +		data[i++] = b;
  63.556 +		c         = *p++;
  63.557 +	}
  63.558 +
  63.559 +	v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
  63.560 +
  63.561 +	//  printf("Write register %d=%08x\n", r, v);
  63.562 +	reg[r].I = v;
  63.563 +	if (r == 15)
  63.564 +	{
  63.565 +		armNextPC = v;
  63.566 +		if (armState)
  63.567 +			reg[15].I = v + 4;
  63.568 +		else
  63.569 +			reg[15].I = v + 2;
  63.570 +	}
  63.571 +	remotePutPacket("OK");
  63.572 +}
  63.573 +
  63.574 +void remoteStubMain()
  63.575 +{
  63.576 +	if (!debugger)
  63.577 +		return;
  63.578 +
  63.579 +	if (remoteResumed)
  63.580 +	{
  63.581 +		remoteSendStatus();
  63.582 +		remoteResumed = false;
  63.583 +	}
  63.584 +
  63.585 +	while (true)
  63.586 +	{
  63.587 +		char buffer[1024];
  63.588 +		int  res = remoteRecvFnc(buffer, 1024);
  63.589 +
  63.590 +		if (res == -1)
  63.591 +		{
  63.592 +			fprintf(stderr, "GDB connection lost\n");
  63.593 +#ifdef SDL
  63.594 +			dbgMain   = debuggerMain;
  63.595 +			dbgSignal = debuggerSignal;
  63.596 +#endif
  63.597 +			debugger = false;
  63.598 +			break;
  63.599 +		}
  63.600 +
  63.601 +		//    fprintf(stderr, "Received %s\n", buffer);
  63.602 +		char *p  = buffer;
  63.603 +		char  c  = *p++;
  63.604 +		char  pp = '+';
  63.605 +		remoteSendFnc(&pp, 1);
  63.606 +
  63.607 +		if (c != '$')
  63.608 +			continue;
  63.609 +		c = *p++;
  63.610 +		switch (c)
  63.611 +		{
  63.612 +		case '?':
  63.613 +			remoteSendSignal();
  63.614 +			break;
  63.615 +		case 'D':
  63.616 +			remotePutPacket("OK");
  63.617 +#ifdef SDL
  63.618 +			dbgMain   = debuggerMain;
  63.619 +			dbgSignal = debuggerSignal;
  63.620 +#endif
  63.621 +			remoteResumed = true;
  63.622 +			debugger      = false;
  63.623 +			return;
  63.624 +		case 'e':
  63.625 +			remoteStepOverRange(p);
  63.626 +			break;
  63.627 +		case 'k':
  63.628 +			remotePutPacket("OK");
  63.629 +#ifdef SDL
  63.630 +			dbgMain   = debuggerMain;
  63.631 +			dbgSignal = debuggerSignal;
  63.632 +#endif
  63.633 +			debugger  = false;
  63.634 +			emulating = false;
  63.635 +			return;
  63.636 +		case 'C':
  63.637 +			remoteResumed = true;
  63.638 +			debugger      = false;
  63.639 +			return;
  63.640 +		case 'c':
  63.641 +			remoteResumed = true;
  63.642 +			debugger      = false;
  63.643 +			return;
  63.644 +		case 's':
  63.645 +			remoteResumed = true;
  63.646 +			remoteSignal  = 5;
  63.647 +			CPULoop(1);
  63.648 +			if (remoteResumed)
  63.649 +			{
  63.650 +				remoteResumed = false;
  63.651 +				remoteSendStatus();
  63.652 +			}
  63.653 +			break;
  63.654 +		case 'g':
  63.655 +			remoteReadRegisters(p);
  63.656 +			break;
  63.657 +		case 'P':
  63.658 +			remoteWriteRegister(p);
  63.659 +			break;
  63.660 +		case 'M':
  63.661 +			remoteMemoryWrite(p);
  63.662 +			break;
  63.663 +		case 'm':
  63.664 +			remoteMemoryRead(p);
  63.665 +			break;
  63.666 +		case 'X':
  63.667 +			remoteBinaryWrite(p);
  63.668 +			break;
  63.669 +		case 'H':
  63.670 +			remotePutPacket("OK");
  63.671 +			break;
  63.672 +		case 'q':
  63.673 +			remotePutPacket("");
  63.674 +			break;
  63.675 +		case 'Z':
  63.676 +			if (*p++ == '2')
  63.677 +			{
  63.678 +				remoteWriteWatch(p, true);
  63.679 +			}
  63.680 +			else
  63.681 +				remotePutPacket("");
  63.682 +			break;
  63.683 +		case 'z':
  63.684 +			if (*p++ == '2')
  63.685 +			{
  63.686 +				remoteWriteWatch(p, false);
  63.687 +			}
  63.688 +			else
  63.689 +				remotePutPacket("");
  63.690 +			break;
  63.691 +		default:
  63.692 +		{
  63.693 +			*(strchr(p, '#') + 3) = 0;
  63.694 +			fprintf(stderr, "Unknown packet %s\n", --p);
  63.695 +			remotePutPacket("");
  63.696 +			break;
  63.697 +		}
  63.698 +		}
  63.699 +	}
  63.700 +}
  63.701 +
  63.702 +void remoteStubSignal(int sig, int number)
  63.703 +{
  63.704 +	remoteSignal  = sig;
  63.705 +	remoteResumed = false;
  63.706 +	remoteSendStatus();
  63.707 +	debugger = true;
  63.708 +}
  63.709 +
  63.710 +void remoteCleanUp()
  63.711 +{
  63.712 +	if (remoteCleanUpFnc)
  63.713 +		remoteCleanUpFnc();
  63.714 +}
  63.715 +
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/src/gba/thumb.h	Sun Mar 04 14:33:52 2012 -0600
    64.3 @@ -0,0 +1,2524 @@
    64.4 +#ifdef C_CORE
    64.5 +#define NEG(i) ((i) >> 31)
    64.6 +#define POS(i) ((~(i)) >> 31)
    64.7 +#define ADDCARRY(a, b, c) \
    64.8 +    C_FLAG = ((NEG(a) & NEG(b)) | \
    64.9 +              (NEG(a) & POS(c)) | \
   64.10 +              (NEG(b) & POS(c))) ? true : false;
   64.11 +#define ADDOVERFLOW(a, b, c) \
   64.12 +    V_FLAG = ((NEG(a) & NEG(b) & POS(c)) | \
   64.13 +              (POS(a) & POS(b) & NEG(c))) ? true : false;
   64.14 +#define SUBCARRY(a, b, c) \
   64.15 +    C_FLAG = ((NEG(a) & POS(b)) | \
   64.16 +              (NEG(a) & POS(c)) | \
   64.17 +              (POS(b) & POS(c))) ? true : false;
   64.18 +#define SUBOVERFLOW(a, b, c) \
   64.19 +    V_FLAG = ((NEG(a) & POS(b) & POS(c)) | \
   64.20 +              (POS(a) & NEG(b) & NEG(c))) ? true : false;
   64.21 +#define ADD_RD_RS_RN \
   64.22 +	{ \
   64.23 +		u32 lhs = reg[source].I; \
   64.24 +		u32 rhs = value; \
   64.25 +		u32 res = lhs + rhs; \
   64.26 +		reg[dest].I = res; \
   64.27 +		Z_FLAG		= (res == 0) ? true : false; \
   64.28 +		N_FLAG		= NEG(res) ? true : false; \
   64.29 +		ADDCARRY(lhs, rhs, res); \
   64.30 +		ADDOVERFLOW(lhs, rhs, res); \
   64.31 +	}
   64.32 +#define ADD_RD_RS_O3 \
   64.33 +	{ \
   64.34 +		u32 lhs = reg[source].I; \
   64.35 +		u32 rhs = value; \
   64.36 +		u32 res = lhs + rhs; \
   64.37 +		reg[dest].I = res; \
   64.38 +		Z_FLAG		= (res == 0) ? true : false; \
   64.39 +		N_FLAG		= NEG(res) ? true : false; \
   64.40 +		ADDCARRY(lhs, rhs, res); \
   64.41 +		ADDOVERFLOW(lhs, rhs, res); \
   64.42 +	}
   64.43 +#define ADD_RN_O8(d) \
   64.44 +	{ \
   64.45 +		u32 lhs = reg[(d)].I; \
   64.46 +		u32 rhs = (opcode & 255); \
   64.47 +		u32 res = lhs + rhs; \
   64.48 +		reg[(d)].I = res; \
   64.49 +		Z_FLAG	   = (res == 0) ? true : false; \
   64.50 +		N_FLAG	   = NEG(res) ? true : false; \
   64.51 +		ADDCARRY(lhs, rhs, res); \
   64.52 +		ADDOVERFLOW(lhs, rhs, res); \
   64.53 +	}
   64.54 +#define CMN_RD_RS \
   64.55 +	{ \
   64.56 +		u32 lhs = reg[dest].I; \
   64.57 +		u32 rhs = value; \
   64.58 +		u32 res = lhs + rhs; \
   64.59 +		Z_FLAG = (res == 0) ? true : false; \
   64.60 +		N_FLAG = NEG(res) ? true : false; \
   64.61 +		ADDCARRY(lhs, rhs, res); \
   64.62 +		ADDOVERFLOW(lhs, rhs, res); \
   64.63 +	}
   64.64 +#define ADC_RD_RS \
   64.65 +	{ \
   64.66 +		u32 lhs = reg[dest].I; \
   64.67 +		u32 rhs = value; \
   64.68 +		u32 res = lhs + rhs + (u32)C_FLAG; \
   64.69 +		reg[dest].I = res; \
   64.70 +		Z_FLAG		= (res == 0) ? true : false; \
   64.71 +		N_FLAG		= NEG(res) ? true : false; \
   64.72 +		ADDCARRY(lhs, rhs, res); \
   64.73 +		ADDOVERFLOW(lhs, rhs, res); \
   64.74 +	}
   64.75 +#define SUB_RD_RS_RN \
   64.76 +	{ \
   64.77 +		u32 lhs = reg[source].I; \
   64.78 +		u32 rhs = value; \
   64.79 +		u32 res = lhs - rhs; \
   64.80 +		reg[dest].I = res; \
   64.81 +		Z_FLAG		= (res == 0) ? true : false; \
   64.82 +		N_FLAG		= NEG(res) ? true : false; \
   64.83 +		SUBCARRY(lhs, rhs, res); \
   64.84 +		SUBOVERFLOW(lhs, rhs, res); \
   64.85 +	}
   64.86 +#define SUB_RD_RS_O3 \
   64.87 +	{ \
   64.88 +		u32 lhs = reg[source].I; \
   64.89 +		u32 rhs = value; \
   64.90 +		u32 res = lhs - rhs; \
   64.91 +		reg[dest].I = res; \
   64.92 +		Z_FLAG		= (res == 0) ? true : false; \
   64.93 +		N_FLAG		= NEG(res) ? true : false; \
   64.94 +		SUBCARRY(lhs, rhs, res); \
   64.95 +		SUBOVERFLOW(lhs, rhs, res); \
   64.96 +	}
   64.97 +#define SUB_RN_O8(d) \
   64.98 +	{ \
   64.99 +		u32 lhs = reg[(d)].I; \
  64.100 +		u32 rhs = (opcode & 255); \
  64.101 +		u32 res = lhs - rhs; \
  64.102 +		reg[(d)].I = res; \
  64.103 +		Z_FLAG	   = (res == 0) ? true : false; \
  64.104 +		N_FLAG	   = NEG(res) ? true : false; \
  64.105 +		SUBCARRY(lhs, rhs, res); \
  64.106 +		SUBOVERFLOW(lhs, rhs, res); \
  64.107 +	}
  64.108 +#define CMP_RN_O8(d) \
  64.109 +	{ \
  64.110 +		u32 lhs = reg[(d)].I; \
  64.111 +		u32 rhs = (opcode & 255); \
  64.112 +		u32 res = lhs - rhs; \
  64.113 +		Z_FLAG = (res == 0) ? true : false; \
  64.114 +		N_FLAG = NEG(res) ? true : false; \
  64.115 +		SUBCARRY(lhs, rhs, res); \
  64.116 +		SUBOVERFLOW(lhs, rhs, res); \
  64.117 +	}
  64.118 +#define SBC_RD_RS \
  64.119 +	{ \
  64.120 +		u32 lhs = reg[dest].I; \
  64.121 +		u32 rhs = value; \
  64.122 +		u32 res = lhs - rhs - !((u32)C_FLAG); \
  64.123 +		reg[dest].I = res; \
  64.124 +		Z_FLAG		= (res == 0) ? true : false; \
  64.125 +		N_FLAG		= NEG(res) ? true : false; \
  64.126 +		SUBCARRY(lhs, rhs, res); \
  64.127 +		SUBOVERFLOW(lhs, rhs, res); \
  64.128 +	}
  64.129 +#define LSL_RD_RM_I5 \
  64.130 +	{ \
  64.131 +		C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false; \
  64.132 +		value  = reg[source].I << shift; \
  64.133 +	}
  64.134 +#define LSL_RD_RS \
  64.135 +	{ \
  64.136 +		C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false; \
  64.137 +		value  = reg[dest].I << value; \
  64.138 +	}
  64.139 +#define LSR_RD_RM_I5 \
  64.140 +	{ \
  64.141 +		C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false; \
  64.142 +		value  = reg[source].I >> shift; \
  64.143 +	}
  64.144 +#define LSR_RD_RS \
  64.145 +	{ \
  64.146 +		C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \
  64.147 +		value  = reg[dest].I >> value; \
  64.148 +	}
  64.149 +#define ASR_RD_RM_I5 \
  64.150 +	{ \
  64.151 +		C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false; \
  64.152 +		value  = (s32)reg[source].I >> (int)shift; \
  64.153 +	}
  64.154 +#define ASR_RD_RS \
  64.155 +	{ \
  64.156 +		C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false; \
  64.157 +		value  = (s32)reg[dest].I >> (int)value; \
  64.158 +	}
  64.159 +#define ROR_RD_RS \
  64.160 +	{ \
  64.161 +		C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \
  64.162 +		value  = ((reg[dest].I << (32 - value)) | \
  64.163 +		          (reg[dest].I >> value)); \
  64.164 +	}
  64.165 +#define NEG_RD_RS \
  64.166 +	{ \
  64.167 +		u32 lhs = reg[source].I; \
  64.168 +		u32 rhs = 0; \
  64.169 +		u32 res = rhs - lhs; \
  64.170 +		reg[dest].I = res; \
  64.171 +		Z_FLAG		= (res == 0) ? true : false; \
  64.172 +		N_FLAG		= NEG(res) ? true : false; \
  64.173 +		SUBCARRY(rhs, lhs, res); \
  64.174 +		SUBOVERFLOW(rhs, lhs, res); \
  64.175 +	}
  64.176 +#define CMP_RD_RS \
  64.177 +	{ \
  64.178 +		u32 lhs = reg[dest].I; \
  64.179 +		u32 rhs = value; \
  64.180 +		u32 res = lhs - rhs; \
  64.181 +		Z_FLAG = (res == 0) ? true : false; \
  64.182 +		N_FLAG = NEG(res) ? true : false; \
  64.183 +		SUBCARRY(lhs, rhs, res); \
  64.184 +		SUBOVERFLOW(lhs, rhs, res); \
  64.185 +	}
  64.186 +#else
  64.187 +#ifdef __GNUC__
  64.188 +#ifdef __POWERPC__
  64.189 +			#define ADD_RD_RS_RN \
  64.190 +	{                                       \
  64.191 +		register int Flags;                 \
  64.192 +		register int Result;                \
  64.193 +		asm volatile ("addco. %0, %2, %3\n"  \
  64.194 +		              "mcrxr cr1\n"           \
  64.195 +		              "mfcr %1\n"             \
  64.196 +					  : "=r" (Result),        \
  64.197 +		              "=r" (Flags)          \
  64.198 +					  : "r" (reg[source].I),  \
  64.199 +		              "r" (value)           \
  64.200 +		              );                      \
  64.201 +		reg[dest].I = Result;               \
  64.202 +		Z_FLAG		= (Flags >> 29) & 1;         \
  64.203 +		N_FLAG		= (Flags >> 31) & 1;         \
  64.204 +		C_FLAG		= (Flags >> 25) & 1;         \
  64.205 +		V_FLAG		= (Flags >> 26) & 1;         \
  64.206 +	}
  64.207 +			#define ADD_RD_RS_O3 ADD_RD_RS_RN
  64.208 +			#define ADD_RN_O8(d) \
  64.209 +	{ \
  64.210 +		register int Flags;                 \
  64.211 +		register int Result;                \
  64.212 +		asm volatile ("addco. %0, %2, %3\n"  \
  64.213 +		              "mcrxr cr1\n"           \
  64.214 +		              "mfcr %1\n"             \
  64.215 +					  : "=r" (Result),        \
  64.216 +		              "=r" (Flags)          \
  64.217 +					  : "r" (reg[(d)].I),     \
  64.218 +		              "r" (opcode & 255)    \
  64.219 +		              );                      \
  64.220 +		reg[(d)].I = Result;                \
  64.221 +		Z_FLAG	   = (Flags >> 29) & 1;         \
  64.222 +		N_FLAG	   = (Flags >> 31) & 1;         \
  64.223 +		C_FLAG	   = (Flags >> 25) & 1;         \
  64.224 +		V_FLAG	   = (Flags >> 26) & 1;         \
  64.225 +	}
  64.226 +			#define CMN_RD_RS \
  64.227 +	{ \
  64.228 +		register int Flags;                 \
  64.229 +		register int Result;                \
  64.230 +		asm volatile ("addco. %0, %2, %3\n"  \
  64.231 +		              "mcrxr cr1\n"           \
  64.232 +		              "mfcr %1\n"             \
  64.233 +					  : "=r" (Result),        \
  64.234 +		              "=r" (Flags)          \
  64.235 +					  : "r" (reg[dest].I),    \
  64.236 +		              "r" (value)           \
  64.237 +		              );                      \
  64.238 +		Z_FLAG = (Flags >> 29) & 1;         \
  64.239 +		N_FLAG = (Flags >> 31) & 1;         \
  64.240 +		C_FLAG = (Flags >> 25) & 1;         \
  64.241 +		V_FLAG = (Flags >> 26) & 1;         \
  64.242 +	}
  64.243 +			#define ADC_RD_RS \
  64.244 +	{ \
  64.245 +		register int Flags;                 \
  64.246 +		register int Result;                \
  64.247 +		asm volatile ("mtspr xer, %4\n"      \
  64.248 +		              "addeo. %0, %2, %3\n"  \
  64.249 +		              "mcrxr cr1\n"          \
  64.250 +		              "mfcr	%1\n"            \
  64.251 +					  : "=r" (Result),       \
  64.252 +		              "=r" (Flags)         \
  64.253 +					  : "r" (reg[dest].I),   \
  64.254 +		              "r" (value),         \
  64.255 +		              "r" (C_FLAG << 29)   \
  64.256 +		              );                     \
  64.257 +		reg[dest].I = Result;               \
  64.258 +		Z_FLAG		= (Flags >> 29) & 1;         \
  64.259 +		N_FLAG		= (Flags >> 31) & 1;         \
  64.260 +		C_FLAG		= (Flags >> 25) & 1;         \
  64.261 +		V_FLAG		= (Flags >> 26) & 1;         \
  64.262 +	}
  64.263 +			#define SUB_RD_RS_RN \
  64.264 +	{ \
  64.265 +		register int Flags;                 \
  64.266 +		register int Result;                \
  64.267 +		asm volatile ("subco. %0, %2, %3\n"  \
  64.268 +		              "mcrxr cr1\n"           \
  64.269 +		              "mfcr %1\n"             \
  64.270 +					  : "=r" (Result),        \
  64.271 +		              "=r" (Flags)          \
  64.272 +					  : "r" (reg[source].I),  \
  64.273 +		              "r" (value)           \
  64.274 +		              );                      \
  64.275 +		reg[dest].I = Result;               \
  64.276 +		Z_FLAG		= (Flags >> 29) & 1;         \
  64.277 +		N_FLAG		= (Flags >> 31) & 1;         \
  64.278 +		C_FLAG		= (Flags >> 25) & 1;         \
  64.279 +		V_FLAG		= (Flags >> 26) & 1;         \
  64.280 +	}
  64.281 +			#define SUB_RD_RS_O3 SUB_RD_RS_RN
  64.282 +			#define SUB_RN_O8(d) \
  64.283 +	{ \
  64.284 +		register int Flags;                 \
  64.285 +		register int Result;                \
  64.286 +		asm volatile ("subco. %0, %2, %3\n"  \
  64.287 +		              "mcrxr cr1\n"           \
  64.288 +		              "mfcr %1\n"             \
  64.289 +					  : "=r" (Result),        \
  64.290 +		              "=r" (Flags)          \
  64.291 +					  : "r" (reg[(d)].I),     \
  64.292 +		              "r" (opcode & 255)    \
  64.293 +		              );                      \
  64.294 +		reg[(d)].I = Result;                \
  64.295 +		Z_FLAG	   = (Flags >> 29) & 1;         \
  64.296 +		N_FLAG	   = (Flags >> 31) & 1;         \
  64.297 +		C_FLAG	   = (Flags >> 25) & 1;         \
  64.298 +		V_FLAG	   = (Flags >> 26) & 1;         \
  64.299 +	}
  64.300 +			#define CMP_RN_O8(d) \
  64.301 +	{ \
  64.302 +		register int Flags;                 \
  64.303 +		register int Result;                \
  64.304 +		asm volatile ("subco. %0, %2, %3\n"  \
  64.305 +		              "mcrxr cr1\n"           \
  64.306 +		              "mfcr %1\n"             \
  64.307 +					  : "=r" (Result),        \
  64.308 +		              "=r" (Flags)          \
  64.309 +					  : "r" (reg[(d)].I),     \
  64.310 +		              "r" (opcode & 255)    \
  64.311 +		              );                      \
  64.312 +		Z_FLAG = (Flags >> 29) & 1;         \
  64.313 +		N_FLAG = (Flags >> 31) & 1;         \
  64.314 +		C_FLAG = (Flags >> 25) & 1;         \
  64.315 +		V_FLAG = (Flags >> 26) & 1;         \
  64.316 +	}
  64.317 +			#define SBC_RD_RS \
  64.318 +	{ \
  64.319 +		register int Flags;                 \
  64.320 +		register int Result;                \
  64.321 +		asm volatile ("mtspr xer, %4\n"      \
  64.322 +		              "subfeo. %0, %3, %2\n" \
  64.323 +		              "mcrxr cr1\n"          \
  64.324 +		              "mfcr	%1\n"            \
  64.325 +					  : "=r" (Result),       \
  64.326 +		              "=r" (Flags)         \
  64.327 +					  : "r" (reg[dest].I),   \
  64.328 +		              "r" (value),         \
  64.329 +		              "r" (C_FLAG << 29)   \
  64.330 +		              );                     \
  64.331 +		reg[dest].I = Result;               \
  64.332 +		Z_FLAG		= (Flags >> 29) & 1;         \
  64.333 +		N_FLAG		= (Flags >> 31) & 1;         \
  64.334 +		C_FLAG		= (Flags >> 25) & 1;         \
  64.335 +		V_FLAG		= (Flags >> 26) & 1;         \
  64.336 +	}
  64.337 +			#define LSL_RD_RM_I5 \
  64.338 +	{ \
  64.339 +		C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false; \
  64.340 +		value  = reg[source].I << shift; \
  64.341 +	}
  64.342 +			#define LSL_RD_RS \
  64.343 +	{ \
  64.344 +		C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false; \
  64.345 +		value  = reg[dest].I << value; \
  64.346 +	}
  64.347 +			#define LSR_RD_RM_I5 \
  64.348 +	{ \
  64.349 +		C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false; \
  64.350 +		value  = reg[source].I >> shift; \
  64.351 +	}
  64.352 +			#define LSR_RD_RS \
  64.353 +	{ \
  64.354 +		C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \
  64.355 +		value  = reg[dest].I >> value; \
  64.356 +	}
  64.357 +			#define ASR_RD_RM_I5 \
  64.358 +	{ \
  64.359 +		C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false; \
  64.360 +		value  = (s32)reg[source].I >> (int)shift; \
  64.361 +	}
  64.362 +			#define ASR_RD_RS \
  64.363 +	{ \
  64.364 +		C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false; \
  64.365 +		value  = (s32)reg[dest].I >> (int)value; \
  64.366 +	}
  64.367 +			#define ROR_RD_RS \
  64.368 +	{ \
  64.369 +		C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \
  64.370 +		value  = ((reg[dest].I << (32 - value)) | \
  64.371 +		          (reg[dest].I >> value)); \
  64.372 +	}
  64.373 +			#define NEG_RD_RS \
  64.374 +	{ \
  64.375 +		register int Flags;                 \
  64.376 +		register int Result;                \
  64.377 +		asm volatile ("subfco. %0, %2, %3\n" \
  64.378 +		              "mcrxr cr1\n"           \
  64.379 +		              "mfcr %1\n"             \
  64.380 +					  : "=r" (Result),        \
  64.381 +		              "=r" (Flags)          \
  64.382 +					  : "r" (reg[source].I),  \
  64.383 +		              "r" (0)               \
  64.384 +		              );                      \
  64.385 +		reg[dest].I = Result;               \
  64.386 +		Z_FLAG		= (Flags >> 29) & 1;         \
  64.387 +		N_FLAG		= (Flags >> 31) & 1;         \
  64.388 +		C_FLAG		= (Flags >> 25) & 1;         \
  64.389 +		V_FLAG		= (Flags >> 26) & 1;         \
  64.390 +	}
  64.391 +			#define CMP_RD_RS \
  64.392 +	{ \
  64.393 +		register int Flags;                 \
  64.394 +		register int Result;                \
  64.395 +		asm volatile ("subco. %0, %2, %3\n"  \
  64.396 +		              "mcrxr cr1\n"           \
  64.397 +		              "mfcr %1\n"             \
  64.398 +					  : "=r" (Result),        \
  64.399 +		              "=r" (Flags)          \
  64.400 +					  : "r" (reg[dest].I),    \
  64.401 +		              "r" (value)           \
  64.402 +		              );                      \
  64.403 +		Z_FLAG = (Flags >> 29) & 1;         \
  64.404 +		N_FLAG = (Flags >> 31) & 1;         \
  64.405 +		C_FLAG = (Flags >> 25) & 1;         \
  64.406 +		V_FLAG = (Flags >> 26) & 1;         \
  64.407 +	}
  64.408 +#else
  64.409 +#define ADD_RD_RS_RN \
  64.410 +    asm ("add %1, %%ebx;" \
  64.411 +         "setsb N_FLAG;" \
  64.412 +         "setzb Z_FLAG;" \
  64.413 +         "setcb C_FLAG;" \
  64.414 +         "setob V_FLAG;" \
  64.415 +		 : "=b" (reg[dest].I) \
  64.416 +		 : "r" (value), "b" (reg[source].I));
  64.417 +#define ADD_RD_RS_O3 \
  64.418 +    asm ("add %1, %%ebx;" \
  64.419 +         "setsb N_FLAG;" \
  64.420 +         "setzb Z_FLAG;" \
  64.421 +         "setcb C_FLAG;" \
  64.422 +         "setob V_FLAG;" \
  64.423 +		 : "=b" (reg[dest].I) \
  64.424 +		 : "r" (value), "b" (reg[source].I));
  64.425 +#define ADD_RN_O8(d) \
  64.426 +    asm ("add %1, %%ebx;" \
  64.427 +         "setsb N_FLAG;" \
  64.428 +         "setzb Z_FLAG;" \
  64.429 +         "setcb C_FLAG;" \
  64.430 +         "setob V_FLAG;" \
  64.431 +		 : "=b" (reg[(d)].I) \
  64.432 +		 : "r" (opcode & 255), "b" (reg[(d)].I));
  64.433 +#define CMN_RD_RS \
  64.434 +    asm ("add %0, %1;" \
  64.435 +         "setsb N_FLAG;" \
  64.436 +         "setzb Z_FLAG;" \
  64.437 +         "setcb C_FLAG;" \
  64.438 +         "setob V_FLAG;" \
  64.439 +		 : \
  64.440 +		 : "r" (value), "r" (reg[dest].I) : "1");
  64.441 +#define ADC_RD_RS \
  64.442 +    asm ("bt $0, C_FLAG;" \
  64.443 +         "adc %1, %%ebx;" \
  64.444 +         "setsb N_FLAG;" \
  64.445 +         "setzb Z_FLAG;" \
  64.446 +         "setcb C_FLAG;" \
  64.447 +         "setob V_FLAG;" \
  64.448 +		 : "=b" (reg[dest].I) \
  64.449 +		 : "r" (value), "b" (reg[dest].I));
  64.450 +#define SUB_RD_RS_RN \
  64.451 +    asm ("sub %1, %%ebx;" \
  64.452 +         "setsb N_FLAG;" \
  64.453 +         "setzb Z_FLAG;" \
  64.454 +         "setncb C_FLAG;" \
  64.455 +         "setob V_FLAG;" \
  64.456 +		 : "=b" (reg[dest].I) \
  64.457 +		 : "r" (value), "b" (reg[source].I));
  64.458 +#define SUB_RD_RS_O3 \
  64.459 +    asm ("sub %1, %%ebx;" \
  64.460 +         "setsb N_FLAG;" \
  64.461 +         "setzb Z_FLAG;" \
  64.462 +         "setncb C_FLAG;" \
  64.463 +         "setob V_FLAG;" \
  64.464 +		 : "=b" (reg[dest].I) \
  64.465 +		 : "r" (value), "b" (reg[source].I));
  64.466 +#define SUB_RN_O8(d) \
  64.467 +    asm ("sub %1, %%ebx;" \
  64.468 +         "setsb N_FLAG;" \
  64.469 +         "setzb Z_FLAG;" \
  64.470 +         "setncb C_FLAG;" \
  64.471 +         "setob V_FLAG;" \
  64.472 +		 : "=b" (reg[(d)].I) \
  64.473 +		 : "r" (opcode & 255), "b" (reg[(d)].I));
  64.474 +#define CMP_RN_O8(d) \
  64.475 +    asm ("sub %0, %1;" \
  64.476 +         "setsb N_FLAG;" \
  64.477 +         "setzb Z_FLAG;" \
  64.478 +         "setncb C_FLAG;" \
  64.479 +         "setob V_FLAG;" \
  64.480 +		 : \
  64.481 +		 : "r" (opcode & 255), "r" (reg[(d)].I) : "1");
  64.482 +#define SBC_RD_RS \
  64.483 +    asm volatile ("bt $0, C_FLAG;" \
  64.484 +                  "cmc;" \
  64.485 +                  "sbb %1, %%ebx;" \
  64.486 +                  "setsb N_FLAG;" \
  64.487 +                  "setzb Z_FLAG;" \
  64.488 +                  "setncb C_FLAG;" \
  64.489 +                  "setob V_FLAG;" \
  64.490 +				  : "=b" (reg[dest].I) \
  64.491 +				  : "r" (value), "b" (reg[dest].I) : "cc", "memory");
  64.492 +#define LSL_RD_RM_I5 \
  64.493 +    asm ("shl %%cl, %%eax;" \
  64.494 +         "setcb C_FLAG;" \
  64.495 +		 : "=a" (value) \
  64.496 +		 : "a" (reg[source].I), "c" (shift));
  64.497 +#define LSL_RD_RS \
  64.498 +    asm ("shl %%cl, %%eax;" \
  64.499 +         "setcb C_FLAG;" \
  64.500 +		 : "=a" (value) \
  64.501 +		 : "a" (reg[dest].I), "c" (value));
  64.502 +#define LSR_RD_RM_I5 \
  64.503 +    asm ("shr %%cl, %%eax;" \
  64.504 +         "setcb C_FLAG;" \
  64.505 +		 : "=a" (value) \
  64.506 +		 : "a" (reg[source].I), "c" (shift));
  64.507 +#define LSR_RD_RS \
  64.508 +    asm ("shr %%cl, %%eax;" \
  64.509 +         "setcb C_FLAG;" \
  64.510 +		 : "=a" (value) \
  64.511 +		 : "a" (reg[dest].I), "c" (value));
  64.512 +#define ASR_RD_RM_I5 \
  64.513 +    asm ("sar %%cl, %%eax;" \
  64.514 +         "setcb C_FLAG;" \
  64.515 +		 : "=a" (value) \
  64.516 +		 : "a" (reg[source].I), "c" (shift));
  64.517 +#define ASR_RD_RS \
  64.518 +    asm ("sar %%cl, %%eax;" \
  64.519 +         "setcb C_FLAG;" \
  64.520 +		 : "=a" (value) \
  64.521 +		 : "a" (reg[dest].I), "c" (value));
  64.522 +#define ROR_RD_RS \
  64.523 +    asm ("ror %%cl, %%eax;" \
  64.524 +         "setcb C_FLAG;" \
  64.525 +		 : "=a" (value) \
  64.526 +		 : "a" (reg[dest].I), "c" (value));
  64.527 +#define NEG_RD_RS \
  64.528 +    asm ("neg %%ebx;" \
  64.529 +         "setsb N_FLAG;" \
  64.530 +         "setzb Z_FLAG;" \
  64.531 +         "setncb C_FLAG;" \
  64.532 +         "setob V_FLAG;" \
  64.533 +		 : "=b" (reg[dest].I) \
  64.534 +		 : "b" (reg[source].I));
  64.535 +#define CMP_RD_RS \
  64.536 +    asm ("sub %0, %1;" \
  64.537 +         "setsb N_FLAG;" \
  64.538 +         "setzb Z_FLAG;" \
  64.539 +         "setncb C_FLAG;" \
  64.540 +         "setob V_FLAG;" \
  64.541 +		 : \
  64.542 +		 : "r" (value), "r" (reg[dest].I) : "1");
  64.543 +#endif
  64.544 +#else
  64.545 +#define ADD_RD_RS_RN \
  64.546 +	{ \
  64.547 +		__asm mov eax, source \
  64.548 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
  64.549 +		__asm add ebx, value \
  64.550 +		__asm mov eax, dest \
  64.551 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  64.552 +		__asm sets byte ptr N_FLAG \
  64.553 +		__asm setz byte ptr Z_FLAG \
  64.554 +		__asm setc byte ptr C_FLAG \
  64.555 +		__asm seto byte ptr V_FLAG \
  64.556 +	}
  64.557 +#define ADD_RD_RS_O3 \
  64.558 +	{ \
  64.559 +		__asm mov eax, source \
  64.560 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
  64.561 +		__asm add ebx, value \
  64.562 +		__asm mov eax, dest \
  64.563 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  64.564 +		__asm sets byte ptr N_FLAG \
  64.565 +		__asm setz byte ptr Z_FLAG \
  64.566 +		__asm setc byte ptr C_FLAG \
  64.567 +		__asm seto byte ptr V_FLAG \
  64.568 +	}
  64.569 +#define ADD_RN_O8(d) \
  64.570 +	{ \
  64.571 +		__asm mov ebx, opcode \
  64.572 +		          __asm and ebx, 255 \
  64.573 +		__asm add dword ptr [OFFSET reg + 4 * (d)], ebx \
  64.574 +		__asm sets byte ptr N_FLAG \
  64.575 +		__asm setz byte ptr Z_FLAG \
  64.576 +		__asm setc byte ptr C_FLAG \
  64.577 +		__asm seto byte ptr V_FLAG \
  64.578 +	}
  64.579 +#define CMN_RD_RS \
  64.580 +	{ \
  64.581 +		__asm mov eax, dest \
  64.582 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
  64.583 +		__asm add ebx, value \
  64.584 +		__asm sets byte ptr N_FLAG \
  64.585 +		__asm setz byte ptr Z_FLAG \
  64.586 +		__asm setc byte ptr C_FLAG \
  64.587 +		__asm seto byte ptr V_FLAG \
  64.588 +	}
  64.589 +#define ADC_RD_RS \
  64.590 +	{ \
  64.591 +		__asm mov ebx, dest \
  64.592 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  64.593 +		__asm bt word ptr C_FLAG, 0 \
  64.594 +		__asm adc ebx, value \
  64.595 +		__asm mov eax, dest \
  64.596 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  64.597 +		__asm sets byte ptr N_FLAG \
  64.598 +		__asm setz byte ptr Z_FLAG \
  64.599 +		__asm setc byte ptr C_FLAG \
  64.600 +		__asm seto byte ptr V_FLAG \
  64.601 +	}
  64.602 +#define SUB_RD_RS_RN \
  64.603 +	{ \
  64.604 +		__asm mov eax, source \
  64.605 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
  64.606 +		__asm sub ebx, value \
  64.607 +		__asm mov eax, dest \
  64.608 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  64.609 +		__asm sets byte ptr N_FLAG \
  64.610 +		__asm setz byte ptr Z_FLAG \
  64.611 +		__asm setnc byte ptr C_FLAG \
  64.612 +		__asm seto byte ptr V_FLAG \
  64.613 +	}
  64.614 +#define SUB_RD_RS_O3 \
  64.615 +	{ \
  64.616 +		__asm mov eax, source \
  64.617 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
  64.618 +		__asm sub ebx, value \
  64.619 +		__asm mov eax, dest \
  64.620 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  64.621 +		__asm sets byte ptr N_FLAG \
  64.622 +		__asm setz byte ptr Z_FLAG \
  64.623 +		__asm setnc byte ptr C_FLAG \
  64.624 +		__asm seto byte ptr V_FLAG \
  64.625 +	}
  64.626 +#define SUB_RN_O8(d) \
  64.627 +	{ \
  64.628 +		__asm mov ebx, opcode \
  64.629 +		          __asm and ebx, 255 \
  64.630 +		__asm sub dword ptr [OFFSET reg + 4 * (d)], ebx \
  64.631 +		__asm sets byte ptr N_FLAG \
  64.632 +		__asm setz byte ptr Z_FLAG \
  64.633 +		__asm setnc byte ptr C_FLAG \
  64.634 +		__asm seto byte ptr V_FLAG \
  64.635 +	}
  64.636 +#define CMP_RN_O8(d) \
  64.637 +	{ \
  64.638 +		__asm mov eax, dword ptr [OFFSET reg + 4 * (d)] \
  64.639 +		__asm mov ebx, opcode \
  64.640 +		          __asm and ebx, 255 \
  64.641 +		__asm sub eax, ebx \
  64.642 +		__asm sets byte ptr N_FLAG \
  64.643 +		__asm setz byte ptr Z_FLAG \
  64.644 +		__asm setnc byte ptr C_FLAG \
  64.645 +		__asm seto byte ptr V_FLAG \
  64.646 +	}
  64.647 +#define SBC_RD_RS \
  64.648 +	{ \
  64.649 +		__asm mov ebx, dest \
  64.650 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  64.651 +		__asm mov eax, value \
  64.652 +		__asm bt word ptr C_FLAG, 0 \
  64.653 +		__asm cmc \
  64.654 +		__asm sbb ebx, eax \
  64.655 +		__asm mov eax, dest \
  64.656 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  64.657 +		__asm sets byte ptr N_FLAG \
  64.658 +		__asm setz byte ptr Z_FLAG \
  64.659 +		__asm setnc byte ptr C_FLAG \
  64.660 +		__asm seto byte ptr V_FLAG \
  64.661 +	}
  64.662 +#define LSL_RD_RM_I5 \
  64.663 +	{ \
  64.664 +		__asm mov eax, source \
  64.665 +		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  64.666 +		__asm mov cl, byte ptr shift \
  64.667 +		__asm shl eax, cl \
  64.668 +		__asm mov value, eax \
  64.669 +		__asm setc byte ptr C_FLAG \
  64.670 +	}
  64.671 +#define LSL_RD_RS \
  64.672 +	{ \
  64.673 +		__asm mov eax, dest \
  64.674 +		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  64.675 +		__asm mov cl, byte ptr value \
  64.676 +		__asm shl eax, cl \
  64.677 +		__asm mov value, eax \
  64.678 +		__asm setc byte ptr C_FLAG \
  64.679 +	}
  64.680 +#define LSR_RD_RM_I5 \
  64.681 +	{ \
  64.682 +		__asm mov eax, source \
  64.683 +		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  64.684 +		__asm mov cl, byte ptr shift \
  64.685 +		__asm shr eax, cl \
  64.686 +		__asm mov value, eax \
  64.687 +		__asm setc byte ptr C_FLAG \
  64.688 +	}
  64.689 +#define LSR_RD_RS \
  64.690 +	{ \
  64.691 +		__asm mov eax, dest \
  64.692 +		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  64.693 +		__asm mov cl, byte ptr value \
  64.694 +		__asm shr eax, cl \
  64.695 +		__asm mov value, eax \
  64.696 +		__asm setc byte ptr C_FLAG \
  64.697 +	}
  64.698 +#define ASR_RD_RM_I5 \
  64.699 +	{ \
  64.700 +		__asm mov eax, source \
  64.701 +		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  64.702 +		__asm mov cl, byte ptr shift \
  64.703 +		__asm sar eax, cl \
  64.704 +		__asm mov value, eax \
  64.705 +		__asm setc byte ptr C_FLAG \
  64.706 +	}
  64.707 +#define ASR_RD_RS \
  64.708 +	{ \
  64.709 +		__asm mov eax, dest \
  64.710 +		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  64.711 +		__asm mov cl, byte ptr value \
  64.712 +		__asm sar eax, cl \
  64.713 +		__asm mov value, eax \
  64.714 +		__asm setc byte ptr C_FLAG \
  64.715 +	}
  64.716 +#define ROR_RD_RS \
  64.717 +	{ \
  64.718 +		__asm mov eax, dest \
  64.719 +		__asm mov eax, dword ptr [OFFSET reg + 4 * eax] \
  64.720 +		__asm mov cl, byte ptr value \
  64.721 +		__asm ror eax, cl \
  64.722 +		__asm mov value, eax \
  64.723 +		__asm setc byte ptr C_FLAG \
  64.724 +	}
  64.725 +#define NEG_RD_RS \
  64.726 +	{ \
  64.727 +		__asm mov ebx, source \
  64.728 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \
  64.729 +		__asm neg ebx \
  64.730 +		__asm mov eax, dest \
  64.731 +		__asm mov dword ptr [OFFSET reg + 4 * eax], ebx \
  64.732 +		__asm sets byte ptr N_FLAG \
  64.733 +		__asm setz byte ptr Z_FLAG \
  64.734 +		__asm setnc byte ptr C_FLAG \
  64.735 +		__asm seto byte ptr V_FLAG \
  64.736 +	}
  64.737 +#define CMP_RD_RS \
  64.738 +	{ \
  64.739 +		__asm mov eax, dest \
  64.740 +		__asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \
  64.741 +		__asm sub ebx, value \
  64.742 +		__asm sets byte ptr N_FLAG \
  64.743 +		__asm setz byte ptr Z_FLAG \
  64.744 +		__asm setnc byte ptr C_FLAG \
  64.745 +		__asm seto byte ptr V_FLAG \
  64.746 +	}
  64.747 +#endif
  64.748 +#endif
  64.749 +
  64.750 +u32 opcode = CPUReadHalfWordQuick(armNextPC);
  64.751 +clockTicks = thumbCycles[opcode >> 8] + memoryWaitFetch[(armNextPC >> 24) & 15];
  64.752 +#ifndef FINAL_VERSION
  64.753 +if (armNextPC == stop)
  64.754 +{
  64.755 +	armNextPC = armNextPC++;
  64.756 +}
  64.757 +#endif
  64.758 +
  64.759 +armNextPC  = reg[15].I;
  64.760 +reg[15].I += 2;
  64.761 +
  64.762 +switch (opcode >> 8)
  64.763 +{
  64.764 +case 0x00:
  64.765 +case 0x01:
  64.766 +case 0x02:
  64.767 +case 0x03:
  64.768 +case 0x04:
  64.769 +case 0x05:
  64.770 +case 0x06:
  64.771 +case 0x07:
  64.772 +{
  64.773 +	// LSL Rd, Rm, #Imm 5
  64.774 +	int dest   = opcode & 0x07;
  64.775 +	int source = (opcode >> 3) & 0x07;
  64.776 +	int shift  = (opcode >> 6) & 0x1f;
  64.777 +	u32 value;
  64.778 +
  64.779 +	if (shift)
  64.780 +	{
  64.781 +		LSL_RD_RM_I5;
  64.782 +	}
  64.783 +	else
  64.784 +	{
  64.785 +		value = reg[source].I;
  64.786 +	}
  64.787 +	reg[dest].I = value;
  64.788 +	// C_FLAG set above
  64.789 +	N_FLAG = (value & 0x80000000 ? true : false);
  64.790 +	Z_FLAG = (value ? false : true);
  64.791 +}
  64.792 +break;
  64.793 +case 0x08:
  64.794 +case 0x09:
  64.795 +case 0x0a:
  64.796 +case 0x0b:
  64.797 +case 0x0c:
  64.798 +case 0x0d:
  64.799 +case 0x0e:
  64.800 +case 0x0f:
  64.801 +{
  64.802 +	// LSR Rd, Rm, #Imm 5
  64.803 +	int dest   = opcode & 0x07;
  64.804 +	int source = (opcode >> 3) & 0x07;
  64.805 +	int shift  = (opcode >> 6) & 0x1f;
  64.806 +	u32 value;
  64.807 +
  64.808 +	if (shift)
  64.809 +	{
  64.810 +		LSR_RD_RM_I5;
  64.811 +	}
  64.812 +	else
  64.813 +	{
  64.814 +		C_FLAG = reg[source].I & 0x80000000 ? true : false;
  64.815 +		value  = 0;
  64.816 +	}
  64.817 +	reg[dest].I = value;
  64.818 +	// C_FLAG set above
  64.819 +	N_FLAG = (value & 0x80000000 ? true : false);
  64.820 +	Z_FLAG = (value ? false : true);
  64.821 +}
  64.822 +break;
  64.823 +case 0x10:
  64.824 +case 0x11:
  64.825 +case 0x12:
  64.826 +case 0x13:
  64.827 +case 0x14:
  64.828 +case 0x15:
  64.829 +case 0x16:
  64.830 +case 0x17:
  64.831 +{
  64.832 +	// ASR Rd, Rm, #Imm 5
  64.833 +	int dest   = opcode & 0x07;
  64.834 +	int source = (opcode >> 3) & 0x07;
  64.835 +	int shift  = (opcode >> 6) & 0x1f;
  64.836 +	u32 value;
  64.837 +
  64.838 +	if (shift)
  64.839 +	{
  64.840 +		ASR_RD_RM_I5;
  64.841 +	}
  64.842 +	else
  64.843 +	{
  64.844 +		if (reg[source].I & 0x80000000)
  64.845 +		{
  64.846 +			value  = 0xFFFFFFFF;
  64.847 +			C_FLAG = true;
  64.848 +		}
  64.849 +		else
  64.850 +		{
  64.851 +			value  = 0;
  64.852 +			C_FLAG = false;
  64.853 +		}
  64.854 +	}
  64.855 +	reg[dest].I = value;
  64.856 +	// C_FLAG set above
  64.857 +	N_FLAG = (value & 0x80000000 ? true : false);
  64.858 +	Z_FLAG = (value ? false : true);
  64.859 +}
  64.860 +break;
  64.861 +case 0x18:
  64.862 +case 0x19:
  64.863 +{
  64.864 +	// ADD Rd, Rs, Rn
  64.865 +	int dest   = opcode & 0x07;
  64.866 +	int source = (opcode >> 3) & 0x07;
  64.867 +	u32 value  = reg[(opcode >> 6) & 0x07].I;
  64.868 +	ADD_RD_RS_RN;
  64.869 +}
  64.870 +break;
  64.871 +case 0x1a:
  64.872 +case 0x1b:
  64.873 +{
  64.874 +	// SUB Rd, Rs, Rn
  64.875 +	int dest   = opcode & 0x07;
  64.876 +	int source = (opcode >> 3) & 0x07;
  64.877 +	u32 value  = reg[(opcode >> 6) & 0x07].I;
  64.878 +	SUB_RD_RS_RN;
  64.879 +}
  64.880 +break;
  64.881 +case 0x1c:
  64.882 +case 0x1d:
  64.883 +{
  64.884 +	// ADD Rd, Rs, #Offset3
  64.885 +	int dest   = opcode & 0x07;
  64.886 +	int source = (opcode >> 3) & 0x07;
  64.887 +	u32 value  = (opcode >> 6) & 7;
  64.888 +	ADD_RD_RS_O3;
  64.889 +}
  64.890 +break;
  64.891 +case 0x1e:
  64.892 +case 0x1f:
  64.893 +{
  64.894 +	// SUB Rd, Rs, #Offset3
  64.895 +	int dest   = opcode & 0x07;
  64.896 +	int source = (opcode >> 3) & 0x07;
  64.897 +	u32 value  = (opcode >> 6) & 7;
  64.898 +	SUB_RD_RS_O3;
  64.899 +}
  64.900 +break;
  64.901 +case 0x20:
  64.902 +	// MOV R0, #Offset8
  64.903 +	reg[0].I = opcode & 255;
  64.904 +	N_FLAG	 = false;
  64.905 +	Z_FLAG	 = (reg[0].I ? false : true);
  64.906 +	break;
  64.907 +case 0x21:
  64.908 +	// MOV R1, #Offset8
  64.909 +	reg[1].I = opcode & 255;
  64.910 +	N_FLAG	 = false;
  64.911 +	Z_FLAG	 = (reg[1].I ? false : true);
  64.912 +	break;
  64.913 +case 0x22:
  64.914 +	// MOV R2, #Offset8
  64.915 +	reg[2].I = opcode & 255;
  64.916 +	N_FLAG	 = false;
  64.917 +	Z_FLAG	 = (reg[2].I ? false : true);
  64.918 +	break;
  64.919 +case 0x23:
  64.920 +	// MOV R3, #Offset8
  64.921 +	reg[3].I = opcode & 255;
  64.922 +	N_FLAG	 = false;
  64.923 +	Z_FLAG	 = (reg[3].I ? false : true);
  64.924 +	break;
  64.925 +case 0x24:
  64.926 +	// MOV R4, #Offset8
  64.927 +	reg[4].I = opcode & 255;
  64.928 +	N_FLAG	 = false;
  64.929 +	Z_FLAG	 = (reg[4].I ? false : true);
  64.930 +	break;
  64.931 +case 0x25:
  64.932 +	// MOV R5, #Offset8
  64.933 +	reg[5].I = opcode & 255;
  64.934 +	N_FLAG	 = false;
  64.935 +	Z_FLAG	 = (reg[5].I ? false : true);
  64.936 +	break;
  64.937 +case 0x26:
  64.938 +	// MOV R6, #Offset8
  64.939 +	reg[6].I = opcode & 255;
  64.940 +	N_FLAG	 = false;
  64.941 +	Z_FLAG	 = (reg[6].I ? false : true);
  64.942 +	break;
  64.943 +case 0x27:
  64.944 +	// MOV R7, #Offset8
  64.945 +	reg[7].I = opcode & 255;
  64.946 +	N_FLAG	 = false;
  64.947 +	Z_FLAG	 = (reg[7].I ? false : true);
  64.948 +	break;
  64.949 +case 0x28:
  64.950 +	// CMP R0, #Offset8
  64.951 +	CMP_RN_O8(0);
  64.952 +	break;
  64.953 +case 0x29:
  64.954 +	// CMP R1, #Offset8
  64.955 +	CMP_RN_O8(1);
  64.956 +	break;
  64.957 +case 0x2a:
  64.958 +	// CMP R2, #Offset8
  64.959 +	CMP_RN_O8(2);
  64.960 +	break;
  64.961 +case 0x2b:
  64.962 +	// CMP R3, #Offset8
  64.963 +	CMP_RN_O8(3);
  64.964 +	break;
  64.965 +case 0x2c:
  64.966 +	// CMP R4, #Offset8
  64.967 +	CMP_RN_O8(4);
  64.968 +	break;
  64.969 +case 0x2d:
  64.970 +	// CMP R5, #Offset8
  64.971 +	CMP_RN_O8(5);
  64.972 +	break;
  64.973 +case 0x2e:
  64.974 +	// CMP R6, #Offset8
  64.975 +	CMP_RN_O8(6);
  64.976 +	break;
  64.977 +case 0x2f:
  64.978 +	// CMP R7, #Offset8
  64.979 +	CMP_RN_O8(7);
  64.980 +	break;
  64.981 +case 0x30:
  64.982 +	// ADD R0,#Offset8
  64.983 +	ADD_RN_O8(0);
  64.984 +	break;
  64.985 +case 0x31:
  64.986 +	// ADD R1,#Offset8
  64.987 +	ADD_RN_O8(1);
  64.988 +	break;
  64.989 +case 0x32:
  64.990 +	// ADD R2,#Offset8
  64.991 +	ADD_RN_O8(2);
  64.992 +	break;
  64.993 +case 0x33:
  64.994 +	// ADD R3,#Offset8
  64.995 +	ADD_RN_O8(3);
  64.996 +	break;
  64.997 +case 0x34:
  64.998 +	// ADD R4,#Offset8
  64.999 +	ADD_RN_O8(4);
 64.1000 +	break;
 64.1001 +case 0x35:
 64.1002 +	// ADD R5,#Offset8
 64.1003 +	ADD_RN_O8(5);
 64.1004 +	break;
 64.1005 +case 0x36:
 64.1006 +	// ADD R6,#Offset8
 64.1007 +	ADD_RN_O8(6);
 64.1008 +	break;
 64.1009 +case 0x37:
 64.1010 +	// ADD R7,#Offset8
 64.1011 +	ADD_RN_O8(7);
 64.1012 +	break;
 64.1013 +case 0x38:
 64.1014 +	// SUB R0,#Offset8
 64.1015 +	SUB_RN_O8(0);
 64.1016 +	break;
 64.1017 +case 0x39:
 64.1018 +	// SUB R1,#Offset8
 64.1019 +	SUB_RN_O8(1);
 64.1020 +	break;
 64.1021 +case 0x3a:
 64.1022 +	// SUB R2,#Offset8
 64.1023 +	SUB_RN_O8(2);
 64.1024 +	break;
 64.1025 +case 0x3b:
 64.1026 +	// SUB R3,#Offset8
 64.1027 +	SUB_RN_O8(3);
 64.1028 +	break;
 64.1029 +case 0x3c:
 64.1030 +	// SUB R4,#Offset8
 64.1031 +	SUB_RN_O8(4);
 64.1032 +	break;
 64.1033 +case 0x3d:
 64.1034 +	// SUB R5,#Offset8
 64.1035 +	SUB_RN_O8(5);
 64.1036 +	break;
 64.1037 +case 0x3e:
 64.1038 +	// SUB R6,#Offset8
 64.1039 +	SUB_RN_O8(6);
 64.1040 +	break;
 64.1041 +case 0x3f:
 64.1042 +	// SUB R7,#Offset8
 64.1043 +	SUB_RN_O8(7);
 64.1044 +	break;
 64.1045 +case 0x40:
 64.1046 +	switch ((opcode >> 6) & 3)
 64.1047 +	{
 64.1048 +	case 0x00:
 64.1049 +	{
 64.1050 +		// AND Rd, Rs
 64.1051 +		int dest = opcode & 7;
 64.1052 +		reg[dest].I &= reg[(opcode >> 3) & 7].I;
 64.1053 +		N_FLAG		 = reg[dest].I & 0x80000000 ? true : false;
 64.1054 +		Z_FLAG		 = reg[dest].I ? false : true;
 64.1055 +#ifdef BKPT_SUPPORT
 64.1056 +#define THUMB_CONSOLE_OUTPUT(a, b) \
 64.1057 +	if ((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) { \
 64.1058 +		extern void (*dbgOutput)(char *, u32); \
 64.1059 +		dbgOutput((a), (b)); \
 64.1060 +	}
 64.1061 +#else
 64.1062 +#define THUMB_CONSOLE_OUTPUT(a, b)
 64.1063 +#endif
 64.1064 +		THUMB_CONSOLE_OUTPUT(NULL, reg[2].I);
 64.1065 +	}
 64.1066 +	break;
 64.1067 +	case 0x01:
 64.1068 +		// EOR Rd, Rs
 64.1069 +	{
 64.1070 +		int dest = opcode & 7;
 64.1071 +		reg[dest].I ^= reg[(opcode >> 3) & 7].I;
 64.1072 +		N_FLAG		 = reg[dest].I & 0x80000000 ? true : false;
 64.1073 +		Z_FLAG		 = reg[dest].I ? false : true;
 64.1074 +	}
 64.1075 +	break;
 64.1076 +	case 0x02:
 64.1077 +		// LSL Rd, Rs
 64.1078 +	{
 64.1079 +		int dest  = opcode & 7;
 64.1080 +		u32 value = reg[(opcode >> 3) & 7].B.B0;
 64.1081 +		if (value)
 64.1082 +		{
 64.1083 +			if (value == 32)
 64.1084 +			{
 64.1085 +				value  = 0;
 64.1086 +				C_FLAG = (reg[dest].I & 1 ? true : false);
 64.1087 +			}
 64.1088 +			else if (value < 32)
 64.1089 +			{
 64.1090 +				LSL_RD_RS;
 64.1091 +			}
 64.1092 +			else
 64.1093 +			{
 64.1094 +				value  = 0;
 64.1095 +				C_FLAG = false;
 64.1096 +			}
 64.1097 +			reg[dest].I = value;
 64.1098 +		}
 64.1099 +		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
 64.1100 +		Z_FLAG = reg[dest].I ? false : true;
 64.1101 +		clockTicks++;
 64.1102 +	}
 64.1103 +	break;
 64.1104 +	case 0x03:
 64.1105 +	{
 64.1106 +		// LSR Rd, Rs
 64.1107 +		int dest  = opcode & 7;
 64.1108 +		u32 value = reg[(opcode >> 3) & 7].B.B0;
 64.1109 +		if (value)
 64.1110 +		{
 64.1111 +			if (value == 32)
 64.1112 +			{
 64.1113 +				value  = 0;
 64.1114 +				C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
 64.1115 +			}
 64.1116 +			else if (value < 32)
 64.1117 +			{
 64.1118 +				LSR_RD_RS;
 64.1119 +			}
 64.1120 +			else
 64.1121 +			{
 64.1122 +				value  = 0;
 64.1123 +				C_FLAG = false;
 64.1124 +			}
 64.1125 +			reg[dest].I = value;
 64.1126 +		}
 64.1127 +		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
 64.1128 +		Z_FLAG = reg[dest].I ? false : true;
 64.1129 +		clockTicks++;
 64.1130 +	}
 64.1131 +	break;
 64.1132 +	}
 64.1133 +	break;
 64.1134 +case 0x41:
 64.1135 +	switch ((opcode >> 6) & 3)
 64.1136 +	{
 64.1137 +	case 0x00:
 64.1138 +	{
 64.1139 +		// ASR Rd, Rs
 64.1140 +		int dest  = opcode & 7;
 64.1141 +		u32 value = reg[(opcode >> 3) & 7].B.B0;
 64.1142 +		// ASR
 64.1143 +		if (value)
 64.1144 +		{
 64.1145 +			if (value < 32)
 64.1146 +			{
 64.1147 +				ASR_RD_RS;
 64.1148 +				reg[dest].I = value;
 64.1149 +			}
 64.1150 +			else
 64.1151 +			{
 64.1152 +				if (reg[dest].I & 0x80000000)
 64.1153 +				{
 64.1154 +					reg[dest].I = 0xFFFFFFFF;
 64.1155 +					C_FLAG		= true;
 64.1156 +				}
 64.1157 +				else
 64.1158 +				{
 64.1159 +					reg[dest].I = 0x00000000;
 64.1160 +					C_FLAG		= false;
 64.1161 +				}
 64.1162 +			}
 64.1163 +		}
 64.1164 +		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
 64.1165 +		Z_FLAG = reg[dest].I ? false : true;
 64.1166 +		clockTicks++;
 64.1167 +	}
 64.1168 +	break;
 64.1169 +	case 0x01:
 64.1170 +	{
 64.1171 +		// ADC Rd, Rs
 64.1172 +		int dest  = opcode & 0x07;
 64.1173 +		u32 value = reg[(opcode >> 3) & 7].I;
 64.1174 +		// ADC
 64.1175 +		ADC_RD_RS;
 64.1176 +	}
 64.1177 +	break;
 64.1178 +	case 0x02:
 64.1179 +	{
 64.1180 +		// SBC Rd, Rs
 64.1181 +		int dest  = opcode & 0x07;
 64.1182 +		u32 value = reg[(opcode >> 3) & 7].I;
 64.1183 +
 64.1184 +		// SBC
 64.1185 +		SBC_RD_RS;
 64.1186 +	}
 64.1187 +	break;
 64.1188 +	case 0x03:
 64.1189 +		// ROR Rd, Rs
 64.1190 +	{
 64.1191 +		int dest  = opcode & 7;
 64.1192 +		u32 value = reg[(opcode >> 3) & 7].B.B0;
 64.1193 +
 64.1194 +		if (value)
 64.1195 +		{
 64.1196 +			value = value & 0x1f;
 64.1197 +			if (value == 0)
 64.1198 +			{
 64.1199 +				C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
 64.1200 +			}
 64.1201 +			else
 64.1202 +			{
 64.1203 +				ROR_RD_RS;
 64.1204 +				reg[dest].I = value;
 64.1205 +			}
 64.1206 +		}
 64.1207 +		clockTicks++;
 64.1208 +		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
 64.1209 +		Z_FLAG = reg[dest].I ? false : true;
 64.1210 +	}
 64.1211 +	break;
 64.1212 +	}
 64.1213 +	break;
 64.1214 +case 0x42:
 64.1215 +	switch ((opcode >> 6) & 3)
 64.1216 +	{
 64.1217 +	case 0x00:
 64.1218 +	{
 64.1219 +		// TST Rd, Rs
 64.1220 +		u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I;
 64.1221 +		N_FLAG = value & 0x80000000 ? true : false;
 64.1222 +		Z_FLAG = value ? false : true;
 64.1223 +	}
 64.1224 +	break;
 64.1225 +	case 0x01:
 64.1226 +	{
 64.1227 +		// NEG Rd, Rs
 64.1228 +		int dest   = opcode & 7;
 64.1229 +		int source = (opcode >> 3) & 7;
 64.1230 +		NEG_RD_RS;
 64.1231 +	}
 64.1232 +	break;
 64.1233 +	case 0x02:
 64.1234 +	{
 64.1235 +		// CMP Rd, Rs
 64.1236 +		int dest  = opcode & 7;
 64.1237 +		u32 value = reg[(opcode >> 3) & 7].I;
 64.1238 +		CMP_RD_RS;
 64.1239 +	}
 64.1240 +	break;
 64.1241 +	case 0x03:
 64.1242 +	{
 64.1243 +		// CMN Rd, Rs
 64.1244 +		int dest  = opcode & 7;
 64.1245 +		u32 value = reg[(opcode >> 3) & 7].I;
 64.1246 +		// CMN
 64.1247 +		CMN_RD_RS;
 64.1248 +	}
 64.1249 +	break;
 64.1250 +	}
 64.1251 +	break;
 64.1252 +case 0x43:
 64.1253 +	switch ((opcode >> 6) & 3)
 64.1254 +	{
 64.1255 +	case 0x00:
 64.1256 +	{
 64.1257 +		// ORR Rd, Rs
 64.1258 +		int dest = opcode & 7;
 64.1259 +		reg[dest].I |= reg[(opcode >> 3) & 7].I;
 64.1260 +		Z_FLAG		 = reg[dest].I ? false : true;
 64.1261 +		N_FLAG		 = reg[dest].I & 0x80000000 ? true : false;
 64.1262 +	}
 64.1263 +	break;
 64.1264 +	case 0x01:
 64.1265 +	{
 64.1266 +		// MUL Rd, Rs
 64.1267 +		int dest = opcode & 7;
 64.1268 +		u32 rm	 = reg[(opcode >> 3) & 7].I;
 64.1269 +		reg[dest].I = reg[dest].I * rm;
 64.1270 +		if (((s32)rm) < 0)
 64.1271 +			rm = ~rm;
 64.1272 +		if ((rm & 0xFFFFFF00) == 0)
 64.1273 +			clockTicks += 1;
 64.1274 +		else if ((rm & 0xFFFF0000) == 0)
 64.1275 +			clockTicks += 2;
 64.1276 +		else if ((rm & 0xFF000000) == 0)
 64.1277 +			clockTicks += 3;
 64.1278 +		else
 64.1279 +			clockTicks += 4;
 64.1280 +		Z_FLAG = reg[dest].I ? false : true;
 64.1281 +		N_FLAG = reg[dest].I & 0x80000000 ? true : false;
 64.1282 +	}
 64.1283 +	break;
 64.1284 +	case 0x02:
 64.1285 +	{
 64.1286 +		// BIC Rd, Rs
 64.1287 +		int dest = opcode & 7;
 64.1288 +		reg[dest].I &= (~reg[(opcode >> 3) & 7].I);
 64.1289 +		Z_FLAG		 = reg[dest].I ? false : true;
 64.1290 +		N_FLAG		 = reg[dest].I & 0x80000000 ? true : false;
 64.1291 +	}
 64.1292 +	break;
 64.1293 +	case 0x03:
 64.1294 +	{
 64.1295 +		// MVN Rd, Rs
 64.1296 +		int dest = opcode & 7;
 64.1297 +		reg[dest].I = ~reg[(opcode >> 3) & 7].I;
 64.1298 +		Z_FLAG		= reg[dest].I ? false : true;
 64.1299 +		N_FLAG		= reg[dest].I & 0x80000000 ? true : false;
 64.1300 +	}
 64.1301 +	break;
 64.1302 +	}
 64.1303 +	break;
 64.1304 +case 0x44:
 64.1305 +{
 64.1306 +	int dest = opcode & 7;
 64.1307 +	int base = (opcode >> 3) & 7;
 64.1308 +	switch ((opcode >> 6) & 3)
 64.1309 +	{
 64.1310 +	default:
 64.1311 +		goto unknown_thumb;
 64.1312 +	case 1:
 64.1313 +		// ADD Rd, Hs
 64.1314 +		reg[dest].I += reg[base + 8].I;
 64.1315 +		break;
 64.1316 +	case 2:
 64.1317 +		// ADD Hd, Rs
 64.1318 +		reg[dest + 8].I += reg[base].I;
 64.1319 +		if (dest == 7)
 64.1320 +		{
 64.1321 +			reg[15].I &= 0xFFFFFFFE;
 64.1322 +			armNextPC  = reg[15].I;
 64.1323 +			reg[15].I += 2;
 64.1324 +			clockTicks++;
 64.1325 +		}
 64.1326 +		break;
 64.1327 +	case 3:
 64.1328 +		// ADD Hd, Hs
 64.1329 +		reg[dest + 8].I += reg[base + 8].I;
 64.1330 +		if (dest == 7)
 64.1331 +		{
 64.1332 +			reg[15].I &= 0xFFFFFFFE;
 64.1333 +			armNextPC  = reg[15].I;
 64.1334 +			reg[15].I += 2;
 64.1335 +			clockTicks++;
 64.1336 +		}
 64.1337 +		break;
 64.1338 +	}
 64.1339 +}
 64.1340 +break;
 64.1341 +case 0x45:
 64.1342 +{
 64.1343 +	int dest = opcode & 7;
 64.1344 +	int base = (opcode >> 3) & 7;
 64.1345 +	u32 value;
 64.1346 +	switch ((opcode >> 6) & 3)
 64.1347 +	{
 64.1348 +	case 0:
 64.1349 +		// CMP Rd, Hs
 64.1350 +		value = reg[base].I;
 64.1351 +		CMP_RD_RS;
 64.1352 +		break;
 64.1353 +	case 1:
 64.1354 +		// CMP Rd, Hs
 64.1355 +		value = reg[base + 8].I;
 64.1356 +		CMP_RD_RS;
 64.1357 +		break;
 64.1358 +	case 2:
 64.1359 +		// CMP Hd, Rs
 64.1360 +		value = reg[base].I;
 64.1361 +		dest += 8;
 64.1362 +		CMP_RD_RS;
 64.1363 +		break;
 64.1364 +	case 3:
 64.1365 +		// CMP Hd, Hs
 64.1366 +		value = reg[base + 8].I;
 64.1367 +		dest += 8;
 64.1368 +		CMP_RD_RS;
 64.1369 +		break;
 64.1370 +	}
 64.1371 +}
 64.1372 +break;
 64.1373 +case 0x46:
 64.1374 +{
 64.1375 +	int dest = opcode & 7;
 64.1376 +	int base = (opcode >> 3) & 7;
 64.1377 +	switch ((opcode >> 6) & 3)
 64.1378 +	{
 64.1379 +	case 0:
 64.1380 +		// this form should not be used...
 64.1381 +		// MOV Rd, Rs
 64.1382 +		reg[dest].I = reg[base].I;
 64.1383 +		break;
 64.1384 +	case 1:
 64.1385 +		// MOV Rd, Hs
 64.1386 +		reg[dest].I = reg[base + 8].I;
 64.1387 +		break;
 64.1388 +	case 2:
 64.1389 +		// MOV Hd, Rs
 64.1390 +		reg[dest + 8].I = reg[base].I;
 64.1391 +		if (dest == 7)
 64.1392 +		{
 64.1393 +			reg[15].I &= 0xFFFFFFFE;
 64.1394 +			armNextPC  = reg[15].I;
 64.1395 +			reg[15].I += 2;
 64.1396 +			clockTicks++;
 64.1397 +		}
 64.1398 +		break;
 64.1399 +	case 3:
 64.1400 +		// MOV Hd, Hs
 64.1401 +		reg[dest + 8].I = reg[base + 8].I;
 64.1402 +		if (dest == 7)
 64.1403 +		{
 64.1404 +			reg[15].I &= 0xFFFFFFFE;
 64.1405 +			armNextPC  = reg[15].I;
 64.1406 +			reg[15].I += 2;
 64.1407 +			clockTicks++;
 64.1408 +		}
 64.1409 +		break;
 64.1410 +	}
 64.1411 +}
 64.1412 +break;
 64.1413 +case 0x47:
 64.1414 +{
 64.1415 +	int base = (opcode >> 3) & 7;
 64.1416 +	switch ((opcode >> 6) & 3)
 64.1417 +	{
 64.1418 +	case 0:
 64.1419 +		// BX Rs
 64.1420 +		reg[15].I = (reg[base].I) & 0xFFFFFFFE;
 64.1421 +		if (reg[base].I & 1)
 64.1422 +		{
 64.1423 +			armState   = false;
 64.1424 +			armNextPC  = reg[15].I;
 64.1425 +			reg[15].I += 2;
 64.1426 +		}
 64.1427 +		else
 64.1428 +		{
 64.1429 +			armState   = true;
 64.1430 +			reg[15].I &= 0xFFFFFFFC;
 64.1431 +			armNextPC  = reg[15].I;
 64.1432 +			reg[15].I += 4;
 64.1433 +		}
 64.1434 +		break;
 64.1435 +	case 1:
 64.1436 +		// BX Hs
 64.1437 +		reg[15].I = (reg[8 + base].I) & 0xFFFFFFFE;
 64.1438 +		if (reg[8 + base].I & 1)
 64.1439 +		{
 64.1440 +			armState   = false;
 64.1441 +			armNextPC  = reg[15].I;
 64.1442 +			reg[15].I += 2;
 64.1443 +		}
 64.1444 +		else
 64.1445 +		{
 64.1446 +			armState   = true;
 64.1447 +			reg[15].I &= 0xFFFFFFFC;
 64.1448 +			armNextPC  = reg[15].I;
 64.1449 +			reg[15].I += 4;
 64.1450 +		}
 64.1451 +		break;
 64.1452 +	default:
 64.1453 +		goto unknown_thumb;
 64.1454 +	}
 64.1455 +}
 64.1456 +break;
 64.1457 +case 0x48:
 64.1458 +	// LDR R0,[PC, #Imm]
 64.1459 +{
 64.1460 +	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
 64.1461 +	reg[0].I	= CPUReadMemoryQuick(address);
 64.1462 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1463 +}
 64.1464 +break;
 64.1465 +case 0x49:
 64.1466 +	// LDR R1,[PC, #Imm]
 64.1467 +{
 64.1468 +	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
 64.1469 +	reg[1].I	= CPUReadMemoryQuick(address);
 64.1470 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1471 +}
 64.1472 +break;
 64.1473 +case 0x4a:
 64.1474 +	// LDR R2,[PC, #Imm]
 64.1475 +{
 64.1476 +	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
 64.1477 +	reg[2].I	= CPUReadMemoryQuick(address);
 64.1478 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1479 +}
 64.1480 +break;
 64.1481 +case 0x4b:
 64.1482 +	// LDR R3,[PC, #Imm]
 64.1483 +{
 64.1484 +	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
 64.1485 +	reg[3].I	= CPUReadMemoryQuick(address);
 64.1486 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1487 +}
 64.1488 +break;
 64.1489 +case 0x4c:
 64.1490 +	// LDR R4,[PC, #Imm]
 64.1491 +{
 64.1492 +	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
 64.1493 +	reg[4].I	= CPUReadMemoryQuick(address);
 64.1494 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1495 +}
 64.1496 +break;
 64.1497 +case 0x4d:
 64.1498 +	// LDR R5,[PC, #Imm]
 64.1499 +{
 64.1500 +	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
 64.1501 +	reg[5].I	= CPUReadMemoryQuick(address);
 64.1502 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1503 +}
 64.1504 +break;
 64.1505 +case 0x4e:
 64.1506 +	// LDR R6,[PC, #Imm]
 64.1507 +{
 64.1508 +	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
 64.1509 +	reg[6].I	= CPUReadMemoryQuick(address);
 64.1510 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1511 +}
 64.1512 +break;
 64.1513 +case 0x4f:
 64.1514 +	// LDR R7,[PC, #Imm]
 64.1515 +{
 64.1516 +	u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
 64.1517 +	reg[7].I	= CPUReadMemoryQuick(address);
 64.1518 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1519 +}
 64.1520 +break;
 64.1521 +case 0x50:
 64.1522 +case 0x51:
 64.1523 +	// STR Rd, [Rs, Rn]
 64.1524 +{
 64.1525 +	u32
 64.1526 +	    address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
 64.1527 +	CPUWriteMemory(address,
 64.1528 +	               reg[opcode & 7].I);
 64.1529 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1530 +}
 64.1531 +break;
 64.1532 +case 0x52:
 64.1533 +case 0x53:
 64.1534 +	// STRH Rd, [Rs, Rn]
 64.1535 +{
 64.1536 +	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
 64.1537 +	CPUWriteHalfWord(address,
 64.1538 +	                 reg[opcode & 7].W.W0);
 64.1539 +	clockTicks += CPUUpdateTicksAccess16(address);
 64.1540 +}
 64.1541 +break;
 64.1542 +case 0x54:
 64.1543 +case 0x55:
 64.1544 +	// STRB Rd, [Rs, Rn]
 64.1545 +{
 64.1546 +	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
 64.1547 +	CPUWriteByte(address,
 64.1548 +	             reg[opcode & 7].B.B0);
 64.1549 +	clockTicks += CPUUpdateTicksAccess16(address);
 64.1550 +}
 64.1551 +break;
 64.1552 +case 0x56:
 64.1553 +case 0x57:
 64.1554 +	// LDSB Rd, [Rs, Rn]
 64.1555 +{
 64.1556 +	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
 64.1557 +	reg[opcode & 7].I = (s8)CPUReadByte(address);
 64.1558 +	clockTicks		 += CPUUpdateTicksAccess16(address);
 64.1559 +}
 64.1560 +break;
 64.1561 +case 0x58:
 64.1562 +case 0x59:
 64.1563 +	// LDR Rd, [Rs, Rn]
 64.1564 +{
 64.1565 +	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
 64.1566 +	reg[opcode & 7].I = CPUReadMemory(address);
 64.1567 +	clockTicks		 += CPUUpdateTicksAccess32(address);
 64.1568 +}
 64.1569 +break;
 64.1570 +case 0x5a:
 64.1571 +case 0x5b:
 64.1572 +	// LDRH Rd, [Rs, Rn]
 64.1573 +{
 64.1574 +	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
 64.1575 +	reg[opcode & 7].I = CPUReadHalfWord(address);
 64.1576 +	clockTicks		 += CPUUpdateTicksAccess16(address);
 64.1577 +}
 64.1578 +break;
 64.1579 +case 0x5c:
 64.1580 +case 0x5d:
 64.1581 +	// LDRB Rd, [Rs, Rn]
 64.1582 +{
 64.1583 +	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
 64.1584 +	reg[opcode & 7].I = CPUReadByte(address);
 64.1585 +	clockTicks		 += CPUUpdateTicksAccess16(address);
 64.1586 +}
 64.1587 +break;
 64.1588 +case 0x5e:
 64.1589 +case 0x5f:
 64.1590 +	// LDSH Rd, [Rs, Rn]
 64.1591 +{
 64.1592 +	u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I;
 64.1593 +	reg[opcode & 7].I = (s16)CPUReadHalfWordSigned(address);
 64.1594 +	clockTicks		 += CPUUpdateTicksAccess16(address);
 64.1595 +}
 64.1596 +break;
 64.1597 +case 0x60:
 64.1598 +case 0x61:
 64.1599 +case 0x62:
 64.1600 +case 0x63:
 64.1601 +case 0x64:
 64.1602 +case 0x65:
 64.1603 +case 0x66:
 64.1604 +case 0x67:
 64.1605 +	// STR Rd, [Rs, #Imm]
 64.1606 +{
 64.1607 +	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 2);
 64.1608 +	CPUWriteMemory(address,
 64.1609 +	               reg[opcode & 7].I);
 64.1610 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1611 +}
 64.1612 +break;
 64.1613 +case 0x68:
 64.1614 +case 0x69:
 64.1615 +case 0x6a:
 64.1616 +case 0x6b:
 64.1617 +case 0x6c:
 64.1618 +case 0x6d:
 64.1619 +case 0x6e:
 64.1620 +case 0x6f:
 64.1621 +	// LDR Rd, [Rs, #Imm]
 64.1622 +{
 64.1623 +	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 2);
 64.1624 +	reg[opcode & 7].I = CPUReadMemory(address);
 64.1625 +	clockTicks		 += CPUUpdateTicksAccess32(address);
 64.1626 +}
 64.1627 +break;
 64.1628 +case 0x70:
 64.1629 +case 0x71:
 64.1630 +case 0x72:
 64.1631 +case 0x73:
 64.1632 +case 0x74:
 64.1633 +case 0x75:
 64.1634 +case 0x76:
 64.1635 +case 0x77:
 64.1636 +	// STRB Rd, [Rs, #Imm]
 64.1637 +{
 64.1638 +	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31));
 64.1639 +	CPUWriteByte(address,
 64.1640 +	             reg[opcode & 7].B.B0);
 64.1641 +	clockTicks += CPUUpdateTicksAccess16(address);
 64.1642 +}
 64.1643 +break;
 64.1644 +case 0x78:
 64.1645 +case 0x79:
 64.1646 +case 0x7a:
 64.1647 +case 0x7b:
 64.1648 +case 0x7c:
 64.1649 +case 0x7d:
 64.1650 +case 0x7e:
 64.1651 +case 0x7f:
 64.1652 +	// LDRB Rd, [Rs, #Imm]
 64.1653 +{
 64.1654 +	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31));
 64.1655 +	reg[opcode & 7].I = CPUReadByte(address);
 64.1656 +	clockTicks		 += CPUUpdateTicksAccess16(address);
 64.1657 +}
 64.1658 +break;
 64.1659 +case 0x80:
 64.1660 +case 0x81:
 64.1661 +case 0x82:
 64.1662 +case 0x83:
 64.1663 +case 0x84:
 64.1664 +case 0x85:
 64.1665 +case 0x86:
 64.1666 +case 0x87:
 64.1667 +	// STRH Rd, [Rs, #Imm]
 64.1668 +{
 64.1669 +	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 1);
 64.1670 +	CPUWriteHalfWord(address,
 64.1671 +	                 reg[opcode & 7].W.W0);
 64.1672 +	clockTicks += CPUUpdateTicksAccess16(address);
 64.1673 +}
 64.1674 +break;
 64.1675 +case 0x88:
 64.1676 +case 0x89:
 64.1677 +case 0x8a:
 64.1678 +case 0x8b:
 64.1679 +case 0x8c:
 64.1680 +case 0x8d:
 64.1681 +case 0x8e:
 64.1682 +case 0x8f:
 64.1683 +	// LDRH Rd, [Rs, #Imm]
 64.1684 +{
 64.1685 +	u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 1);
 64.1686 +	reg[opcode & 7].I = CPUReadHalfWord(address);
 64.1687 +	clockTicks		 += CPUUpdateTicksAccess16(address);
 64.1688 +}
 64.1689 +break;
 64.1690 +case 0x90:
 64.1691 +	// STR R0, [SP, #Imm]
 64.1692 +{
 64.1693 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1694 +	CPUWriteMemory(address, reg[0].I);
 64.1695 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1696 +}
 64.1697 +break;
 64.1698 +case 0x91:
 64.1699 +	// STR R1, [SP, #Imm]
 64.1700 +{
 64.1701 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1702 +	CPUWriteMemory(address, reg[1].I);
 64.1703 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1704 +}
 64.1705 +break;
 64.1706 +case 0x92:
 64.1707 +	// STR R2, [SP, #Imm]
 64.1708 +{
 64.1709 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1710 +	CPUWriteMemory(address, reg[2].I);
 64.1711 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1712 +}
 64.1713 +break;
 64.1714 +case 0x93:
 64.1715 +	// STR R3, [SP, #Imm]
 64.1716 +{
 64.1717 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1718 +	CPUWriteMemory(address, reg[3].I);
 64.1719 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1720 +}
 64.1721 +break;
 64.1722 +case 0x94:
 64.1723 +	// STR R4, [SP, #Imm]
 64.1724 +{
 64.1725 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1726 +	CPUWriteMemory(address, reg[4].I);
 64.1727 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1728 +}
 64.1729 +break;
 64.1730 +case 0x95:
 64.1731 +	// STR R5, [SP, #Imm]
 64.1732 +{
 64.1733 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1734 +	CPUWriteMemory(address, reg[5].I);
 64.1735 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1736 +}
 64.1737 +break;
 64.1738 +case 0x96:
 64.1739 +	// STR R6, [SP, #Imm]
 64.1740 +{
 64.1741 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1742 +	CPUWriteMemory(address, reg[6].I);
 64.1743 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1744 +}
 64.1745 +break;
 64.1746 +case 0x97:
 64.1747 +	// STR R7, [SP, #Imm]
 64.1748 +{
 64.1749 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1750 +	CPUWriteMemory(address, reg[7].I);
 64.1751 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1752 +}
 64.1753 +break;
 64.1754 +case 0x98:
 64.1755 +	// LDR R0, [SP, #Imm]
 64.1756 +{
 64.1757 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1758 +	reg[0].I	= CPUReadMemoryQuick(address);
 64.1759 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1760 +}
 64.1761 +break;
 64.1762 +case 0x99:
 64.1763 +	// LDR R1, [SP, #Imm]
 64.1764 +{
 64.1765 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1766 +	reg[1].I	= CPUReadMemoryQuick(address);
 64.1767 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1768 +}
 64.1769 +break;
 64.1770 +case 0x9a:
 64.1771 +	// LDR R2, [SP, #Imm]
 64.1772 +{
 64.1773 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1774 +	reg[2].I	= CPUReadMemoryQuick(address);
 64.1775 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1776 +}
 64.1777 +break;
 64.1778 +case 0x9b:
 64.1779 +	// LDR R3, [SP, #Imm]
 64.1780 +{
 64.1781 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1782 +	reg[3].I	= CPUReadMemoryQuick(address);
 64.1783 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1784 +}
 64.1785 +break;
 64.1786 +case 0x9c:
 64.1787 +	// LDR R4, [SP, #Imm]
 64.1788 +{
 64.1789 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1790 +	reg[4].I	= CPUReadMemoryQuick(address);
 64.1791 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1792 +}
 64.1793 +break;
 64.1794 +case 0x9d:
 64.1795 +	// LDR R5, [SP, #Imm]
 64.1796 +{
 64.1797 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1798 +	reg[5].I	= CPUReadMemoryQuick(address);
 64.1799 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1800 +}
 64.1801 +break;
 64.1802 +case 0x9e:
 64.1803 +	// LDR R6, [SP, #Imm]
 64.1804 +{
 64.1805 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1806 +	reg[6].I	= CPUReadMemoryQuick(address);
 64.1807 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1808 +}
 64.1809 +break;
 64.1810 +case 0x9f:
 64.1811 +	// LDR R7, [SP, #Imm]
 64.1812 +{
 64.1813 +	u32 address = reg[13].I + ((opcode & 255) << 2);
 64.1814 +	reg[7].I	= CPUReadMemoryQuick(address);
 64.1815 +	clockTicks += CPUUpdateTicksAccess32(address);
 64.1816 +}
 64.1817 +break;
 64.1818 +case 0xa0:
 64.1819 +	// ADD R0, PC, Imm
 64.1820 +	reg[0].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
 64.1821 +	break;
 64.1822 +case 0xa1:
 64.1823 +	// ADD R1, PC, Imm
 64.1824 +	reg[1].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
 64.1825 +	break;
 64.1826 +case 0xa2:
 64.1827 +	// ADD R2, PC, Imm
 64.1828 +	reg[2].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
 64.1829 +	break;
 64.1830 +case 0xa3:
 64.1831 +	// ADD R3, PC, Imm
 64.1832 +	reg[3].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
 64.1833 +	break;
 64.1834 +case 0xa4:
 64.1835 +	// ADD R4, PC, Imm
 64.1836 +	reg[4].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
 64.1837 +	break;
 64.1838 +case 0xa5:
 64.1839 +	// ADD R5, PC, Imm
 64.1840 +	reg[5].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
 64.1841 +	break;
 64.1842 +case 0xa6:
 64.1843 +	// ADD R6, PC, Imm
 64.1844 +	reg[6].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
 64.1845 +	break;
 64.1846 +case 0xa7:
 64.1847 +	// ADD R7, PC, Imm
 64.1848 +	reg[7].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2);
 64.1849 +	break;
 64.1850 +case 0xa8:
 64.1851 +	// ADD R0, SP, Imm
 64.1852 +	reg[0].I = reg[13].I + ((opcode & 255) << 2);
 64.1853 +	break;
 64.1854 +case 0xa9:
 64.1855 +	// ADD R1, SP, Imm
 64.1856 +	reg[1].I = reg[13].I + ((opcode & 255) << 2);
 64.1857 +	break;
 64.1858 +case 0xaa:
 64.1859 +	// ADD R2, SP, Imm
 64.1860 +	reg[2].I = reg[13].I + ((opcode & 255) << 2);
 64.1861 +	break;
 64.1862 +case 0xab:
 64.1863 +	// ADD R3, SP, Imm
 64.1864 +	reg[3].I = reg[13].I + ((opcode & 255) << 2);
 64.1865 +	break;
 64.1866 +case 0xac:
 64.1867 +	// ADD R4, SP, Imm
 64.1868 +	reg[4].I = reg[13].I + ((opcode & 255) << 2);
 64.1869 +	break;
 64.1870 +case 0xad:
 64.1871 +	// ADD R5, SP, Imm
 64.1872 +	reg[5].I = reg[13].I + ((opcode & 255) << 2);
 64.1873 +	break;
 64.1874 +case 0xae:
 64.1875 +	// ADD R6, SP, Imm
 64.1876 +	reg[6].I = reg[13].I + ((opcode & 255) << 2);
 64.1877 +	break;
 64.1878 +case 0xaf:
 64.1879 +	// ADD R7, SP, Imm
 64.1880 +	reg[7].I = reg[13].I + ((opcode & 255) << 2);
 64.1881 +	break;
 64.1882 +case 0xb0:
 64.1883 +{
 64.1884 +	// ADD SP, Imm
 64.1885 +	int offset = (opcode & 127) << 2;
 64.1886 +	if (opcode & 0x80)
 64.1887 +		offset = -offset;
 64.1888 +	reg[13].I += offset;
 64.1889 +}
 64.1890 +break;
 64.1891 +#define PUSH_REG(val, r) \
 64.1892 +	if (opcode & (val)) { \
 64.1893 +		CPUWriteMemory(address, reg[(r)].I); \
 64.1894 +		if (offset) \
 64.1895 +			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
 64.1896 +		else \
 64.1897 +			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
 64.1898 +		offset	 = 1; \
 64.1899 +		address += 4; \
 64.1900 +	}
 64.1901 +case 0xb4:
 64.1902 +	// PUSH {Rlist}
 64.1903 +{
 64.1904 +	int offset	= 0;
 64.1905 +	u32 temp	= reg[13].I - 4 * cpuBitsSet[opcode & 0xff];
 64.1906 +	u32 address = temp & 0xFFFFFFFC;
 64.1907 +	PUSH_REG(1, 0);
 64.1908 +	PUSH_REG(2, 1);
 64.1909 +	PUSH_REG(4, 2);
 64.1910 +	PUSH_REG(8, 3);
 64.1911 +	PUSH_REG(16, 4);
 64.1912 +	PUSH_REG(32, 5);
 64.1913 +	PUSH_REG(64, 6);
 64.1914 +	PUSH_REG(128, 7);
 64.1915 +	reg[13].I = temp;
 64.1916 +}
 64.1917 +break;
 64.1918 +case 0xb5:
 64.1919 +	// PUSH {Rlist, LR}
 64.1920 +{
 64.1921 +	int offset	= 0;
 64.1922 +	u32 temp	= reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff];
 64.1923 +	u32 address = temp & 0xFFFFFFFC;
 64.1924 +	PUSH_REG(1, 0);
 64.1925 +	PUSH_REG(2, 1);
 64.1926 +	PUSH_REG(4, 2);
 64.1927 +	PUSH_REG(8, 3);
 64.1928 +	PUSH_REG(16, 4);
 64.1929 +	PUSH_REG(32, 5);
 64.1930 +	PUSH_REG(64, 6);
 64.1931 +	PUSH_REG(128, 7);
 64.1932 +	PUSH_REG(256, 14);
 64.1933 +	reg[13].I = temp;
 64.1934 +}
 64.1935 +break;
 64.1936 +#define POP_REG(val, r) \
 64.1937 +	if (opcode & (val)) { \
 64.1938 +		reg[(r)].I = CPUReadMemory(address); \
 64.1939 +		if (offset) \
 64.1940 +			clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); \
 64.1941 +		else \
 64.1942 +			clockTicks += 2 + CPUUpdateTicksAccess32(address); \
 64.1943 +		offset	 = 1; \
 64.1944 +		address += 4; \
 64.1945 +	}
 64.1946 +case 0xbc:
 64.1947 +	// POP {Rlist}
 64.1948 +{
 64.1949 +	int offset	= 0;
 64.1950 +	u32 address = reg[13].I & 0xFFFFFFFC;
 64.1951 +	u32 temp	= reg[13].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.1952 +	POP_REG(1, 0);
 64.1953 +	POP_REG(2, 1);
 64.1954 +	POP_REG(4, 2);
 64.1955 +	POP_REG(8, 3);
 64.1956 +	POP_REG(16, 4);
 64.1957 +	POP_REG(32, 5);
 64.1958 +	POP_REG(64, 6);
 64.1959 +	POP_REG(128, 7);
 64.1960 +	reg[13].I = temp;
 64.1961 +}
 64.1962 +break;
 64.1963 +case 0xbd:
 64.1964 +	// POP {Rlist, PC}
 64.1965 +{
 64.1966 +	int offset	= 0;
 64.1967 +	u32 address = reg[13].I & 0xFFFFFFFC;
 64.1968 +	u32 temp	= reg[13].I + 4 + 4 * cpuBitsSet[opcode & 0xFF];
 64.1969 +	POP_REG(1, 0);
 64.1970 +	POP_REG(2, 1);
 64.1971 +	POP_REG(4, 2);
 64.1972 +	POP_REG(8, 3);
 64.1973 +	POP_REG(16, 4);
 64.1974 +	POP_REG(32, 5);
 64.1975 +	POP_REG(64, 6);
 64.1976 +	POP_REG(128, 7);
 64.1977 +	reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE);
 64.1978 +	if (offset)
 64.1979 +		clockTicks += CPUUpdateTicksAccessSeq32(address);
 64.1980 +	else
 64.1981 +		clockTicks += CPUUpdateTicksAccess32(address);
 64.1982 +	armNextPC  = reg[15].I;
 64.1983 +	reg[15].I += 2;
 64.1984 +	reg[13].I  = temp;
 64.1985 +}
 64.1986 +break;
 64.1987 +#define THUMB_STM_REG(val, r, b) \
 64.1988 +	if (opcode & (val)) { \
 64.1989 +		CPUWriteMemory(address, reg[(r)].I); \
 64.1990 +		if (!offset) { \
 64.1991 +			reg[(b)].I	= temp; \
 64.1992 +			clockTicks += 1 + CPUUpdateTicksAccess32(address); \
 64.1993 +		} else \
 64.1994 +			clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \
 64.1995 +		offset	 = 1; \
 64.1996 +		address += 4; \
 64.1997 +	}
 64.1998 +case 0xc0:
 64.1999 +{
 64.2000 +	// STM R0!, {Rlist}
 64.2001 +	u32 address = reg[0].I & 0xFFFFFFFC;
 64.2002 +	u32 temp	= reg[0].I + 4 * cpuBitsSet[opcode & 0xff];
 64.2003 +	int offset	= 0;
 64.2004 +	// store
 64.2005 +	THUMB_STM_REG(1, 0, 0);
 64.2006 +	THUMB_STM_REG(2, 1, 0);
 64.2007 +	THUMB_STM_REG(4, 2, 0);
 64.2008 +	THUMB_STM_REG(8, 3, 0);
 64.2009 +	THUMB_STM_REG(16, 4, 0);
 64.2010 +	THUMB_STM_REG(32, 5, 0);
 64.2011 +	THUMB_STM_REG(64, 6, 0);
 64.2012 +	THUMB_STM_REG(128, 7, 0);
 64.2013 +}
 64.2014 +break;
 64.2015 +case 0xc1:
 64.2016 +{
 64.2017 +	// STM R1!, {Rlist}
 64.2018 +	u32 address = reg[1].I & 0xFFFFFFFC;
 64.2019 +	u32 temp	= reg[1].I + 4 * cpuBitsSet[opcode & 0xff];
 64.2020 +	int offset	= 0;
 64.2021 +	// store
 64.2022 +	THUMB_STM_REG(1, 0, 1);
 64.2023 +	THUMB_STM_REG(2, 1, 1);
 64.2024 +	THUMB_STM_REG(4, 2, 1);
 64.2025 +	THUMB_STM_REG(8, 3, 1);
 64.2026 +	THUMB_STM_REG(16, 4, 1);
 64.2027 +	THUMB_STM_REG(32, 5, 1);
 64.2028 +	THUMB_STM_REG(64, 6, 1);
 64.2029 +	THUMB_STM_REG(128, 7, 1);
 64.2030 +}
 64.2031 +break;
 64.2032 +case 0xc2:
 64.2033 +{
 64.2034 +	// STM R2!, {Rlist}
 64.2035 +	u32 address = reg[2].I & 0xFFFFFFFC;
 64.2036 +	u32 temp	= reg[2].I + 4 * cpuBitsSet[opcode & 0xff];
 64.2037 +	int offset	= 0;
 64.2038 +	// store
 64.2039 +	THUMB_STM_REG(1, 0, 2);
 64.2040 +	THUMB_STM_REG(2, 1, 2);
 64.2041 +	THUMB_STM_REG(4, 2, 2);
 64.2042 +	THUMB_STM_REG(8, 3, 2);
 64.2043 +	THUMB_STM_REG(16, 4, 2);
 64.2044 +	THUMB_STM_REG(32, 5, 2);
 64.2045 +	THUMB_STM_REG(64, 6, 2);
 64.2046 +	THUMB_STM_REG(128, 7, 2);
 64.2047 +}
 64.2048 +break;
 64.2049 +case 0xc3:
 64.2050 +{
 64.2051 +	// STM R3!, {Rlist}
 64.2052 +	u32 address = reg[3].I & 0xFFFFFFFC;
 64.2053 +	u32 temp	= reg[3].I + 4 * cpuBitsSet[opcode & 0xff];
 64.2054 +	int offset	= 0;
 64.2055 +	// store
 64.2056 +	THUMB_STM_REG(1, 0, 3);
 64.2057 +	THUMB_STM_REG(2, 1, 3);
 64.2058 +	THUMB_STM_REG(4, 2, 3);
 64.2059 +	THUMB_STM_REG(8, 3, 3);
 64.2060 +	THUMB_STM_REG(16, 4, 3);
 64.2061 +	THUMB_STM_REG(32, 5, 3);
 64.2062 +	THUMB_STM_REG(64, 6, 3);
 64.2063 +	THUMB_STM_REG(128, 7, 3);
 64.2064 +}
 64.2065 +break;
 64.2066 +case 0xc4:
 64.2067 +{
 64.2068 +	// STM R4!, {Rlist}
 64.2069 +	u32 address = reg[4].I & 0xFFFFFFFC;
 64.2070 +	u32 temp	= reg[4].I + 4 * cpuBitsSet[opcode & 0xff];
 64.2071 +	int offset	= 0;
 64.2072 +	// store
 64.2073 +	THUMB_STM_REG(1, 0, 4);
 64.2074 +	THUMB_STM_REG(2, 1, 4);
 64.2075 +	THUMB_STM_REG(4, 2, 4);
 64.2076 +	THUMB_STM_REG(8, 3, 4);
 64.2077 +	THUMB_STM_REG(16, 4, 4);
 64.2078 +	THUMB_STM_REG(32, 5, 4);
 64.2079 +	THUMB_STM_REG(64, 6, 4);
 64.2080 +	THUMB_STM_REG(128, 7, 4);
 64.2081 +}
 64.2082 +break;
 64.2083 +case 0xc5:
 64.2084 +{
 64.2085 +	// STM R5!, {Rlist}
 64.2086 +	u32 address = reg[5].I & 0xFFFFFFFC;
 64.2087 +	u32 temp	= reg[5].I + 4 * cpuBitsSet[opcode & 0xff];
 64.2088 +	int offset	= 0;
 64.2089 +	// store
 64.2090 +	THUMB_STM_REG(1, 0, 5);
 64.2091 +	THUMB_STM_REG(2, 1, 5);
 64.2092 +	THUMB_STM_REG(4, 2, 5);
 64.2093 +	THUMB_STM_REG(8, 3, 5);
 64.2094 +	THUMB_STM_REG(16, 4, 5);
 64.2095 +	THUMB_STM_REG(32, 5, 5);
 64.2096 +	THUMB_STM_REG(64, 6, 5);
 64.2097 +	THUMB_STM_REG(128, 7, 5);
 64.2098 +}
 64.2099 +break;
 64.2100 +case 0xc6:
 64.2101 +{
 64.2102 +	// STM R6!, {Rlist}
 64.2103 +	u32 address = reg[6].I & 0xFFFFFFFC;
 64.2104 +	u32 temp	= reg[6].I + 4 * cpuBitsSet[opcode & 0xff];
 64.2105 +	int offset	= 0;
 64.2106 +	// store
 64.2107 +	THUMB_STM_REG(1, 0, 6);
 64.2108 +	THUMB_STM_REG(2, 1, 6);
 64.2109 +	THUMB_STM_REG(4, 2, 6);
 64.2110 +	THUMB_STM_REG(8, 3, 6);
 64.2111 +	THUMB_STM_REG(16, 4, 6);
 64.2112 +	THUMB_STM_REG(32, 5, 6);
 64.2113 +	THUMB_STM_REG(64, 6, 6);
 64.2114 +	THUMB_STM_REG(128, 7, 6);
 64.2115 +}
 64.2116 +break;
 64.2117 +case 0xc7:
 64.2118 +{
 64.2119 +	// STM R7!, {Rlist}
 64.2120 +	u32 address = reg[7].I & 0xFFFFFFFC;
 64.2121 +	u32 temp	= reg[7].I + 4 * cpuBitsSet[opcode & 0xff];
 64.2122 +	int offset	= 0;
 64.2123 +	// store
 64.2124 +	THUMB_STM_REG(1, 0, 7);
 64.2125 +	THUMB_STM_REG(2, 1, 7);
 64.2126 +	THUMB_STM_REG(4, 2, 7);
 64.2127 +	THUMB_STM_REG(8, 3, 7);
 64.2128 +	THUMB_STM_REG(16, 4, 7);
 64.2129 +	THUMB_STM_REG(32, 5, 7);
 64.2130 +	THUMB_STM_REG(64, 6, 7);
 64.2131 +	THUMB_STM_REG(128, 7, 7);
 64.2132 +}
 64.2133 +break;
 64.2134 +#define THUMB_LDM_REG(val, r) \
 64.2135 +	if (opcode & (val)) { \
 64.2136 +		reg[(r)].I = CPUReadMemory(address); \
 64.2137 +		if (offset) \
 64.2138 +			clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); \
 64.2139 +		else \
 64.2140 +			clockTicks += 2 + CPUUpdateTicksAccess32(address); \
 64.2141 +		offset	 = 1; \
 64.2142 +		address += 4; \
 64.2143 +	}
 64.2144 +case 0xc8:
 64.2145 +{
 64.2146 +	// LDM R0!, {Rlist}
 64.2147 +	u32 address = reg[0].I & 0xFFFFFFFC;
 64.2148 +	u32 temp	= reg[0].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.2149 +	int offset	= 0;
 64.2150 +	// load
 64.2151 +	THUMB_LDM_REG(1, 0);
 64.2152 +	THUMB_LDM_REG(2, 1);
 64.2153 +	THUMB_LDM_REG(4, 2);
 64.2154 +	THUMB_LDM_REG(8, 3);
 64.2155 +	THUMB_LDM_REG(16, 4);
 64.2156 +	THUMB_LDM_REG(32, 5);
 64.2157 +	THUMB_LDM_REG(64, 6);
 64.2158 +	THUMB_LDM_REG(128, 7);
 64.2159 +	if (!(opcode & 1))
 64.2160 +		reg[0].I = temp;
 64.2161 +}
 64.2162 +break;
 64.2163 +case 0xc9:
 64.2164 +{
 64.2165 +	// LDM R1!, {Rlist}
 64.2166 +	u32 address = reg[1].I & 0xFFFFFFFC;
 64.2167 +	u32 temp	= reg[1].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.2168 +	int offset	= 0;
 64.2169 +	// load
 64.2170 +	THUMB_LDM_REG(1, 0);
 64.2171 +	THUMB_LDM_REG(2, 1);
 64.2172 +	THUMB_LDM_REG(4, 2);
 64.2173 +	THUMB_LDM_REG(8, 3);
 64.2174 +	THUMB_LDM_REG(16, 4);
 64.2175 +	THUMB_LDM_REG(32, 5);
 64.2176 +	THUMB_LDM_REG(64, 6);
 64.2177 +	THUMB_LDM_REG(128, 7);
 64.2178 +	if (!(opcode & 2))
 64.2179 +		reg[1].I = temp;
 64.2180 +}
 64.2181 +break;
 64.2182 +case 0xca:
 64.2183 +{
 64.2184 +	// LDM R2!, {Rlist}
 64.2185 +	u32 address = reg[2].I & 0xFFFFFFFC;
 64.2186 +	u32 temp	= reg[2].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.2187 +	int offset	= 0;
 64.2188 +	// load
 64.2189 +	THUMB_LDM_REG(1, 0);
 64.2190 +	THUMB_LDM_REG(2, 1);
 64.2191 +	THUMB_LDM_REG(4, 2);
 64.2192 +	THUMB_LDM_REG(8, 3);
 64.2193 +	THUMB_LDM_REG(16, 4);
 64.2194 +	THUMB_LDM_REG(32, 5);
 64.2195 +	THUMB_LDM_REG(64, 6);
 64.2196 +	THUMB_LDM_REG(128, 7);
 64.2197 +	if (!(opcode & 4))
 64.2198 +		reg[2].I = temp;
 64.2199 +}
 64.2200 +break;
 64.2201 +case 0xcb:
 64.2202 +{
 64.2203 +	// LDM R3!, {Rlist}
 64.2204 +	u32 address = reg[3].I & 0xFFFFFFFC;
 64.2205 +	u32 temp	= reg[3].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.2206 +	int offset	= 0;
 64.2207 +	// load
 64.2208 +	THUMB_LDM_REG(1, 0);
 64.2209 +	THUMB_LDM_REG(2, 1);
 64.2210 +	THUMB_LDM_REG(4, 2);
 64.2211 +	THUMB_LDM_REG(8, 3);
 64.2212 +	THUMB_LDM_REG(16, 4);
 64.2213 +	THUMB_LDM_REG(32, 5);
 64.2214 +	THUMB_LDM_REG(64, 6);
 64.2215 +	THUMB_LDM_REG(128, 7);
 64.2216 +	if (!(opcode & 8))
 64.2217 +		reg[3].I = temp;
 64.2218 +}
 64.2219 +break;
 64.2220 +case 0xcc:
 64.2221 +{
 64.2222 +	// LDM R4!, {Rlist}
 64.2223 +	u32 address = reg[4].I & 0xFFFFFFFC;
 64.2224 +	u32 temp	= reg[4].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.2225 +	int offset	= 0;
 64.2226 +	// load
 64.2227 +	THUMB_LDM_REG(1, 0);
 64.2228 +	THUMB_LDM_REG(2, 1);
 64.2229 +	THUMB_LDM_REG(4, 2);
 64.2230 +	THUMB_LDM_REG(8, 3);
 64.2231 +	THUMB_LDM_REG(16, 4);
 64.2232 +	THUMB_LDM_REG(32, 5);
 64.2233 +	THUMB_LDM_REG(64, 6);
 64.2234 +	THUMB_LDM_REG(128, 7);
 64.2235 +	if (!(opcode & 16))
 64.2236 +		reg[4].I = temp;
 64.2237 +}
 64.2238 +break;
 64.2239 +case 0xcd:
 64.2240 +{
 64.2241 +	// LDM R5!, {Rlist}
 64.2242 +	u32 address = reg[5].I & 0xFFFFFFFC;
 64.2243 +	u32 temp	= reg[5].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.2244 +	int offset	= 0;
 64.2245 +	// load
 64.2246 +	THUMB_LDM_REG(1, 0);
 64.2247 +	THUMB_LDM_REG(2, 1);
 64.2248 +	THUMB_LDM_REG(4, 2);
 64.2249 +	THUMB_LDM_REG(8, 3);
 64.2250 +	THUMB_LDM_REG(16, 4);
 64.2251 +	THUMB_LDM_REG(32, 5);
 64.2252 +	THUMB_LDM_REG(64, 6);
 64.2253 +	THUMB_LDM_REG(128, 7);
 64.2254 +	if (!(opcode & 32))
 64.2255 +		reg[5].I = temp;
 64.2256 +}
 64.2257 +break;
 64.2258 +case 0xce:
 64.2259 +{
 64.2260 +	// LDM R6!, {Rlist}
 64.2261 +	u32 address = reg[6].I & 0xFFFFFFFC;
 64.2262 +	u32 temp	= reg[6].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.2263 +	int offset	= 0;
 64.2264 +	// load
 64.2265 +	THUMB_LDM_REG(1, 0);
 64.2266 +	THUMB_LDM_REG(2, 1);
 64.2267 +	THUMB_LDM_REG(4, 2);
 64.2268 +	THUMB_LDM_REG(8, 3);
 64.2269 +	THUMB_LDM_REG(16, 4);
 64.2270 +	THUMB_LDM_REG(32, 5);
 64.2271 +	THUMB_LDM_REG(64, 6);
 64.2272 +	THUMB_LDM_REG(128, 7);
 64.2273 +	if (!(opcode & 64))
 64.2274 +		reg[6].I = temp;
 64.2275 +}
 64.2276 +break;
 64.2277 +case 0xcf:
 64.2278 +{
 64.2279 +	// LDM R7!, {Rlist}
 64.2280 +	u32 address = reg[7].I & 0xFFFFFFFC;
 64.2281 +	u32 temp	= reg[7].I + 4 * cpuBitsSet[opcode & 0xFF];
 64.2282 +	int offset	= 0;
 64.2283 +	// load
 64.2284 +	THUMB_LDM_REG(1, 0);
 64.2285 +	THUMB_LDM_REG(2, 1);
 64.2286 +	THUMB_LDM_REG(4, 2);
 64.2287 +	THUMB_LDM_REG(8, 3);
 64.2288 +	THUMB_LDM_REG(16, 4);
 64.2289 +	THUMB_LDM_REG(32, 5);
 64.2290 +	THUMB_LDM_REG(64, 6);
 64.2291 +	THUMB_LDM_REG(128, 7);
 64.2292 +	if (!(opcode & 128))
 64.2293 +		reg[7].I = temp;
 64.2294 +}
 64.2295 +break;
 64.2296 +case 0xd0:
 64.2297 +	// BEQ offset
 64.2298 +	if (Z_FLAG)
 64.2299 +	{
 64.2300 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2301 +		armNextPC  = reg[15].I;
 64.2302 +		reg[15].I += 2;
 64.2303 +		clockTicks = 3;
 64.2304 +	}
 64.2305 +	break;
 64.2306 +case 0xd1:
 64.2307 +	// BNE offset
 64.2308 +	if (!Z_FLAG)
 64.2309 +	{
 64.2310 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2311 +		armNextPC  = reg[15].I;
 64.2312 +		reg[15].I += 2;
 64.2313 +		clockTicks = 3;
 64.2314 +	}
 64.2315 +	break;
 64.2316 +case 0xd2:
 64.2317 +	// BCS offset
 64.2318 +	if (C_FLAG)
 64.2319 +	{
 64.2320 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2321 +		armNextPC  = reg[15].I;
 64.2322 +		reg[15].I += 2;
 64.2323 +		clockTicks = 3;
 64.2324 +	}
 64.2325 +	break;
 64.2326 +case 0xd3:
 64.2327 +	// BCC offset
 64.2328 +	if (!C_FLAG)
 64.2329 +	{
 64.2330 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2331 +		armNextPC  = reg[15].I;
 64.2332 +		reg[15].I += 2;
 64.2333 +		clockTicks = 3;
 64.2334 +	}
 64.2335 +	break;
 64.2336 +case 0xd4:
 64.2337 +	// BMI offset
 64.2338 +	if (N_FLAG)
 64.2339 +	{
 64.2340 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2341 +		armNextPC  = reg[15].I;
 64.2342 +		reg[15].I += 2;
 64.2343 +		clockTicks = 3;
 64.2344 +	}
 64.2345 +	break;
 64.2346 +case 0xd5:
 64.2347 +	// BPL offset
 64.2348 +	if (!N_FLAG)
 64.2349 +	{
 64.2350 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2351 +		armNextPC  = reg[15].I;
 64.2352 +		reg[15].I += 2;
 64.2353 +		clockTicks = 3;
 64.2354 +	}
 64.2355 +	break;
 64.2356 +case 0xd6:
 64.2357 +	// BVS offset
 64.2358 +	if (V_FLAG)
 64.2359 +	{
 64.2360 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2361 +		armNextPC  = reg[15].I;
 64.2362 +		reg[15].I += 2;
 64.2363 +		clockTicks = 3;
 64.2364 +	}
 64.2365 +	break;
 64.2366 +case 0xd7:
 64.2367 +	// BVC offset
 64.2368 +	if (!V_FLAG)
 64.2369 +	{
 64.2370 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2371 +		armNextPC  = reg[15].I;
 64.2372 +		reg[15].I += 2;
 64.2373 +		clockTicks = 3;
 64.2374 +	}
 64.2375 +	break;
 64.2376 +case 0xd8:
 64.2377 +	// BHI offset
 64.2378 +	if (C_FLAG && !Z_FLAG)
 64.2379 +	{
 64.2380 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2381 +		armNextPC  = reg[15].I;
 64.2382 +		reg[15].I += 2;
 64.2383 +		clockTicks = 3;
 64.2384 +	}
 64.2385 +	break;
 64.2386 +case 0xd9:
 64.2387 +	// BLS offset
 64.2388 +	if (!C_FLAG || Z_FLAG)
 64.2389 +	{
 64.2390 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2391 +		armNextPC  = reg[15].I;
 64.2392 +		reg[15].I += 2;
 64.2393 +		clockTicks = 3;
 64.2394 +	}
 64.2395 +	break;
 64.2396 +case 0xda:
 64.2397 +	// BGE offset
 64.2398 +	if (N_FLAG == V_FLAG)
 64.2399 +	{
 64.2400 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2401 +		armNextPC  = reg[15].I;
 64.2402 +		reg[15].I += 2;
 64.2403 +		clockTicks = 3;
 64.2404 +	}
 64.2405 +	break;
 64.2406 +case 0xdb:
 64.2407 +	// BLT offset
 64.2408 +	if (N_FLAG != V_FLAG)
 64.2409 +	{
 64.2410 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2411 +		armNextPC  = reg[15].I;
 64.2412 +		reg[15].I += 2;
 64.2413 +		clockTicks = 3;
 64.2414 +	}
 64.2415 +	break;
 64.2416 +case 0xdc:
 64.2417 +	// BGT offset
 64.2418 +	if (!Z_FLAG && (N_FLAG == V_FLAG))
 64.2419 +	{
 64.2420 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2421 +		armNextPC  = reg[15].I;
 64.2422 +		reg[15].I += 2;
 64.2423 +		clockTicks = 3;
 64.2424 +	}
 64.2425 +	break;
 64.2426 +case 0xdd:
 64.2427 +	// BLE offset
 64.2428 +	if (Z_FLAG || (N_FLAG != V_FLAG))
 64.2429 +	{
 64.2430 +		reg[15].I += ((s8)(opcode & 0xFF)) << 1;
 64.2431 +		armNextPC  = reg[15].I;
 64.2432 +		reg[15].I += 2;
 64.2433 +		clockTicks = 3;
 64.2434 +	}
 64.2435 +	break;
 64.2436 +case 0xdf:
 64.2437 +	// SWI #comment
 64.2438 +	CPUSoftwareInterrupt(opcode & 0xFF);
 64.2439 +	break;
 64.2440 +case 0xe0:
 64.2441 +case 0xe1:
 64.2442 +case 0xe2:
 64.2443 +case 0xe3:
 64.2444 +case 0xe4:
 64.2445 +case 0xe5:
 64.2446 +case 0xe6:
 64.2447 +case 0xe7:
 64.2448 +{
 64.2449 +	// B offset
 64.2450 +	int offset = (opcode & 0x3FF) << 1;
 64.2451 +	if (opcode & 0x0400)
 64.2452 +		offset |= 0xFFFFF800;
 64.2453 +	reg[15].I += offset;
 64.2454 +	armNextPC  = reg[15].I;
 64.2455 +	reg[15].I += 2;
 64.2456 +}
 64.2457 +break;
 64.2458 +case 0xf0:
 64.2459 +case 0xf1:
 64.2460 +case 0xf2:
 64.2461 +case 0xf3:
 64.2462 +{
 64.2463 +	// BLL #offset
 64.2464 +	int offset = (opcode & 0x7FF);
 64.2465 +	reg[14].I = reg[15].I + (offset << 12);
 64.2466 +}
 64.2467 +break;
 64.2468 +case 0xf4:
 64.2469 +case 0xf5:
 64.2470 +case 0xf6:
 64.2471 +case 0xf7:
 64.2472 +{
 64.2473 +	// BLL #offset
 64.2474 +	int offset = (opcode & 0x7FF);
 64.2475 +	reg[14].I = reg[15].I + ((offset << 12) | 0xFF800000);
 64.2476 +}
 64.2477 +break;
 64.2478 +case 0xf8:
 64.2479 +case 0xf9:
 64.2480 +case 0xfa:
 64.2481 +case 0xfb:
 64.2482 +case 0xfc:
 64.2483 +case 0xfd:
 64.2484 +case 0xfe:
 64.2485 +case 0xff:
 64.2486 +{
 64.2487 +	// BLH #offset
 64.2488 +	int offset = (opcode & 0x7FF);
 64.2489 +	u32 temp   = reg[15].I - 2;
 64.2490 +	reg[15].I  = (reg[14].I + (offset << 1)) & 0xFFFFFFFE;
 64.2491 +	armNextPC  = reg[15].I;
 64.2492 +	reg[15].I += 2;
 64.2493 +	reg[14].I  = temp | 1;
 64.2494 +}
 64.2495 +break;
 64.2496 +#ifdef BKPT_SUPPORT
 64.2497 +case 0xbe:
 64.2498 +	// BKPT #comment
 64.2499 +	extern void (*dbgSignal)(int, int);
 64.2500 +	reg[15].I -= 2;
 64.2501 +	armNextPC -= 2;
 64.2502 +	dbgSignal(5, opcode & 255);
 64.2503 +	return;
 64.2504 +#endif
 64.2505 +case 0xb1:
 64.2506 +case 0xb2:
 64.2507 +case 0xb3:
 64.2508 +case 0xb6:
 64.2509 +case 0xb7:
 64.2510 +case 0xb8:
 64.2511 +case 0xb9:
 64.2512 +case 0xba:
 64.2513 +case 0xbb:
 64.2514 +#ifndef BKPT_SUPPORT
 64.2515 +case 0xbe:
 64.2516 +#endif
 64.2517 +case 0xbf:
 64.2518 +case 0xde:
 64.2519 +default:
 64.2520 +unknown_thumb:
 64.2521 +#ifdef GBA_LOGGING
 64.2522 +	if (systemVerbose & VERBOSE_UNDEFINED)
 64.2523 +		log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC - 2);
 64.2524 +#endif
 64.2525 +	CPUUndefinedException();
 64.2526 +	break;
 64.2527 +}