Mercurial > vba-clojure
changeset 19:5e8e5083da94
brought in common and gba, fixed problems with outdated Makefile.am files in both of these packages
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, ®[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, ®[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(®[R8_FIQ].I, ®[8].I); 32.1694 + CPUSwap(®[R9_FIQ].I, ®[9].I); 32.1695 + CPUSwap(®[R10_FIQ].I, ®[10].I); 32.1696 + CPUSwap(®[R11_FIQ].I, ®[11].I); 32.1697 + CPUSwap(®[R12_FIQ].I, ®[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(®[8].I, ®[R8_FIQ].I); 32.1737 + CPUSwap(®[9].I, ®[R9_FIQ].I); 32.1738 + CPUSwap(®[10].I, ®[R10_FIQ].I); 32.1739 + CPUSwap(®[11].I, ®[R11_FIQ].I); 32.1740 + CPUSwap(®[12].I, ®[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(®[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 ¤tX, 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(®s[0], ®[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], ®s[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 +}