├── COPYING.DOC ├── Makefile ├── build.txt ├── cheats.c ├── cheats.h ├── common.h ├── cpu.c ├── cpu.h ├── cpu_threaded.c ├── font.h ├── game_config.txt ├── gui.c ├── gui.h ├── input.c ├── input.h ├── main.c ├── main.h ├── memory.c ├── memory.h ├── mips_stub.S ├── psp ├── ICON0.png ├── Makefile ├── PIC1.png ├── mips_emit.h └── mips_stub.S ├── readme.txt ├── sound.c ├── sound.h ├── video.c ├── video.h ├── x86 ├── Makefile ├── x86_emit.h └── x86_stub.S ├── zip.c └── zip.h /COPYING.DOC: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Lesser General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # gpSP makefile 2 | # Gilead Kutnick - Exophase 3 | 4 | # Global definitions 5 | 6 | CC = gcc 7 | STRIP = strip 8 | AS = as 9 | 10 | PREFIX = /usr 11 | OBJS = main.o cpu.o memory.o video.o input.o \ 12 | sound.o cpu_threaded.o gui.o x86_stub.o 13 | BIN = gpsp.exe 14 | 15 | # Platform specific definitions 16 | 17 | CFLAGS += 18 | INCLUDES = -I${PREFIX}/include `sdl-config --cflags` 19 | LIBS = -L${PREFIX}/lib `sdl-config --libs` -mconsole 20 | 21 | # Compilation: 22 | 23 | .SUFFIXES: .c .S 24 | 25 | %.o: %.c 26 | ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< 27 | 28 | %.o: %.S 29 | ${AS} -o $@ $< 30 | 31 | all: ${OBJS} 32 | ${CC} ${OBJS} ${LIBS} -o ${BIN} 33 | ${STRIP} ${BIN} 34 | 35 | clean: 36 | rm -f *.o ${BIN} 37 | 38 | -------------------------------------------------------------------------------- /build.txt: -------------------------------------------------------------------------------- 1 | How to build gpSP for PSP: 2 | 3 | The makefile is in the psp directory, simply go there and type make. 4 | make kxploit will build for 1.5 firmware. Be sure to include 5 | game_config.txt and gpsp.cfg in the same directory as EBOOT.PBP, as 6 | well as gba_bios.bin (not included). 7 | 8 | Dependencies as of v0.6: 9 | 10 | SDL 11 | zlib 12 | -------------------------------------------------------------------------------- /cheats.c: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include "common.h" 21 | 22 | cheat_type cheats[MAX_CHEATS]; 23 | u32 num_cheats; 24 | 25 | void decrypt_gsa_code(u32 *address_ptr, u32 *value_ptr, cheat_variant_enum 26 | cheat_variant) 27 | { 28 | u32 i, i2, code_position; 29 | u32 address = *address_ptr; 30 | u32 value = *value_ptr; 31 | u32 r = 0xc6ef3720; 32 | 33 | u32 seeds_v1[4] = 34 | { 35 | 0x09f4fbbd, 0x9681884a, 0x352027e9, 0xf3dee5a7 36 | }; 37 | u32 seeds_v3[4] = 38 | { 39 | 0x7aa9648f, 0x7fae6994, 0xc0efaad5, 0x42712c57 40 | }; 41 | u32 *seeds; 42 | 43 | if(cheat_variant == CHEAT_TYPE_GAMESHARK_V1) 44 | seeds = seeds_v1; 45 | else 46 | seeds = seeds_v3; 47 | 48 | for(i = 0; i < 32; i++) 49 | { 50 | value -= ((address << 4) + seeds[2]) ^ (address + r) ^ 51 | ((address >> 5) + seeds[3]); 52 | address -= ((value << 4) + seeds[0]) ^ (value + r) ^ 53 | ((value >> 5) + seeds[1]); 54 | r -= 0x9e3779b9; 55 | } 56 | 57 | *address_ptr = address; 58 | *value_ptr = value; 59 | } 60 | 61 | void add_cheats(u8 *cheats_filename) 62 | { 63 | FILE *cheats_file; 64 | u8 current_line[256]; 65 | u8 *name_ptr; 66 | u32 *cheat_code_ptr; 67 | u32 address, value; 68 | u32 num_cheat_lines; 69 | u32 cheat_name_length; 70 | cheat_variant_enum current_cheat_variant; 71 | 72 | num_cheats = 0; 73 | 74 | cheats_file = fopen(cheats_filename, "rb"); 75 | 76 | if(cheats_file) 77 | { 78 | while(fgets(current_line, 256, cheats_file)) 79 | { 80 | // Get the header line first 81 | name_ptr = strchr(current_line, ' '); 82 | if(name_ptr) 83 | { 84 | *name_ptr = 0; 85 | name_ptr++; 86 | } 87 | 88 | if(!strcasecmp(current_line, "gameshark_v1") || 89 | !strcasecmp(current_line, "gameshark_v2") || 90 | !strcasecmp(current_line, "PAR_v1") || 91 | !strcasecmp(current_line, "PAR_v2")) 92 | { 93 | current_cheat_variant = CHEAT_TYPE_GAMESHARK_V1; 94 | } 95 | else 96 | 97 | if(!strcasecmp(current_line, "gameshark_v3") || 98 | !strcasecmp(current_line, "PAR_v3")) 99 | { 100 | current_cheat_variant = CHEAT_TYPE_GAMESHARK_V3; 101 | } 102 | else 103 | { 104 | current_cheat_variant = CHEAT_TYPE_INVALID; 105 | } 106 | 107 | if(current_cheat_variant != CHEAT_TYPE_INVALID) 108 | { 109 | strncpy(cheats[num_cheats].cheat_name, name_ptr, CHEAT_NAME_LENGTH - 1); 110 | cheats[num_cheats].cheat_name[CHEAT_NAME_LENGTH - 1] = 0; 111 | cheat_name_length = strlen(cheats[num_cheats].cheat_name); 112 | if(cheat_name_length && 113 | (cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\n') || 114 | (cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\r')) 115 | { 116 | cheats[num_cheats].cheat_name[cheat_name_length - 1] = 0; 117 | cheat_name_length--; 118 | } 119 | 120 | if(cheat_name_length && 121 | cheats[num_cheats].cheat_name[cheat_name_length - 1] == '\r') 122 | { 123 | cheats[num_cheats].cheat_name[cheat_name_length - 1] = 0; 124 | } 125 | 126 | cheats[num_cheats].cheat_variant = current_cheat_variant; 127 | cheat_code_ptr = cheats[num_cheats].cheat_codes; 128 | num_cheat_lines = 0; 129 | 130 | while(fgets(current_line, 256, cheats_file)) 131 | { 132 | if(strlen(current_line) < 3) 133 | break; 134 | 135 | sscanf(current_line, "%08x %08x", &address, &value); 136 | 137 | decrypt_gsa_code(&address, &value, current_cheat_variant); 138 | 139 | cheat_code_ptr[0] = address; 140 | cheat_code_ptr[1] = value; 141 | 142 | cheat_code_ptr += 2; 143 | num_cheat_lines++; 144 | } 145 | 146 | cheats[num_cheats].num_cheat_lines = num_cheat_lines; 147 | 148 | num_cheats++; 149 | } 150 | } 151 | 152 | fclose(cheats_file); 153 | } 154 | } 155 | 156 | void process_cheat_gs1(cheat_type *cheat) 157 | { 158 | u32 cheat_opcode; 159 | u32 *code_ptr = cheat->cheat_codes; 160 | u32 address, value; 161 | u32 i; 162 | 163 | for(i = 0; i < cheat->num_cheat_lines; i++) 164 | { 165 | address = code_ptr[0]; 166 | value = code_ptr[1]; 167 | 168 | code_ptr += 2; 169 | 170 | cheat_opcode = address >> 28; 171 | address &= 0xFFFFFFF; 172 | 173 | switch(cheat_opcode) 174 | { 175 | case 0x0: 176 | write_memory8(address, value); 177 | break; 178 | 179 | case 0x1: 180 | write_memory16(address, value); 181 | break; 182 | 183 | case 0x2: 184 | write_memory32(address, value); 185 | break; 186 | 187 | case 0x3: 188 | { 189 | u32 num_addresses = address & 0xFFFF; 190 | u32 address1, address2; 191 | u32 i2; 192 | 193 | for(i2 = 0; i2 < num_addresses; i2++) 194 | { 195 | address1 = code_ptr[0]; 196 | address2 = code_ptr[1]; 197 | code_ptr += 2; 198 | i++; 199 | 200 | write_memory32(address1, value); 201 | if(address2 != 0) 202 | write_memory32(address2, value); 203 | } 204 | break; 205 | } 206 | 207 | // ROM patch not supported yet 208 | case 0x6: 209 | break; 210 | 211 | // GS button down not supported yet 212 | case 0x8: 213 | break; 214 | 215 | // Reencryption (DEADFACE) not supported yet 216 | case 0xD: 217 | if(read_memory16(address) != (value & 0xFFFF)) 218 | { 219 | code_ptr += 2; 220 | i++; 221 | } 222 | break; 223 | 224 | case 0xE: 225 | if(read_memory16(value & 0xFFFFFFF) != (address & 0xFFFF)) 226 | { 227 | u32 skip = ((address >> 16) & 0x03); 228 | code_ptr += skip * 2; 229 | i += skip; 230 | } 231 | break; 232 | 233 | // Hook routine not supported yet (not important??) 234 | case 0x0F: 235 | break; 236 | } 237 | } 238 | } 239 | 240 | // These are especially incomplete. 241 | 242 | void process_cheat_gs3(cheat_type *cheat) 243 | { 244 | u32 cheat_opcode; 245 | u32 *code_ptr = cheat->cheat_codes; 246 | u32 address, value; 247 | u32 i; 248 | 249 | for(i = 0; i < cheat->num_cheat_lines; i++) 250 | { 251 | address = code_ptr[0]; 252 | value = code_ptr[1]; 253 | 254 | code_ptr += 2; 255 | 256 | cheat_opcode = address >> 28; 257 | address &= 0xFFFFFFF; 258 | 259 | switch(cheat_opcode) 260 | { 261 | case 0x0: 262 | cheat_opcode = address >> 24; 263 | address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); 264 | 265 | switch(cheat_opcode) 266 | { 267 | case 0x0: 268 | { 269 | u32 iterations = value >> 24; 270 | u32 i2; 271 | 272 | value &= 0xFF; 273 | 274 | for(i2 = 0; i2 <= iterations; i2++, address++) 275 | { 276 | write_memory8(address, value); 277 | } 278 | break; 279 | } 280 | 281 | case 0x2: 282 | { 283 | u32 iterations = value >> 16; 284 | u32 i2; 285 | 286 | value &= 0xFFFF; 287 | 288 | for(i2 = 0; i2 <= iterations; i2++, address += 2) 289 | { 290 | write_memory16(address, value); 291 | } 292 | break; 293 | } 294 | 295 | case 0x4: 296 | write_memory32(address, value); 297 | break; 298 | } 299 | break; 300 | 301 | case 0x4: 302 | cheat_opcode = address >> 24; 303 | address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); 304 | 305 | switch(cheat_opcode) 306 | { 307 | case 0x0: 308 | address = read_memory32(address) + (value >> 24); 309 | write_memory8(address, value & 0xFF); 310 | break; 311 | 312 | case 0x2: 313 | address = read_memory32(address) + ((value >> 16) * 2); 314 | write_memory16(address, value & 0xFFFF); 315 | break; 316 | 317 | case 0x4: 318 | address = read_memory32(address); 319 | write_memory32(address, value); 320 | break; 321 | 322 | } 323 | break; 324 | 325 | case 0x8: 326 | cheat_opcode = address >> 24; 327 | address = (address & 0xFFFFF) + ((address << 4) & 0xF000000); 328 | 329 | switch(cheat_opcode) 330 | { 331 | case 0x0: 332 | value = (value & 0xFF) + read_memory8(address); 333 | write_memory8(address, value); 334 | break; 335 | 336 | case 0x2: 337 | value = (value & 0xFFFF) + read_memory16(address); 338 | write_memory16(address, value); 339 | break; 340 | 341 | case 0x4: 342 | value = value + read_memory32(address); 343 | write_memory32(address, value); 344 | break; 345 | } 346 | break; 347 | 348 | case 0xC: 349 | cheat_opcode = address >> 24; 350 | address = (address & 0xFFFFFF) + 0x4000000; 351 | 352 | switch(cheat_opcode) 353 | { 354 | case 0x6: 355 | write_memory16(address, value); 356 | break; 357 | 358 | case 0x7: 359 | write_memory32(address, value); 360 | break; 361 | } 362 | break; 363 | } 364 | } 365 | } 366 | 367 | 368 | void process_cheats() 369 | { 370 | u32 i; 371 | 372 | for(i = 0; i < num_cheats; i++) 373 | { 374 | if(cheats[i].cheat_active) 375 | { 376 | switch(cheats[i].cheat_variant) 377 | { 378 | case CHEAT_TYPE_GAMESHARK_V1: 379 | process_cheat_gs1(cheats + i); 380 | break; 381 | 382 | case CHEAT_TYPE_GAMESHARK_V3: 383 | process_cheat_gs3(cheats + i); 384 | break; 385 | } 386 | } 387 | } 388 | } 389 | -------------------------------------------------------------------------------- /cheats.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #define CHEAT_NAME_LENGTH 17 21 | 22 | typedef enum 23 | { 24 | CHEAT_TYPE_GAMESHARK_V1, 25 | CHEAT_TYPE_GAMESHARK_V3, 26 | CHEAT_TYPE_INVALID 27 | } cheat_variant_enum; 28 | 29 | typedef struct 30 | { 31 | u8 cheat_name[CHEAT_NAME_LENGTH]; 32 | u32 cheat_active; 33 | u32 cheat_codes[256]; 34 | u32 num_cheat_lines; 35 | cheat_variant_enum cheat_variant; 36 | } cheat_type; 37 | 38 | void process_cheats(); 39 | void add_cheats(u8 *cheats_filename); 40 | 41 | #define MAX_CHEATS 8 42 | 43 | extern cheat_type cheats[MAX_CHEATS]; 44 | extern u32 num_cheats; 45 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef COMMON_H 21 | #define COMMON_H 22 | 23 | #define ror(dest, value, shift) \ 24 | dest = ((value) >> shift) | ((value) << (32 - shift)) \ 25 | 26 | // Huge thanks to pollux for the heads up on using native file I/O 27 | // functions on PSP for vastly improved memstick performance. 28 | 29 | #define file_write_mem(filename_tag, buffer, size) \ 30 | { \ 31 | memcpy(write_mem_ptr, buffer, size); \ 32 | write_mem_ptr += size; \ 33 | } \ 34 | 35 | #define file_write_mem_array(filename_tag, array) \ 36 | file_write_mem(filename_tag, array, sizeof(array)) \ 37 | 38 | #define file_write_mem_variable(filename_tag, variable) \ 39 | file_write_mem(filename_tag, &variable, sizeof(variable)) \ 40 | 41 | #ifdef PSP_BUILD 42 | #define fastcall 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #define function_cc 53 | 54 | #define convert_palette(value) \ 55 | value = ((value & 0x7FE0) << 1) | (value & 0x1F) \ 56 | 57 | #define psp_file_open_read PSP_O_RDONLY 58 | #define psp_file_open_write (PSP_O_CREAT | PSP_O_WRONLY | PSP_O_TRUNC) 59 | 60 | #define file_open(filename_tag, filename, mode) \ 61 | s32 filename_tag = sceIoOpen(filename, psp_file_open_##mode, 0777) \ 62 | 63 | #define file_check_valid(filename_tag) \ 64 | (filename_tag >= 0) \ 65 | 66 | #define file_close(filename_tag) \ 67 | sceIoClose(filename_tag) \ 68 | 69 | #define file_read(filename_tag, buffer, size) \ 70 | sceIoRead(filename_tag, buffer, size) \ 71 | 72 | #define file_write(filename_tag, buffer, size) \ 73 | sceIoWrite(filename_tag, buffer, size) \ 74 | 75 | #define file_seek(filename_tag, offset, type) \ 76 | sceIoLseek(filename_tag, offset, PSP_##type) \ 77 | 78 | #define file_tag_type s32 79 | #else 80 | #include 81 | 82 | #define function_cc __attribute__((regparm(2))) 83 | 84 | typedef unsigned char u8; 85 | typedef signed char s8; 86 | typedef unsigned short int u16; 87 | typedef signed short int s16; 88 | typedef unsigned int u32; 89 | typedef signed int s32; 90 | typedef unsigned long long int u64; 91 | typedef signed long long int s64; 92 | 93 | #define convert_palette(value) \ 94 | value = ((value & 0x1F) << 11) | ((value & 0x03E0) << 1) | (value >> 10) \ 95 | 96 | #define stdio_file_open_read "rb" 97 | #define stdio_file_open_write "wb" 98 | 99 | #define file_open(filename_tag, filename, mode) \ 100 | FILE *filename_tag = fopen(filename, stdio_file_open_##mode) \ 101 | 102 | #define file_check_valid(filename_tag) \ 103 | (filename_tag) \ 104 | 105 | #define file_close(filename_tag) \ 106 | fclose(filename_tag) \ 107 | 108 | #define file_read(filename_tag, buffer, size) \ 109 | fread(buffer, size, 1, filename_tag) \ 110 | 111 | #define file_write(filename_tag, buffer, size) \ 112 | fwrite(buffer, size, 1, filename_tag) \ 113 | 114 | #define file_seek(filename_tag, offset, type) \ 115 | fseek(filename_tag, offset, type) \ 116 | 117 | #define file_tag_type FILE * 118 | 119 | #endif 120 | 121 | // These must be variables, not constants. 122 | 123 | #define file_read_variable(filename_tag, variable) \ 124 | file_read(filename_tag, &variable, sizeof(variable)) \ 125 | 126 | #define file_write_variable(filename_tag, variable) \ 127 | file_write(filename_tag, &variable, sizeof(variable)) \ 128 | 129 | // These must be statically declared arrays (ie, global or on the stack, 130 | // not dynamically allocated on the heap) 131 | 132 | #define file_read_array(filename_tag, array) \ 133 | file_read(filename_tag, array, sizeof(array)) \ 134 | 135 | #define file_write_array(filename_tag, array) \ 136 | file_write(filename_tag, array, sizeof(array)) \ 137 | 138 | 139 | 140 | typedef u32 fixed16_16; 141 | 142 | #define float_to_fp16_16(value) \ 143 | (fixed16_16)((value) * 65536.0) \ 144 | 145 | #define fp16_16_to_float(value) \ 146 | (float)((value) / 65536.0) \ 147 | 148 | #define u32_to_fp16_16(value) \ 149 | ((value) << 16) \ 150 | 151 | #define fp16_16_to_u32(value) \ 152 | ((value) >> 16) \ 153 | 154 | #define fp16_16_fractional_part(value) \ 155 | ((value) & 0xFFFF) \ 156 | 157 | #define fixed_div(numerator, denominator, bits) \ 158 | (((numerator * (1 << bits)) + (denominator / 2)) / denominator) \ 159 | 160 | #define address8(base, offset) \ 161 | *((u8 *)((u8 *)base + (offset))) \ 162 | 163 | #define address16(base, offset) \ 164 | *((u16 *)((u8 *)base + (offset))) \ 165 | 166 | #define address32(base, offset) \ 167 | *((u32 *)((u8 *)base + (offset))) \ 168 | 169 | #include 170 | #include 171 | #include 172 | #include 173 | #include 174 | #include 175 | #include "cpu.h" 176 | #include "memory.h" 177 | #include "video.h" 178 | #include "input.h" 179 | #include "sound.h" 180 | #include "main.h" 181 | #include "gui.h" 182 | #include "zip.h" 183 | #include "cheats.h" 184 | 185 | #ifdef PSP_BUILD 186 | #define printf pspDebugScreenPrintf 187 | #endif 188 | 189 | #endif 190 | 191 | -------------------------------------------------------------------------------- /cpu.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef CPU_H 21 | #define CPU_H 22 | 23 | // System mode and user mode are represented as the same here 24 | 25 | typedef enum 26 | { 27 | MODE_USER, 28 | MODE_IRQ, 29 | MODE_FIQ, 30 | MODE_SUPERVISOR, 31 | MODE_ABORT, 32 | MODE_UNDEFINED, 33 | MODE_INVALID 34 | } cpu_mode_type; 35 | 36 | typedef enum 37 | { 38 | CPU_ALERT_NONE, 39 | CPU_ALERT_HALT, 40 | CPU_ALERT_SMC, 41 | CPU_ALERT_IRQ 42 | } cpu_alert_type; 43 | 44 | typedef enum 45 | { 46 | CPU_ACTIVE, 47 | CPU_HALT, 48 | CPU_STOP 49 | } cpu_halt_type; 50 | 51 | typedef enum 52 | { 53 | IRQ_NONE = 0x0000, 54 | IRQ_VBLANK = 0x0001, 55 | IRQ_HBLANK = 0x0002, 56 | IRQ_VCOUNT = 0x0004, 57 | IRQ_TIMER0 = 0x0008, 58 | IRQ_TIMER1 = 0x0010, 59 | IRQ_TIMER2 = 0x0020, 60 | IRQ_TIMER3 = 0x0040, 61 | IRQ_SERIAL = 0x0080, 62 | IRQ_DMA0 = 0x0100, 63 | IRQ_DMA1 = 0x0200, 64 | IRQ_DMA2 = 0x0400, 65 | IRQ_DMA3 = 0x0800, 66 | IRQ_KEYPAD = 0x1000, 67 | IRQ_GAMEPAK = 0x2000, 68 | } irq_type; 69 | 70 | typedef enum 71 | { 72 | REG_SP = 13, 73 | REG_LR = 14, 74 | REG_PC = 15, 75 | REG_N_FLAG = 16, 76 | REG_Z_FLAG = 17, 77 | REG_C_FLAG = 18, 78 | REG_V_FLAG = 19, 79 | REG_CPSR = 20, 80 | REG_SAVE = 21, 81 | REG_SAVE2 = 22, 82 | REG_SAVE3 = 23, 83 | CPU_MODE = 29, 84 | CPU_HALT_STATE = 30, 85 | CHANGED_PC_STATUS = 31 86 | } ext_reg_numbers; 87 | 88 | typedef enum 89 | { 90 | STEP, 91 | PC_BREAKPOINT, 92 | VCOUNT_BREAKPOINT, 93 | Z_BREAKPOINT, 94 | COUNTDOWN_BREAKPOINT, 95 | COUNTDOWN_BREAKPOINT_B, 96 | STEP_RUN, 97 | RUN 98 | } debug_state; 99 | 100 | typedef enum 101 | { 102 | TRANSLATION_REGION_RAM, 103 | TRANSLATION_REGION_ROM, 104 | TRANSLATION_REGION_BIOS 105 | } translation_region_type; 106 | 107 | extern debug_state current_debug_state; 108 | extern u32 instruction_count; 109 | extern u32 last_instruction; 110 | 111 | u32 function_cc step_debug(u32 pc, u32 cycles); 112 | u32 execute_arm(u32 cycles); 113 | void raise_interrupt(irq_type irq_raised); 114 | 115 | u32 function_cc execute_load_u8(u32 address); 116 | u32 function_cc execute_load_u16(u32 address); 117 | u32 function_cc execute_load_u32(u32 address); 118 | u32 function_cc execute_load_s8(u32 address); 119 | u32 function_cc execute_load_s16(u32 address); 120 | void function_cc execute_store_u8(u32 address, u32 source); 121 | void function_cc execute_store_u16(u32 address, u32 source); 122 | void function_cc execute_store_u32(u32 address, u32 source); 123 | void function_cc execute_store_u8_no_smc(u32 address, u32 source); 124 | void function_cc execute_store_u16_no_smc(u32 address, u32 source); 125 | void function_cc execute_store_u32_no_smc(u32 address, u32 source); 126 | u32 function_cc execute_arm_translate(u32 cycles); 127 | void init_translater(); 128 | void cpu_write_mem_savestate(file_tag_type savestate_file); 129 | void cpu_read_savestate(file_tag_type savestate_file); 130 | 131 | u8 function_cc *block_lookup_address_arm(u32 pc); 132 | u8 function_cc *block_lookup_address_thumb(u32 pc); 133 | s32 translate_block_arm(u32 pc, translation_region_type translation_region, 134 | u32 smc_enable); 135 | s32 translate_block_thumb(u32 pc, translation_region_type translation_region, 136 | u32 smc_enable); 137 | 138 | #define ROM_TRANSLATION_CACHE_SIZE (1024 * 512 * 4) 139 | #define RAM_TRANSLATION_CACHE_SIZE (1024 * 384) 140 | #define BIOS_TRANSLATION_CACHE_SIZE (1024 * 128) 141 | #define TRANSLATION_CACHE_LIMIT_THRESHOLD (1024) 142 | 143 | extern u8 rom_translation_cache[ROM_TRANSLATION_CACHE_SIZE]; 144 | extern u8 ram_translation_cache[RAM_TRANSLATION_CACHE_SIZE]; 145 | extern u8 bios_translation_cache[BIOS_TRANSLATION_CACHE_SIZE]; 146 | extern u8 *rom_translation_ptr; 147 | extern u8 *ram_translation_ptr; 148 | extern u8 *bios_translation_ptr; 149 | 150 | #define MAX_TRANSLATION_GATES 8 151 | 152 | extern u32 idle_loop_target_pc; 153 | extern u32 force_pc_update_target; 154 | extern u32 iwram_stack_optimize; 155 | extern u32 allow_smc_ram_u8; 156 | extern u32 allow_smc_ram_u16; 157 | extern u32 allow_smc_ram_u32; 158 | extern u32 direct_map_vram; 159 | extern u32 translation_gate_targets; 160 | extern u32 translation_gate_target_pc[MAX_TRANSLATION_GATES]; 161 | 162 | #define ROM_BRANCH_HASH_SIZE (1024 * 64) 163 | 164 | u32 *rom_branch_hash[ROM_BRANCH_HASH_SIZE]; 165 | 166 | void flush_translation_cache_rom(); 167 | void flush_translation_cache_ram(); 168 | void flush_translation_cache_bios(); 169 | void dump_translation_cache(); 170 | 171 | extern u32 reg_mode[7][7]; 172 | extern u32 spsr[6]; 173 | extern cpu_mode_type cpu_mode; 174 | extern cpu_halt_type cpu_halt; 175 | 176 | extern u32 cpu_modes[32]; 177 | extern const u32 psr_masks[16]; 178 | 179 | extern u32 breakpoint_value; 180 | 181 | extern u32 memory_region_access_read_u8[16]; 182 | extern u32 memory_region_access_read_s8[16]; 183 | extern u32 memory_region_access_read_u16[16]; 184 | extern u32 memory_region_access_read_s16[16]; 185 | extern u32 memory_region_access_read_u32[16]; 186 | extern u32 memory_region_access_write_u8[16]; 187 | extern u32 memory_region_access_write_u16[16]; 188 | extern u32 memory_region_access_write_u32[16]; 189 | extern u32 memory_reads_u8; 190 | extern u32 memory_reads_s8; 191 | extern u32 memory_reads_u16; 192 | extern u32 memory_reads_s16; 193 | extern u32 memory_reads_u32; 194 | extern u32 memory_writes_u8; 195 | extern u32 memory_writes_u16; 196 | extern u32 memory_writes_u32; 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /game_config.txt: -------------------------------------------------------------------------------- 1 | # gpSP game settings database 2 | 3 | # What is this file??? game_config.txt is a database of settings on a 4 | # per-game basis. A couple of the settings are required to make games 5 | # work at all, but most of them are there to improve the performance of 6 | # a game. If a game doesn't work then look through the settings here, 7 | # but keep in mind that this file can not be used to fix a majority of 8 | # games, the ones that don't work because of emulator bugs. For those 9 | # you'll have to wait for a new release and hope it someday gets fixed. 10 | 11 | # This file is meant to be edited in plain text, with a normal editor. 12 | # game_name, game_code, and vender_code can be found in the game's header. 13 | # All three must match for the game to be used, and those setting must be 14 | # in that order. Be sure to use [!] ROMs (verified by GoodGBA) when 15 | # building this list. Right now I don't know how much overlap there is 16 | # between different region games, but usually idle loops don't apply to 17 | # them. If you're using a different region than the one in here you can 18 | # try copying the entry, it might improve it. 19 | 20 | # You can also find the three identifying codes on the second line from 21 | # the top in gpSP's main menu. So anyone should be able to add settings 22 | # to this file if they know what to set, but for some options it'll take 23 | # a lot of special knowledge for them to be of any use. Be sure to see if 24 | # your game is already here, but only if the game_name/game_code/ 25 | # vender_code all match. Only the first full match's settings will be used. 26 | 27 | # Everything here is case sensitive. Don't mess with this file unless 28 | # you know what you're doing - if in doubt sooner ask someone who does. 29 | 30 | # I mainly focus on USA versions, so try those first. And, just because 31 | # a game is on here doesn't mean the game actually works in the current 32 | # version. :/ 33 | 34 | # These are the following options: 35 | 36 | # idle_loop_eliminate_target - tells the recompiler that this branch 37 | # is an idle loop and thus a hardware update should follow it every 38 | # time. This is purely a speed improvement and is not meant to improve 39 | # compatibility - if it does it represents a strange timing problem in 40 | # the game. You can only set one of these for now. Don't use this if 41 | # you don't know what you're doing, it can break the game. Some games 42 | # will run miserably slowly without this option. 43 | 44 | # translation_gate_target - tells the recompiler to put an indirect 45 | # branch (gate) at this point, so artificially stop the current block. 46 | # This is useful if the game performs self modifying code from within 47 | # the same block it is currently executing - this can prevent it from 48 | # causing SMC hits far more times than it should. This is also only a 49 | # speed hack; you can have up to 8 of these. Don't use this if you don't 50 | # know what you're doing, they'll just make the game slower and are 51 | # rarely helpful (good for Camelot games). 52 | 53 | # iwram_stack_optimize - set this to "no" to turn it off. By default this 54 | # is set on. It will turn off an optimization that assumes that the stack 55 | # is always in IWRAM, and thus makes ldm/stm relative to the stack much 56 | # faster. Turning it off will degrade game speed slightly, but is 57 | # necessary for a few games that don't follow this convention. 58 | 59 | # flash_rom_type - set this to 128KB if the game has a 128KB flash ROM, 60 | # otherwise leave it alone or you might break game saving. If you get 61 | # a white screen when the game starts try this option. 62 | 63 | # bios_rom_hack_39 - a hack that allows "roll" to work with the correct BIOS 64 | # in Zelda: Minish Cap. 65 | 66 | # bios_rom_hack_2C - like the above but allows Rayman Advance to work. 67 | 68 | # Castlevania: Circle of the Moon (U) 69 | game_name = DRACULA AGB1 70 | game_code = AAME 71 | vender_code = A4 72 | idle_loop_eliminate_target = 080003d2 73 | 74 | # Megaman Battle Network (U) 75 | game_name = MEGAMAN_BN 76 | game_code = AREE 77 | vender_code = 08 78 | idle_loop_eliminate_target = 08000338 79 | 80 | # Megaman Battle Network 2 (U) 81 | game_name = MEGAMAN_EXE2 82 | game_code = AE2E 83 | vender_code = 08 84 | idle_loop_eliminate_target = 08000358 85 | 86 | # Megaman Battle Network 3 White (U) 87 | game_name = MEGA_EXE3_WH 88 | game_code = A6BE 89 | vender_code = 08 90 | idle_loop_eliminate_target = 0800036c 91 | 92 | # Megaman Battle Network 3 Blue (U) 93 | game_name = MEGA_EXE3_BL 94 | game_code = A3XE 95 | vender_code = 08 96 | idle_loop_eliminate_target = 0800036c 97 | 98 | # Megaman Battle Network 4 Red Sun (U) 99 | game_name = MEGAMANBN4RS 100 | game_code = B4WE 101 | vender_code = 08 102 | idle_loop_eliminate_target = 080003a6 103 | 104 | # Megaman Battle Network 4 Blue Moon (U) 105 | game_name = MEGAMANBN4BM 106 | game_code = B4BE 107 | vender_code = 08 108 | idle_loop_eliminate_target = 080003a6 109 | 110 | # Megaman Battle Network 5 Team Protoman (U) 111 | game_name = MEGAMAN5_TP_ 112 | game_code = BRBE 113 | vender_code = 08 114 | idle_loop_eliminate_target = 080003ca 115 | 116 | # Megaman Battle Network 5 Team Colonel (U) 117 | game_name = MEGAMAN5_TC_ 118 | game_code = BRKE 119 | vender_code = 08 120 | idle_loop_eliminate_target = 080003ca 121 | 122 | # Megaman Battle Network 6 Cybeast Gregar (U) 123 | game_name = MEGAMAN6_GXX 124 | game_code = BR5E 125 | vender_code = 08 126 | idle_loop_eliminate_target = 080003da 127 | 128 | # Megaman Zero (U/E) 129 | game_name = MEGAMAN ZERO 130 | game_code = AZCE 131 | vender_code = 08 132 | idle_loop_eliminate_target = 080004ee 133 | 134 | # Megaman Zero 2 (U) 135 | game_name = MEGAMANZERO2 136 | game_code = A62E 137 | vender_code = 08 138 | idle_loop_eliminate_target = 08000664 139 | 140 | # Megaman Zero 3 (U) 141 | game_name = MEGAMANZERO3 142 | game_code = BZ3E 143 | vender_code = 08 144 | idle_loop_eliminate_target = 08001a08 145 | 146 | # Megaman Zero 4 (U) 147 | game_name = MEGAMANZERO4 148 | game_code = B4ZP 149 | vender_code = 08 150 | idle_loop_eliminate_target = 0800090c 151 | 152 | # Kirby: Nightmare in Dreamland (U) 153 | game_name = AGB KIRBY DX 154 | game_code = A7KE 155 | vender_code = 01 156 | idle_loop_eliminate_target = 08000fae 157 | iwram_stack_optimize = no 158 | 159 | # Hoshi no Kirby: Yume no Izumi Deluxe (J) 160 | game_name = AGB KIRBY DX 161 | game_code = A7KJ 162 | vender_code = 01 163 | idle_loop_eliminate_target = 08000f92 164 | iwram_stack_optimize = no 165 | 166 | # Kirby: Nightmare in Dreamland (E) 167 | game_name = AGB KIRBY DX 168 | game_code = A7KP 169 | vender_code = 01 170 | idle_loop_eliminate_target = 08000fae 171 | iwram_stack_optimize = no 172 | 173 | # Super Mario Advance (U) 174 | game_name = SUPER MARIOA 175 | game_code = AMZE 176 | vender_code = 01 177 | idle_loop_eliminate_target = 08001cf2 178 | 179 | # Super Mario Advance 2 (U) 180 | game_name = SUPER MARIOB 181 | game_code = AA2E 182 | vender_code = 01 183 | idle_loop_eliminate_target = 08000534 184 | 185 | # Super Mario Advance 3 (U) 186 | game_name = SUPER MARIOC 187 | game_code = A3AE 188 | vender_code = 01 189 | idle_loop_eliminate_target = 08002ba4 190 | 191 | # Super Mario Advance 4 (U) 192 | game_name = SUPER MARIOD 193 | game_code = AX4E 194 | vender_code = 01 195 | idle_loop_eliminate_target = 08000732 196 | flash_rom_type = 128KB 197 | 198 | # Super Mario Advance 4 (J) 199 | game_name = SUPER MARIOD 200 | game_code = AX4J 201 | vender_code = 01 202 | idle_loop_eliminate_target = 08000732 203 | flash_rom_type = 128KB 204 | 205 | # Super Mario Advance 4 (E) 206 | game_name = SUPER MARIOD 207 | game_code = AX4P 208 | vender_code = 01 209 | idle_loop_eliminate_target = 08000732 210 | flash_rom_type = 128KB 211 | 212 | # Advance Wars (U) 213 | # This one was really annoying to find, I hope it's okay.. there 214 | # might be a better one somewhere. 215 | game_name = ADVANCEWARS 216 | game_code = AWRE 217 | vender_code = 01 218 | idle_loop_eliminate_target = 0803880a 219 | 220 | # Pokemon Emerald (E/U) 221 | # I don't know why this has an idle loop when Ruby doesn't.... 222 | game_name = POKEMON EMER 223 | game_code = BPEE 224 | vender_code = 01 225 | idle_loop_eliminate_target = 080008ce 226 | flash_rom_type = 128KB 227 | 228 | # Pokemon Emerald (J) 229 | game_name = POKEMON EMER 230 | game_code = BPEJ 231 | vender_code = 01 232 | idle_loop_eliminate_target = 080008ce 233 | flash_rom_type = 128KB 234 | 235 | # Pokemon Emerald (G) 236 | game_name = POKEMON EMER 237 | game_code = BPED 238 | vender_code = 01 239 | idle_loop_eliminate_target = 080008ce 240 | flash_rom_type = 128KB 241 | 242 | # Pokemon Emerald (F) 243 | game_name = POKEMON EMER 244 | game_code = BPEF 245 | vender_code = 01 246 | idle_loop_eliminate_target = 080008ce 247 | flash_rom_type = 128KB 248 | 249 | # Pokemon Emerald (S) 250 | game_name = POKEMON EMER 251 | game_code = BPES 252 | vender_code = 01 253 | idle_loop_eliminate_target = 080008ce 254 | flash_rom_type = 128KB 255 | 256 | # Pokemon Emerald (I) 257 | game_name = POKEMON EMER 258 | game_code = BPEI 259 | vender_code = 01 260 | idle_loop_eliminate_target = 080008ce 261 | flash_rom_type = 128KB 262 | 263 | # Pokemon Sapphire (U) 264 | game_name = POKEMON SAPP 265 | game_code = AXPE 266 | vender_code = 01 267 | flash_rom_type = 128KB 268 | 269 | # Pokemon Sapphire (J) 270 | game_name = POKEMON SAPP 271 | game_code = AXPJ 272 | vender_code = 01 273 | flash_rom_type = 128KB 274 | 275 | # Pokemon Sapphire (G) 276 | game_name = POKEMON SAPP 277 | game_code = AXPD 278 | vender_code = 01 279 | flash_rom_type = 128KB 280 | 281 | # Pokemon Sapphire (I) 282 | game_name = POKEMON SAPP 283 | game_code = AXPI 284 | vender_code = 01 285 | flash_rom_type = 128KB 286 | 287 | # Pokemon Sapphire (S) 288 | game_name = POKEMON SAPP 289 | game_code = AXPS 290 | vender_code = 01 291 | flash_rom_type = 128KB 292 | 293 | # Pokemon Sapphire (F) 294 | game_name = POKEMON SAPP 295 | game_code = AXPF 296 | vender_code = 01 297 | flash_rom_type = 128KB 298 | 299 | # Pokemon Ruby (U) 300 | game_name = POKEMON RUBY 301 | game_code = AXVE 302 | vender_code = 01 303 | flash_rom_type = 128KB 304 | 305 | # Pokemon Ruby (J) 306 | game_name = POKEMON RUBY 307 | game_code = AXVJ 308 | vender_code = 01 309 | flash_rom_type = 128KB 310 | 311 | # Pokemon Ruby (G) 312 | game_name = POKEMON RUBY 313 | game_code = AXVD 314 | vender_code = 01 315 | flash_rom_type = 128KB 316 | 317 | # Pokemon Ruby (I) 318 | game_name = POKEMON RUBY 319 | game_code = AXVI 320 | vender_code = 01 321 | flash_rom_type = 128KB 322 | 323 | # Pokemon Ruby (S) 324 | game_name = POKEMON RUBY 325 | game_code = AXVS 326 | vender_code = 01 327 | flash_rom_type = 128KB 328 | 329 | # Pokemon Ruby (F) 330 | game_name = POKEMON RUBY 331 | game_code = AXVF 332 | vender_code = 01 333 | flash_rom_type = 128KB 334 | 335 | # V-Rally 3 (E) 336 | game_name = V-RALLY 3 337 | game_code = AVRP 338 | vender_code = 70 339 | idle_loop_eliminate_target = 080aa920 340 | 341 | # Mario Vs Donkey Kong (U) 342 | game_name = MARIOVSDK 343 | game_code = BM5E 344 | vender_code = 01 345 | idle_loop_eliminate_target = 08033eec 346 | 347 | # Pokemon: Sapphire (U) 348 | game_name = POKEMON SAPP 349 | game_code = AXPE 350 | vender_code = 01 351 | flash_rom_type = 128KB 352 | 353 | # Pokemon: Sapphire (G) 354 | game_name = POKEMON SAPP 355 | game_code = AXPD 356 | vender_code = 01 357 | flash_rom_type = 128KB 358 | 359 | # Pokemon: Fire Red (J) 360 | game_name = POKEMON FIRE 361 | game_code = BPRJ 362 | vender_code = 01 363 | idle_loop_eliminate_target = 080008b2 364 | # If you have the European version try this instead. 365 | #idle_loop_eliminate_target = 080008c6 366 | flash_rom_type = 128KB 367 | 368 | # Pokemon: Fire Red (E/U) 369 | game_name = POKEMON FIRE 370 | game_code = BPRE 371 | vender_code = 01 372 | idle_loop_eliminate_target = 080008c6 373 | flash_rom_type = 128KB 374 | 375 | # Pokemon: Fire Red (S) 376 | game_name = POKEMON FIRE 377 | game_code = BPRS 378 | vender_code = 01 379 | idle_loop_eliminate_target = 080008c6 380 | flash_rom_type = 128KB 381 | 382 | # Pokemon: Fire Red (G) 383 | game_name = POKEMON FIRE 384 | game_code = BPRD 385 | vender_code = 01 386 | idle_loop_eliminate_target = 080008c6 387 | flash_rom_type = 128KB 388 | 389 | # Pokemon: Fire Red (I) 390 | game_name = POKEMON FIRE 391 | game_code = BPRI 392 | vender_code = 01 393 | idle_loop_eliminate_target = 080008c6 394 | flash_rom_type = 128KB 395 | 396 | # Pokemon: Fire Red (F) 397 | game_name = POKEMON FIRE 398 | game_code = BPRE 399 | vender_code = 01 400 | idle_loop_eliminate_target = 080008c6 401 | flash_rom_type = 128KB 402 | 403 | # Pokemon: Leaf Green (E/U) 404 | # Hey, this one is the same as Fire Red, who'd have thought? :B 405 | game_name = POKEMON LEAF 406 | game_code = BPGE 407 | vender_code = 01 408 | idle_loop_eliminate_target = 080008b2 409 | flash_rom_type = 128KB 410 | 411 | # Pokemon: Leaf Green (S) 412 | game_name = POKEMON LEAF 413 | game_code = BPGS 414 | vender_code = 01 415 | idle_loop_eliminate_target = 080008b6 416 | flash_rom_type = 128KB 417 | 418 | # Pokemon: Leaf Green (G) 419 | game_name = POKEMON LEAF 420 | game_code = BPGD 421 | vender_code = 01 422 | idle_loop_eliminate_target = 080008b6 423 | flash_rom_type = 128KB 424 | 425 | # Pokemon: Leaf Green (I) 426 | game_name = POKEMON LEAF 427 | game_code = BPGI 428 | vender_code = 01 429 | idle_loop_eliminate_target = 080008b6 430 | flash_rom_type = 128KB 431 | 432 | # Pokemon: Leaf Green (F) 433 | game_name = POKEMON LEAF 434 | game_code = BPGF 435 | vender_code = 01 436 | idle_loop_eliminate_target = 080008b6 437 | flash_rom_type = 128KB 438 | 439 | # Pokemon: Fushigi no Dungeon Aka no Kyuujotai (J) 440 | game_name = POKE DUNGEON 441 | game_code = B24J 442 | vender_code = 01 443 | flash_rom_type = 128KB 444 | 445 | # Pokemon: Red Rescue Team (E/U) 446 | game_name = POKE DUNGEON 447 | game_code = B24E 448 | vender_code = 01 449 | flash_rom_type = 128KB 450 | 451 | # F-Zero: Climax (J) 452 | game_name = F-ZEROCLIMAX 453 | game_code = BFTJ 454 | vender_code = 01 455 | flash_rom_type = 128KB 456 | 457 | # Final Fantasy Tactics Advance (U) 458 | game_name = FFTA_USVER. 459 | game_code = AFXE 460 | vender_code = 01 461 | idle_loop_eliminate_target = 0800041e 462 | 463 | # Gradius Galaxies (U) 464 | # Badly coded game with several idle loops. This one works for level 465 | # one at least. 466 | game_name = GRADIUSGALAX 467 | game_code = AGAE 468 | vender_code = A4 469 | idle_loop_eliminate_target = 08013844 470 | 471 | # Rebelstar: Tactical Command (U) 472 | # Badly coded game with several idle loops. I don't think any are 473 | # even close to dominant, and it jumps around too much when things 474 | # matter.... 475 | game_name = REBELSTAR 476 | game_code = BRLE 477 | vender_code = AF 478 | idle_loop_eliminate_target = 0800041a 479 | 480 | # Golden Sun 481 | game_name = Golden_Sun_A 482 | game_code = AGSE 483 | vender_code = 01 484 | translation_gate_target = 03000820 485 | translation_gate_target = 030009ac 486 | translation_gate_target = 03007dac 487 | 488 | # Golden Sun: The Lost Age (U) 489 | # Probably the most horrifically coded GBA game in existence. 490 | game_name = GOLDEN_SUN_B 491 | game_code = AGFE 492 | vender_code = 01 493 | idle_loop_eliminate_target = 08013542 494 | translation_gate_target = 030009ac 495 | #translation_gate_target = 03007d70 496 | 497 | # Nothing to see here :/ 498 | # Mario & Luigi: Superstar Saga (U) 499 | game_name = MARIO&LUIGIU 500 | game_code = A88E 501 | vender_code = 01 502 | 503 | # Mario Party Advance (U) 504 | game_name = MARIOPARTYUS 505 | game_code = B8ME 506 | vender_code = 01 507 | iwram_stack_optimize = no 508 | 509 | # Mario Party Advance (J) 510 | game_name = MARIOPARTYJA 511 | game_code = B8MJ 512 | vender_code = 01 513 | iwram_stack_optimize = no 514 | 515 | # Mario Party Advance (E) 516 | game_name = MARIOPARTYEU 517 | game_code = B8MP 518 | vender_code = 01 519 | iwram_stack_optimize = no 520 | 521 | # Mario Golf: Advance Tour (U) 522 | game_name = MARIOGOLFGBA 523 | game_code = BMGE 524 | vender_code = 01 525 | iwram_stack_optimize = no 526 | idle_loop_eliminate_target = 08014e0a 527 | translation_gate_target = 03000d00 528 | translation_gate_target = 03000a30 529 | 530 | # Mario Golf: GBA Tour (J) 531 | game_name = MARIOGOLFGBA 532 | game_code = BMGJ 533 | vender_code = 01 534 | iwram_stack_optimize = no 535 | idle_loop_eliminate_target = 08014e0a 536 | translation_gate_target = 03000d00 537 | translation_gate_target = 03000a30 538 | 539 | # Mario Golf: Advance Tour (E) 540 | game_name = MARIOGOLFGBA 541 | game_code = BMGP 542 | vender_code = 01 543 | iwram_stack_optimize = no 544 | idle_loop_eliminate_target = 08014e0a 545 | translation_gate_target = 03000d00 546 | translation_gate_target = 03000a30 547 | 548 | # Mario Golf: Advance Tour (S) 549 | game_name = MARIOGOLFGBA 550 | game_code = BMGS 551 | vender_code = 01 552 | iwram_stack_optimize = no 553 | idle_loop_eliminate_target = 08014e0a 554 | translation_gate_target = 03000d00 555 | translation_gate_target = 03000a30 556 | 557 | # Mario Golf: Advance Tour (F) 558 | game_name = MARIOGOLFGBA 559 | game_code = BMGF 560 | vender_code = 01 561 | iwram_stack_optimize = no 562 | idle_loop_eliminate_target = 08014e0a 563 | translation_gate_target = 03000d00 564 | translation_gate_target = 03000a30 565 | 566 | # Mario Golf: Advance Tour (I) 567 | game_name = MARIOGOLFGBA 568 | game_code = BMGI 569 | vender_code = 01 570 | iwram_stack_optimize = no 571 | idle_loop_eliminate_target = 08014e0a 572 | translation_gate_target = 03000d00 573 | translation_gate_target = 03000a30 574 | 575 | # Mario Golf: Advance Tour (G) 576 | game_name = MARIOGOLFGBA 577 | game_code = BMGD 578 | vender_code = 01 579 | iwram_stack_optimize = no 580 | idle_loop_eliminate_target = 08014e0a 581 | translation_gate_target = 03000d00 582 | translation_gate_target = 03000a30 583 | 584 | # Mario Golf: Advance Tour (A) 585 | game_name = MARIOGOLFGBA 586 | game_code = BMGU 587 | vender_code = 01 588 | iwram_stack_optimize = no 589 | idle_loop_eliminate_target = 08014e0a 590 | translation_gate_target = 03000d00 591 | translation_gate_target = 03000a30 592 | 593 | # Tales of Phantasia (U) 594 | game_name = PHANTASIA 595 | game_code = AN8E 596 | vender_code = 01 597 | iwram_stack_optimize = no 598 | 599 | # Tales of Phantasia (J) 600 | game_name = PHANTASIA 601 | game_code = AN8J 602 | vender_code = AF 603 | iwram_stack_optimize = no 604 | 605 | # Tales of Phantasia (E) 606 | game_name = PHANTASIA 607 | game_code = AN8P 608 | vender_code = 01 609 | iwram_stack_optimize = no 610 | 611 | # Advance Wars 2: Black Hole Rising (U) 612 | game_name = ADVANCEWARS2 613 | game_code = AW2E 614 | vender_code = 01 615 | idle_loop_eliminate_target = 08036e2a 616 | 617 | # Bomberman Tournament (U) 618 | game_name = BOMSTORYUSA 619 | game_code = ABSE 620 | vender_code = 52 621 | idle_loop_eliminate_target = 08000526 622 | 623 | # Broken Sword - The Shadow of the Templars (U) 624 | game_name = BROKENSWORD 625 | game_code = ABJE 626 | vender_code = 6L 627 | idle_loop_eliminate_target = 08000a26 628 | 629 | # Defender of The Crown (U) 630 | game_name = DOTC 631 | game_code = ADHE 632 | vender_code = 5N 633 | idle_loop_eliminate_target = 080007ec 634 | 635 | # Drill Dozer (U) 636 | game_name = DRILL DOZER 637 | game_code = V49E 638 | vender_code = 01 639 | idle_loop_eliminate_target = 080006c2 640 | 641 | # F-Zero - Maximum Velocity (U) 642 | game_name = F-ZERO ADVAN 643 | game_code = AFZE 644 | vender_code = 01 645 | idle_loop_eliminate_target = 08000c2e 646 | 647 | # Megaman Zero 2 (U) 648 | game_name = MEGAMANZERO2 649 | game_code = A62E 650 | vender_code = 08 651 | idle_loop_eliminate_target = 08000664 652 | 653 | # Megaman Zero 3 (U) 654 | game_name = MEGAMANZERO3 655 | game_code = BZ3E 656 | vender_code = 08 657 | idle_loop_eliminate_target = 08001a08 658 | 659 | # Megaman Zero 4 (U) 660 | game_name = MEGAMANZERO4 661 | game_code = B4ZE 662 | vender_code = 08 663 | idle_loop_eliminate_target = 0800090c 664 | 665 | # Metal Slug Advance (U) 666 | game_name = METAL SLUG 667 | game_code = BSME 668 | vender_code = B7 669 | idle_loop_eliminate_target = 08000298 670 | 671 | # Magical Quest 2 Starring Mickey & Minnie (U) 672 | game_name = M&M MAGICAL2 673 | game_code = AQME 674 | vender_code = 08 675 | idle_loop_eliminate_target = 0801d340 676 | 677 | # Magical Quest 3 Starring Mickey & Donald (U) 678 | game_name = M&D MAGICAL3 679 | game_code = BMQE 680 | vender_code = 08 681 | idle_loop_eliminate_target = 08016064 682 | 683 | # Pinball Challenge Deluxe (E) 684 | game_name = PINBALL CHAL 685 | game_code = APLP 686 | vender_code = 41 687 | idle_loop_eliminate_target = 080075a6 688 | 689 | # Prince of Persia - The Sands of Time (U) 690 | game_name = PRINCEPERSIA 691 | game_code = BPYE 692 | vender_code = 41 693 | idle_loop_eliminate_target = 0808ff3a 694 | 695 | # Rhythm Tengoku (J) 696 | game_name = RHYTHMTENGOK 697 | game_code = BRIJ 698 | vender_code = 01 699 | idle_loop_eliminate_target = 080013d4 700 | 701 | # River City Ransom EX (U) 702 | game_name = RIVERCRANSOM 703 | game_code = BDTE 704 | vender_code = EB 705 | idle_loop_eliminate_target = 0800065a 706 | 707 | # Super Puzzle Fighter II Turbo (U) 708 | game_name = PUZZLEFIGHT2 709 | game_code = AZ8E 710 | vender_code = 08 711 | idle_loop_eliminate_target = 08002b5e 712 | 713 | # Yu-Gi-Oh! - Dungeon Dice Monsters (U) 714 | game_name = YU-GI-OH DDM 715 | game_code = AYDE 716 | vender_code = A4 717 | idle_loop_eliminate_target = 0802cc6a 718 | 719 | # Yu-Gi-Oh! - The Eternal Duelist Soul (U) 720 | game_name = YU-GI-OH!EDS 721 | game_code = AY5E 722 | vender_code = A4 723 | idle_loop_eliminate_target = 08075d96 724 | 725 | # Yu-Gi-Oh! - The Sacred Cards (U) 726 | game_name = YUGIOH DM7 727 | game_code = AY7E 728 | vender_code = A4 729 | idle_loop_eliminate_target = 08003bd6 730 | 731 | # Yu-Gi-Oh! - World Championship Tournament 2004 (U) 732 | game_name = YWCT2004USA 733 | game_code = BYWE 734 | vender_code = A4 735 | idle_loop_eliminate_target = 080831da 736 | 737 | # Yu-Gi-Oh! - Worldwide Edition - Stairway to the Destined Duel (U) 738 | game_name = YUGIOHWWE 739 | game_code = AYWE 740 | vender_code = A4 741 | idle_loop_eliminate_target = 08089792 742 | 743 | # Wario Ware, Inc. Mega Microgames (U) 744 | game_name = WARIOWAREINC 745 | game_code = AZWE 746 | vender_code = 01 747 | idle_loop_eliminate_target = 08000f66 748 | 749 | # Tom Clancy's Splinter Cell (U) 750 | game_name = SPLINTERCELL 751 | game_code = AO4E 752 | vender_code = 41 753 | idle_loop_eliminate_target = 0807a0c4 754 | 755 | # Tom Clancy's Splinter Cell - Pandora Tomorrow (U) 756 | game_name = TOM CLANCY'S 757 | game_code = BSLE 758 | vender_code = 41 759 | idle_loop_eliminate_target = 0807785e 760 | 761 | # Final Fantasy IV Advance (U) 762 | game_name = FF4ADVANCE 763 | game_code = BZ4E 764 | vender_code = 01 765 | idle_loop_eliminate_target = 0800fabe 766 | # or try 00000430 767 | 768 | # Digimon Battle Spirit (U) 769 | game_name = DIGIMON BTSP 770 | game_code = A8SE 771 | vender_code = B2 772 | idle_loop_eliminate_target = 08011208 773 | 774 | # Digimon Battle Spirit 2 (U) 775 | game_name = DIGIMON BS2 776 | game_code = BDSE 777 | vender_code = B2 778 | idle_loop_eliminate_target = 08010eb0 779 | 780 | # Donald Duck Advance (U) 781 | game_name = DISNEY'S DON 782 | game_code = ADKE 783 | vender_code = 41 784 | idle_loop_eliminate_target = 08002f30 785 | 786 | # Final Fight One (U) 787 | game_name = FINAL FIGHT 788 | game_code = AFFE 789 | vender_code = 08 790 | idle_loop_eliminate_target = 0800b428 791 | 792 | # Megaman Battle Chip Challenge (U) 793 | game_name = BATTLECHIPGP 794 | game_code = A89E 795 | vender_code = 08 796 | idle_loop_eliminate_target = 08000544 797 | 798 | # Monster Force (U) 799 | game_name = MONSTERFORCE 800 | game_code = AM8E 801 | vender_code = 7D 802 | idle_loop_eliminate_target = 08000b00 803 | 804 | # Monster Rancher Advance (U) 805 | game_name = MONSRANCHERA 806 | game_code = AMFE 807 | vender_code = 9B 808 | idle_loop_eliminate_target = 0809f394 809 | 810 | # Monster Rancher Advance 2 (U) 811 | game_name = MONSTERRANC2 812 | game_code = A2QE 813 | vender_code = 9B 814 | idle_loop_eliminate_target = 081c7290 815 | 816 | # The Pinball of The Dead 817 | game_name = PINBALL DEAD 818 | game_code = APDE 819 | vender_code = 78 820 | idle_loop_eliminate_target = 08000300 821 | 822 | # Tringo (U) 823 | game_name = TRINGO 824 | game_code = BTJE 825 | vender_code = 4Z 826 | idle_loop_eliminate_target = 080009a4 827 | 828 | # Virtual Kasparov (U) 829 | game_name = VIRTKASPAROV 830 | game_code = AVKE 831 | vender_code = 60 832 | idle_loop_eliminate_target = 0800093a 833 | 834 | # Advance Wars 2 - Black Hole Rising (E) 835 | game_name = ADVANCEWARS2 836 | game_code = AW2P 837 | vender_code = 01 838 | idle_loop_eliminate_target = 080371be 839 | 840 | # Bookworm (U) 841 | game_name = BOOKWORM 842 | game_code = BKWE 843 | vender_code = 5G 844 | idle_loop_eliminate_target = 0800397c 845 | 846 | # 007 - Nightfire (U) 847 | game_name = NIGHTFIRE 848 | game_code = A7OE 849 | vender_code = 69 850 | idle_loop_eliminate_target = 080031d6 851 | 852 | # Asterix & Obelix XXL (E) 853 | game_name = ASTERIX 854 | game_code = BLXP 855 | vender_code = 70 856 | idle_loop_eliminate_target = 0846d060 857 | 858 | # Was this game released in Japan? What as? 859 | # Ninja Five-0 (U) 860 | game_name = NINJA FIVE 0 861 | game_code = ANXE 862 | vender_code = A4 863 | iwram_stack_optimize = no 864 | 865 | # Ninja Cop (E) 866 | game_name = NINJA COP 867 | game_code = ANXP 868 | vender_code = A4 869 | iwram_stack_optimize = no 870 | 871 | # Sennen Kazoku (J) 872 | game_name = SENNENKAZOKU 873 | game_code = BKAJ 874 | vender_code = 01 875 | flash_rom_type = 128KB 876 | 877 | # Doom 2 (U) 878 | game_name = DOOM II 879 | game_code = A9DE 880 | vender_code = 52 881 | translation_gate_target = 030041c8 882 | translation_gate_target = 03004fa0 883 | 884 | # Bleach Advance (J) 885 | game_name = BLEACH ADV1 886 | game_code = BLEJ 887 | vender_code = 8P 888 | iwram_stack_optimize = no 889 | 890 | # This is needed to make the game work. 891 | # Another World (Homebrew) 892 | game_name = FoxAnWorld 893 | game_code = Home 894 | vender_code = 00 895 | translation_gate_target = 03000f1c 896 | 897 | -------------------------------------------------------------------------------- /gui.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef GUI_H 21 | #define GUI_H 22 | 23 | #define GPSP_CONFIG_FILENAME "gpsp.cfg" 24 | 25 | s32 load_file(u8 **wildcards, u8 *result); 26 | u32 adjust_frameskip(u32 button_id); 27 | s32 load_game_config_file(); 28 | s32 load_config_file(); 29 | s32 save_game_config_file(); 30 | s32 save_config_file(); 31 | u32 menu(u16 *original_screen); 32 | 33 | extern u32 savestate_slot; 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /input.c: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include "common.h" 21 | 22 | // Special thanks to psp298 for the analog->dpad code! 23 | 24 | void trigger_key(u32 key) 25 | { 26 | u32 p1_cnt = io_registers[REG_P1CNT]; 27 | u32 p1; 28 | 29 | if((p1_cnt >> 14) & 0x01) 30 | { 31 | u32 key_intersection = (p1_cnt & key) & 0x3FF; 32 | 33 | if(p1_cnt >> 15) 34 | { 35 | if(key_intersection == (p1_cnt & 0x3FF)) 36 | raise_interrupt(IRQ_KEYPAD); 37 | } 38 | else 39 | { 40 | if(key_intersection) 41 | raise_interrupt(IRQ_KEYPAD); 42 | } 43 | } 44 | } 45 | 46 | u32 key = 0; 47 | 48 | u32 gamepad_config_map[16] = 49 | { 50 | BUTTON_ID_MENU, 51 | BUTTON_ID_A, 52 | BUTTON_ID_B, 53 | BUTTON_ID_START, 54 | BUTTON_ID_L, 55 | BUTTON_ID_R, 56 | BUTTON_ID_DOWN, 57 | BUTTON_ID_LEFT, 58 | BUTTON_ID_UP, 59 | BUTTON_ID_RIGHT, 60 | BUTTON_ID_SELECT, 61 | BUTTON_ID_START, 62 | BUTTON_ID_UP, 63 | BUTTON_ID_DOWN, 64 | BUTTON_ID_LEFT, 65 | BUTTON_ID_RIGHT 66 | }; 67 | 68 | u32 global_enable_analog = 1; 69 | u32 analog_sensitivity_level = 4; 70 | 71 | #ifdef PSP_BUILD 72 | 73 | #define PSP_ALL_BUTTON_MASK 0xFFFF 74 | 75 | u32 last_buttons = 0; 76 | u64 button_repeat_timestamp; 77 | 78 | typedef enum 79 | { 80 | BUTTON_NOT_HELD, 81 | BUTTON_HELD_INITIAL, 82 | BUTTON_HELD_REPEAT 83 | } button_repeat_state_type; 84 | 85 | button_repeat_state_type button_repeat_state = BUTTON_NOT_HELD; 86 | u32 button_repeat = 0; 87 | gui_action_type cursor_repeat = CURSOR_NONE; 88 | 89 | #define BUTTON_REPEAT_START 200000 90 | #define BUTTON_REPEAT_CONTINUE 50000 91 | 92 | gui_action_type get_gui_input() 93 | { 94 | SceCtrlData ctrl_data; 95 | gui_action_type new_button = CURSOR_NONE; 96 | u32 new_buttons; 97 | 98 | delay_us(25000); 99 | 100 | sceCtrlPeekBufferPositive(&ctrl_data, 1); 101 | ctrl_data.Buttons &= PSP_ALL_BUTTON_MASK; 102 | new_buttons = (last_buttons ^ ctrl_data.Buttons) & ctrl_data.Buttons; 103 | last_buttons = ctrl_data.Buttons; 104 | 105 | if(new_buttons & PSP_CTRL_LEFT) 106 | new_button = CURSOR_LEFT; 107 | 108 | if(new_buttons & PSP_CTRL_RIGHT) 109 | new_button = CURSOR_RIGHT; 110 | 111 | if(new_buttons & PSP_CTRL_UP) 112 | new_button = CURSOR_UP; 113 | 114 | if(new_buttons & PSP_CTRL_DOWN) 115 | new_button = CURSOR_DOWN; 116 | 117 | if(new_buttons & PSP_CTRL_START) 118 | new_button = CURSOR_SELECT; 119 | 120 | if(new_buttons & PSP_CTRL_CIRCLE) 121 | new_button = CURSOR_SELECT; 122 | 123 | if(new_buttons & PSP_CTRL_CROSS) 124 | new_button = CURSOR_EXIT; 125 | 126 | if(new_buttons & PSP_CTRL_SQUARE) 127 | new_button = CURSOR_BACK; 128 | 129 | if(new_button != CURSOR_NONE) 130 | { 131 | get_ticks_us(&button_repeat_timestamp); 132 | button_repeat_state = BUTTON_HELD_INITIAL; 133 | button_repeat = new_buttons; 134 | cursor_repeat = new_button; 135 | } 136 | else 137 | { 138 | if(ctrl_data.Buttons & button_repeat) 139 | { 140 | u64 new_ticks; 141 | get_ticks_us(&new_ticks); 142 | 143 | if(button_repeat_state == BUTTON_HELD_INITIAL) 144 | { 145 | if((new_ticks - button_repeat_timestamp) > 146 | BUTTON_REPEAT_START) 147 | { 148 | new_button = cursor_repeat; 149 | button_repeat_timestamp = new_ticks; 150 | button_repeat_state = BUTTON_HELD_REPEAT; 151 | } 152 | } 153 | 154 | if(button_repeat_state == BUTTON_HELD_REPEAT) 155 | { 156 | if((new_ticks - button_repeat_timestamp) > 157 | BUTTON_REPEAT_CONTINUE) 158 | { 159 | new_button = cursor_repeat; 160 | button_repeat_timestamp = new_ticks; 161 | } 162 | } 163 | } 164 | } 165 | 166 | return new_button; 167 | } 168 | 169 | #define PSP_CTRL_ANALOG_UP (1 << 28) 170 | #define PSP_CTRL_ANALOG_DOWN (1 << 29) 171 | #define PSP_CTRL_ANALOG_LEFT (1 << 30) 172 | #define PSP_CTRL_ANALOG_RIGHT (1 << 31) 173 | 174 | u32 button_psp_mask_to_config[] = 175 | { 176 | PSP_CTRL_TRIANGLE, 177 | PSP_CTRL_CIRCLE, 178 | PSP_CTRL_CROSS, 179 | PSP_CTRL_SQUARE, 180 | PSP_CTRL_LTRIGGER, 181 | PSP_CTRL_RTRIGGER, 182 | PSP_CTRL_DOWN, 183 | PSP_CTRL_LEFT, 184 | PSP_CTRL_UP, 185 | PSP_CTRL_RIGHT, 186 | PSP_CTRL_SELECT, 187 | PSP_CTRL_START, 188 | PSP_CTRL_ANALOG_UP, 189 | PSP_CTRL_ANALOG_DOWN, 190 | PSP_CTRL_ANALOG_LEFT, 191 | PSP_CTRL_ANALOG_RIGHT 192 | }; 193 | 194 | u32 button_id_to_gba_mask[] = 195 | { 196 | BUTTON_UP, 197 | BUTTON_DOWN, 198 | BUTTON_LEFT, 199 | BUTTON_RIGHT, 200 | BUTTON_A, 201 | BUTTON_B, 202 | BUTTON_L, 203 | BUTTON_R, 204 | BUTTON_START, 205 | BUTTON_SELECT, 206 | BUTTON_NONE, 207 | BUTTON_NONE, 208 | BUTTON_NONE, 209 | BUTTON_NONE 210 | }; 211 | 212 | gui_action_type get_gui_input_fs_hold(u32 button_id) 213 | { 214 | gui_action_type new_button = get_gui_input(); 215 | if((last_buttons & button_psp_mask_to_config[button_id]) == 0) 216 | return CURSOR_BACK; 217 | 218 | return new_button; 219 | } 220 | 221 | u32 rapidfire_flag = 1; 222 | 223 | u32 update_input() 224 | { 225 | SceCtrlData ctrl_data; 226 | u32 buttons; 227 | u32 non_repeat_buttons; 228 | u32 button_id; 229 | u32 i; 230 | u32 new_key = 0; 231 | u32 analog_sensitivity = 92 - (analog_sensitivity_level * 4); 232 | u32 inv_analog_sensitivity = 256 - analog_sensitivity; 233 | 234 | sceCtrlPeekBufferPositive(&ctrl_data, 1); 235 | 236 | buttons = ctrl_data.Buttons; 237 | 238 | if(global_enable_analog) 239 | { 240 | if(ctrl_data.Lx < analog_sensitivity) 241 | buttons |= PSP_CTRL_ANALOG_LEFT; 242 | 243 | if(ctrl_data.Lx > inv_analog_sensitivity) 244 | buttons |= PSP_CTRL_ANALOG_RIGHT; 245 | 246 | if(ctrl_data.Ly < analog_sensitivity) 247 | buttons |= PSP_CTRL_ANALOG_UP; 248 | 249 | if(ctrl_data.Ly > inv_analog_sensitivity) 250 | buttons |= PSP_CTRL_ANALOG_DOWN; 251 | } 252 | 253 | non_repeat_buttons = (last_buttons ^ buttons) & buttons; 254 | last_buttons = buttons; 255 | 256 | for(i = 0; i < 16; i++) 257 | { 258 | if(non_repeat_buttons & button_psp_mask_to_config[i]) 259 | button_id = gamepad_config_map[i]; 260 | 261 | switch(button_id) 262 | { 263 | case BUTTON_ID_MENU: 264 | { 265 | u16 *screen_copy = copy_screen(); 266 | u32 ret_val = menu(screen_copy); 267 | free(screen_copy); 268 | 269 | return ret_val; 270 | } 271 | 272 | case BUTTON_ID_LOADSTATE: 273 | { 274 | u8 current_savestate_filename[512]; 275 | get_savestate_filename_noshot(savestate_slot, 276 | current_savestate_filename); 277 | load_state(current_savestate_filename); 278 | return 1; 279 | } 280 | 281 | case BUTTON_ID_SAVESTATE: 282 | { 283 | u8 current_savestate_filename[512]; 284 | u16 *current_screen = copy_screen(); 285 | get_savestate_filename_noshot(savestate_slot, 286 | current_savestate_filename); 287 | save_state(current_savestate_filename, current_screen); 288 | free(current_screen); 289 | return 0; 290 | } 291 | 292 | case BUTTON_ID_FASTFORWARD: 293 | synchronize_flag ^= 1; 294 | return 0; 295 | } 296 | 297 | if(buttons & button_psp_mask_to_config[i]) 298 | { 299 | button_id = gamepad_config_map[i]; 300 | if(button_id < BUTTON_ID_MENU) 301 | { 302 | new_key |= button_id_to_gba_mask[button_id]; 303 | } 304 | else 305 | 306 | if((button_id >= BUTTON_ID_RAPIDFIRE_A) && 307 | (button_id <= BUTTON_ID_RAPIDFIRE_L)) 308 | { 309 | rapidfire_flag ^= 1; 310 | if(rapidfire_flag) 311 | { 312 | new_key |= button_id_to_gba_mask[button_id - 313 | BUTTON_ID_RAPIDFIRE_A + BUTTON_ID_A]; 314 | } 315 | else 316 | { 317 | new_key &= ~button_id_to_gba_mask[button_id - 318 | BUTTON_ID_RAPIDFIRE_A + BUTTON_ID_A]; 319 | } 320 | } 321 | } 322 | } 323 | 324 | if((new_key | key) != key) 325 | trigger_key(new_key); 326 | 327 | key = new_key; 328 | 329 | io_registers[REG_P1] = (~key) & 0x3FF; 330 | 331 | return 0; 332 | } 333 | 334 | void init_input() 335 | { 336 | sceCtrlSetSamplingCycle(0); 337 | sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG); 338 | } 339 | 340 | #else 341 | 342 | u32 key_map(SDLKey key_sym) 343 | { 344 | switch(key_sym) 345 | { 346 | case SDLK_LSHIFT: 347 | return BUTTON_L; 348 | 349 | case SDLK_x: 350 | return BUTTON_R; 351 | 352 | case SDLK_DOWN: 353 | return BUTTON_DOWN; 354 | 355 | case SDLK_UP: 356 | return BUTTON_UP; 357 | 358 | case SDLK_LEFT: 359 | return BUTTON_LEFT; 360 | 361 | case SDLK_RIGHT: 362 | return BUTTON_RIGHT; 363 | 364 | case SDLK_RETURN: 365 | return BUTTON_START; 366 | 367 | case SDLK_RSHIFT: 368 | return BUTTON_SELECT; 369 | 370 | case SDLK_LCTRL: 371 | return BUTTON_B; 372 | 373 | case SDLK_LALT: 374 | return BUTTON_A; 375 | 376 | default: 377 | return BUTTON_NONE; 378 | } 379 | } 380 | 381 | u32 joy_map(u32 button) 382 | { 383 | switch(button) 384 | { 385 | case 4: 386 | return BUTTON_L; 387 | 388 | case 5: 389 | return BUTTON_R; 390 | 391 | case 9: 392 | return BUTTON_START; 393 | 394 | case 8: 395 | return BUTTON_SELECT; 396 | 397 | case 0: 398 | return BUTTON_B; 399 | 400 | case 1: 401 | return BUTTON_A; 402 | 403 | default: 404 | return BUTTON_NONE; 405 | } 406 | } 407 | 408 | 409 | u32 joy_hat_map(u32 value) 410 | { 411 | u32 result = BUTTON_NONE; 412 | 413 | if(value & SDL_HAT_UP) 414 | result |= BUTTON_UP; 415 | 416 | if(value & SDL_HAT_RIGHT) 417 | result |= BUTTON_RIGHT; 418 | 419 | if(value & SDL_HAT_DOWN) 420 | result |= BUTTON_DOWN; 421 | 422 | if(value & SDL_HAT_LEFT) 423 | result |= BUTTON_LEFT; 424 | 425 | return result; 426 | } 427 | 428 | gui_action_type get_gui_input() 429 | { 430 | SDL_Event event; 431 | gui_action_type gui_action = CURSOR_NONE; 432 | 433 | delay_us(30000); 434 | 435 | while(SDL_PollEvent(&event)) 436 | { 437 | switch(event.type) 438 | { 439 | case SDL_QUIT: 440 | quit(); 441 | 442 | case SDL_KEYDOWN: 443 | { 444 | switch(event.key.keysym.sym) 445 | { 446 | case SDLK_ESCAPE: 447 | gui_action = CURSOR_EXIT; 448 | break; 449 | 450 | case SDLK_DOWN: 451 | gui_action = CURSOR_DOWN; 452 | break; 453 | 454 | case SDLK_UP: 455 | gui_action = CURSOR_UP; 456 | break; 457 | 458 | case SDLK_LEFT: 459 | gui_action = CURSOR_LEFT; 460 | break; 461 | 462 | case SDLK_RIGHT: 463 | gui_action = CURSOR_RIGHT; 464 | break; 465 | 466 | case SDLK_RETURN: 467 | gui_action = CURSOR_SELECT; 468 | break; 469 | 470 | case SDLK_BACKSPACE: 471 | gui_action = CURSOR_BACK; 472 | break; 473 | } 474 | break; 475 | } 476 | } 477 | } 478 | 479 | return gui_action; 480 | } 481 | 482 | // FIXME: Not implemented properly for x86 version. 483 | 484 | gui_action_type get_gui_input_fs_hold(u32 button_id) 485 | { 486 | return get_gui_input(); 487 | } 488 | 489 | u32 update_input() 490 | { 491 | SDL_Event event; 492 | 493 | while(SDL_PollEvent(&event)) 494 | { 495 | switch(event.type) 496 | { 497 | case SDL_QUIT: 498 | quit(); 499 | 500 | case SDL_KEYDOWN: 501 | { 502 | if(event.key.keysym.sym == SDLK_ESCAPE) 503 | { 504 | quit(); 505 | } 506 | 507 | if(event.key.keysym.sym == SDLK_BACKSPACE) 508 | { 509 | u16 *screen_copy = copy_screen(); 510 | u32 ret_val = menu(screen_copy); 511 | free(screen_copy); 512 | 513 | return ret_val; 514 | // return adjust_frameskip(0); 515 | } 516 | else 517 | 518 | if(event.key.keysym.sym == SDLK_F1) 519 | { 520 | current_debug_state = STEP; 521 | } 522 | else 523 | 524 | if(event.key.keysym.sym == SDLK_F2) 525 | { 526 | FILE *fp = fopen("palette_ram.bin", "wb"); 527 | printf("writing palette RAM\n"); 528 | fwrite(palette_ram, 1024, 1, fp); 529 | fclose(fp); 530 | printf("writing palette VRAM\n"); 531 | fp = fopen("vram.bin", "wb"); 532 | fwrite(vram, 1024 * 96, 1, fp); 533 | fclose(fp); 534 | printf("writing palette OAM RAM\n"); 535 | fp = fopen("oam_ram.bin", "wb"); 536 | fwrite(oam_ram, 1024, 1, fp); 537 | fclose(fp); 538 | printf("writing palette I/O registers\n"); 539 | fp = fopen("io_registers.bin", "wb"); 540 | fwrite(io_registers, 1024, 1, fp); 541 | fclose(fp); 542 | } 543 | else 544 | 545 | if(event.key.keysym.sym == SDLK_F3) 546 | { 547 | dump_translation_cache(); 548 | } 549 | else 550 | 551 | if(event.key.keysym.sym == SDLK_F5) 552 | { 553 | u8 current_savestate_filename[512]; 554 | u16 *current_screen = copy_screen(); 555 | get_savestate_filename_noshot(savestate_slot, 556 | current_savestate_filename); 557 | save_state(current_savestate_filename, current_screen); 558 | free(current_screen); 559 | } 560 | else 561 | 562 | if(event.key.keysym.sym == SDLK_F7) 563 | { 564 | u8 current_savestate_filename[512]; 565 | get_savestate_filename_noshot(savestate_slot, 566 | current_savestate_filename); 567 | load_state(current_savestate_filename); 568 | current_debug_state = STEP; 569 | return 1; 570 | } 571 | else 572 | 573 | if(event.key.keysym.sym == SDLK_BACKQUOTE) 574 | { 575 | synchronize_flag ^= 1; 576 | } 577 | else 578 | { 579 | key |= key_map(event.key.keysym.sym); 580 | trigger_key(key); 581 | } 582 | 583 | break; 584 | } 585 | 586 | case SDL_KEYUP: 587 | { 588 | key &= ~(key_map(event.key.keysym.sym)); 589 | break; 590 | } 591 | 592 | case SDL_JOYAXISMOTION: 593 | { 594 | /* key = (key & 0xFF0F) | joy_axis_map(event.jaxis.value, 595 | event.jaxis.axis); 596 | trigger_key(key); */ 597 | break; 598 | } 599 | 600 | case SDL_JOYHATMOTION: 601 | { 602 | key = (key & 0xFF0F) | joy_hat_map(event.jhat.value); 603 | trigger_key(key); 604 | break; 605 | } 606 | 607 | case SDL_JOYBUTTONDOWN: 608 | { 609 | key |= joy_map(event.jbutton.button); 610 | trigger_key(key); 611 | break; 612 | } 613 | 614 | case SDL_JOYBUTTONUP: 615 | { 616 | key &= ~(joy_map(event.jbutton.button)); 617 | break; 618 | } 619 | } 620 | } 621 | 622 | io_registers[REG_P1] = (~key) & 0x3FF; 623 | 624 | return 0; 625 | } 626 | 627 | void init_input() 628 | { 629 | u32 joystick_count = SDL_NumJoysticks(); 630 | 631 | if(joystick_count > 0) 632 | { 633 | SDL_JoystickOpen(0); 634 | SDL_JoystickEventState(SDL_ENABLE); 635 | } 636 | } 637 | 638 | #endif 639 | 640 | #define input_savestate_builder(type) \ 641 | void input_##type##_savestate(file_tag_type savestate_file) \ 642 | { \ 643 | file_##type##_variable(savestate_file, key); \ 644 | } \ 645 | 646 | input_savestate_builder(read); 647 | input_savestate_builder(write_mem); 648 | 649 | -------------------------------------------------------------------------------- /input.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef INPUT_H 21 | #define INPUT_H 22 | 23 | typedef enum 24 | { 25 | BUTTON_L = 0x200, 26 | BUTTON_R = 0x100, 27 | BUTTON_DOWN = 0x80, 28 | BUTTON_UP = 0x40, 29 | BUTTON_LEFT = 0x20, 30 | BUTTON_RIGHT = 0x10, 31 | BUTTON_START = 0x08, 32 | BUTTON_SELECT = 0x04, 33 | BUTTON_B = 0x02, 34 | BUTTON_A = 0x01, 35 | BUTTON_NONE = 0x00 36 | } input_buttons_type; 37 | 38 | typedef enum 39 | { 40 | BUTTON_ID_UP, 41 | BUTTON_ID_DOWN, 42 | BUTTON_ID_LEFT, 43 | BUTTON_ID_RIGHT, 44 | BUTTON_ID_A, 45 | BUTTON_ID_B, 46 | BUTTON_ID_L, 47 | BUTTON_ID_R, 48 | BUTTON_ID_START, 49 | BUTTON_ID_SELECT, 50 | BUTTON_ID_MENU, 51 | BUTTON_ID_FASTFORWARD, 52 | BUTTON_ID_LOADSTATE, 53 | BUTTON_ID_SAVESTATE, 54 | BUTTON_ID_RAPIDFIRE_A, 55 | BUTTON_ID_RAPIDFIRE_B, 56 | BUTTON_ID_RAPIDFIRE_L, 57 | BUTTON_ID_RAPIDFIRE_R, 58 | BUTTON_ID_NONE 59 | } input_buttons_id_type; 60 | 61 | typedef enum 62 | { 63 | CURSOR_UP, 64 | CURSOR_DOWN, 65 | CURSOR_LEFT, 66 | CURSOR_RIGHT, 67 | CURSOR_SELECT, 68 | CURSOR_BACK, 69 | CURSOR_EXIT, 70 | CURSOR_NONE 71 | } gui_action_type; 72 | 73 | void init_input(); 74 | u32 update_input(); 75 | gui_action_type get_gui_input(); 76 | gui_action_type get_gui_input_fs_hold(u32 button_id); 77 | void input_write_mem_savestate(file_tag_type savestate_file); 78 | void input_read_savestate(file_tag_type savestate_file); 79 | 80 | extern u32 gamepad_config_map[16]; 81 | extern u32 global_enable_analog; 82 | extern u32 analog_sensitivity_level; 83 | 84 | #endif 85 | 86 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include "common.h" 21 | 22 | #ifdef PSP_BUILD 23 | 24 | void vblank_interrupt_handler(u32 sub, u32 *parg); 25 | 26 | PSP_HEAP_SIZE_MAX(); 27 | 28 | #endif 29 | 30 | timer_type timer[4]; 31 | 32 | //debug_state current_debug_state = COUNTDOWN_BREAKPOINT; 33 | //debug_state current_debug_state = PC_BREAKPOINT; 34 | u32 breakpoint_value = 0x7c5000; 35 | debug_state current_debug_state = RUN; 36 | //u32 breakpoint_value = 0; 37 | 38 | frameskip_type current_frameskip_type = auto_frameskip; 39 | u32 frameskip_value = 4; 40 | u32 random_skip = 0; 41 | u32 global_cycles_per_instruction = 3; 42 | 43 | u32 skip_next_frame = 0; 44 | 45 | u32 frameskip_counter = 0; 46 | 47 | u32 cpu_ticks = 0; 48 | u32 frame_ticks = 0; 49 | 50 | u32 execute_cycles = 960; 51 | s32 video_count = 960; 52 | u32 ticks; 53 | 54 | u32 arm_frame = 0; 55 | u32 thumb_frame = 0; 56 | u32 last_frame = 0; 57 | 58 | u32 cycle_memory_access = 0; 59 | u32 cycle_pc_relative_access = 0; 60 | u32 cycle_sp_relative_access = 0; 61 | u32 cycle_block_memory_access = 0; 62 | u32 cycle_block_memory_sp_access = 0; 63 | u32 cycle_block_memory_words = 0; 64 | u32 cycle_dma16_words = 0; 65 | u32 cycle_dma32_words = 0; 66 | u32 flush_ram_count = 0; 67 | u32 gbc_update_count = 0; 68 | u32 oam_update_count = 0; 69 | 70 | u32 synchronize_flag = 1; 71 | 72 | u32 update_backup_flag = 1; 73 | u32 clock_speed = 333; 74 | volatile u8 main_path[512]; 75 | 76 | #define check_count(count_var) \ 77 | if(count_var < execute_cycles) \ 78 | execute_cycles = count_var; \ 79 | 80 | #define check_timer(timer_number) \ 81 | if(timer[timer_number].status == TIMER_PRESCALE) \ 82 | check_count(timer[timer_number].count); \ 83 | 84 | #define update_timer(timer_number) \ 85 | if(timer[timer_number].status != TIMER_INACTIVE) \ 86 | { \ 87 | if(timer[timer_number].status != TIMER_CASCADE) \ 88 | { \ 89 | timer[timer_number].count -= execute_cycles; \ 90 | io_registers[REG_TM##timer_number##D] = \ 91 | -(timer[timer_number].count >> timer[timer_number].prescale); \ 92 | } \ 93 | \ 94 | if(timer[timer_number].count <= 0) \ 95 | { \ 96 | if(timer[timer_number].irq == TIMER_TRIGGER_IRQ) \ 97 | irq_raised |= IRQ_TIMER##timer_number; \ 98 | \ 99 | if((timer_number != 3) && \ 100 | (timer[timer_number + 1].status == TIMER_CASCADE)) \ 101 | { \ 102 | timer[timer_number + 1].count--; \ 103 | io_registers[REG_TM0D + (timer_number + 1) * 2] = \ 104 | -(timer[timer_number + 1].count); \ 105 | } \ 106 | \ 107 | if(timer_number < 2) \ 108 | { \ 109 | if(timer[timer_number].direct_sound_channels & 0x01) \ 110 | sound_timer(timer[timer_number].frequency_step, 0); \ 111 | \ 112 | if(timer[timer_number].direct_sound_channels & 0x02) \ 113 | sound_timer(timer[timer_number].frequency_step, 1); \ 114 | } \ 115 | \ 116 | timer[timer_number].count += \ 117 | (timer[timer_number].reload << timer[timer_number].prescale); \ 118 | } \ 119 | } \ 120 | 121 | u8 *file_ext[] = { ".gba", ".bin", ".zip", NULL }; 122 | 123 | void init_main() 124 | { 125 | u32 i; 126 | 127 | skip_next_frame = 0; 128 | 129 | for(i = 0; i < 4; i++) 130 | { 131 | dma[i].start_type = DMA_INACTIVE; 132 | dma[i].direct_sound_channel = DMA_NO_DIRECT_SOUND; 133 | timer[i].status = TIMER_INACTIVE; 134 | timer[i].reload = 0x10000; 135 | timer[i].stop_cpu_ticks = 0; 136 | } 137 | 138 | timer[0].direct_sound_channels = TIMER_DS_CHANNEL_BOTH; 139 | timer[1].direct_sound_channels = TIMER_DS_CHANNEL_NONE; 140 | 141 | cpu_ticks = 0; 142 | frame_ticks = 0; 143 | 144 | execute_cycles = 960; 145 | video_count = 960; 146 | 147 | flush_translation_cache_rom(); 148 | flush_translation_cache_ram(); 149 | flush_translation_cache_bios(); 150 | } 151 | 152 | int main(int argc, char *argv[]) 153 | { 154 | u32 i; 155 | u32 vcount = 0; 156 | u32 ticks; 157 | u32 dispstat; 158 | u8 load_filename[512]; 159 | 160 | #ifdef PSP_BUILD 161 | sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, 162 | vblank_interrupt_handler, NULL); 163 | sceKernelEnableSubIntr(PSP_VBLANK_INT, 0); 164 | #else 165 | freopen("CON", "wb", stdout); 166 | #endif 167 | 168 | init_gamepak_buffer(); 169 | 170 | // Copy the directory path of the executable into main_path 171 | getcwd(main_path, 512); 172 | load_config_file(); 173 | 174 | gamepak_filename[0] = 0; 175 | 176 | if(load_bios("gba_bios.bin") == -1) 177 | { 178 | #ifdef PSP_BUILD 179 | gui_action_type gui_action = CURSOR_NONE; 180 | 181 | printf("Sorry, but gpSP requires a Gameboy Advance BIOS image to run\n"); 182 | printf("correctly. Make sure to get an authentic one (search the web,\n"); 183 | printf("beg other people if you want, but don't hold me accountable\n"); 184 | printf("if you get hated or banned for it), it'll be exactly 16384\n"); 185 | printf("bytes large and should have the following md5sum value:\n\n"); 186 | printf("a860e8c0b6d573d191e4ec7db1b1e4f6\n\n"); 187 | printf("Other BIOS files might work either partially completely, I\n"); 188 | printf("really don't know.\n\n"); 189 | printf("When you do get it name it gba_bios.bin and put it in the\n"); 190 | printf("same directory as this EBOOT.\n\n"); 191 | printf("Good luck. Press any button to exit.\n"); 192 | 193 | while(gui_action == CURSOR_NONE) 194 | { 195 | gui_action = get_gui_input(); 196 | delay_us(15000); 197 | } 198 | 199 | quit(); 200 | #endif 201 | } 202 | 203 | #ifdef PSP_BUILD 204 | delay_us(2500000); 205 | #endif 206 | 207 | init_main(); 208 | init_sound(); 209 | 210 | init_video(); 211 | init_input(); 212 | 213 | video_resolution_large(); 214 | 215 | if(argc > 1) 216 | { 217 | if(load_gamepak(argv[1]) == -1) 218 | { 219 | printf("Failed to load gamepak %s, exiting.\n", load_filename); 220 | exit(-1); 221 | } 222 | 223 | set_gba_resolution(screen_scale); 224 | video_resolution_small(); 225 | 226 | init_cpu(); 227 | init_memory(); 228 | } 229 | else 230 | { 231 | if(load_file(file_ext, load_filename) == -1) 232 | { 233 | menu(copy_screen()); 234 | } 235 | else 236 | { 237 | if(load_gamepak(load_filename) == -1) 238 | { 239 | printf("Failed to load gamepak %s, exiting.\n", load_filename); 240 | delay_us(5000000); 241 | exit(-1); 242 | } 243 | 244 | set_gba_resolution(screen_scale); 245 | video_resolution_small(); 246 | 247 | init_cpu(); 248 | init_memory(); 249 | } 250 | } 251 | 252 | last_frame = 0; 253 | 254 | // We'll never actually return from here. 255 | 256 | #ifdef PSP_BUILD 257 | execute_arm_translate(execute_cycles); 258 | #else 259 | execute_arm_translate(execute_cycles); 260 | // execute_arm(execute_cycles); 261 | #endif 262 | return 0; 263 | } 264 | 265 | void print_memory_stats(u32 *counter, u32 *region_stats, u8 *stats_str) 266 | { 267 | u32 other_region_counter = region_stats[0x1] + region_stats[0xE] + region_stats[0xF]; 268 | u32 rom_region_counter = region_stats[0x8] + region_stats[0x9] + region_stats[0xA] + 269 | region_stats[0xB] + region_stats[0xC] + region_stats[0xD]; 270 | u32 _counter = *counter; 271 | 272 | printf("memory access stats: %s (out of %d)\n", stats_str, _counter); 273 | printf("bios: %f%%\tiwram: %f%%\tewram: %f%%\tvram: %f\n", 274 | region_stats[0x0] * 100.0 / _counter, region_stats[0x3] * 100.0 / _counter, 275 | region_stats[0x2] * 100.0 / _counter, region_stats[0x6] * 100.0 / _counter); 276 | 277 | printf("oam: %f%%\tpalette: %f%%\trom: %f%%\tother: %f%%\n", 278 | region_stats[0x7] * 100.0 / _counter, region_stats[0x5] * 100.0 / _counter, 279 | rom_region_counter * 100.0 / _counter, other_region_counter * 100.0 / _counter); 280 | 281 | *counter = 0; 282 | memset(region_stats, 0, sizeof(u32) * 16); 283 | } 284 | 285 | u32 update_gba() 286 | { 287 | irq_type irq_raised = IRQ_NONE; 288 | cpu_ticks += execute_cycles; 289 | 290 | if(gbc_sound_update) 291 | { 292 | gbc_update_count++; 293 | update_gbc_sound(cpu_ticks); 294 | gbc_sound_update = 0; 295 | } 296 | 297 | update_timer(0); 298 | update_timer(1); 299 | update_timer(2); 300 | update_timer(3); 301 | 302 | video_count -= execute_cycles; 303 | 304 | if(video_count <= 0) 305 | { 306 | u32 vcount = io_registers[REG_VCOUNT]; 307 | u32 dispstat = io_registers[REG_DISPSTAT]; 308 | 309 | if((dispstat & 0x02) == 0) 310 | { 311 | // Transition from hrefresh to hblank 312 | video_count += 272; 313 | dispstat |= 0x02; 314 | 315 | if((dispstat & 0x01) == 0) 316 | { 317 | u32 i; 318 | if(oam_update) 319 | oam_update_count++; 320 | 321 | update_scanline(); 322 | 323 | 324 | // If in visible area also fire HDMA 325 | for(i = 0; i < 4; i++) 326 | { 327 | if(dma[i].start_type == DMA_START_HBLANK) 328 | dma_transfer(dma + i); 329 | } 330 | } 331 | 332 | if(dispstat & 0x10) 333 | irq_raised |= IRQ_HBLANK; 334 | } 335 | else 336 | { 337 | // Transition from hblank to next line 338 | video_count += 960; 339 | dispstat &= ~0x02; 340 | 341 | vcount++; 342 | 343 | if(vcount == 160) 344 | { 345 | // Transition from vrefresh to vblank 346 | u32 i; 347 | 348 | dispstat |= 0x01; 349 | if(dispstat & 0x8) 350 | { 351 | irq_raised |= IRQ_VBLANK; 352 | } 353 | 354 | affine_reference_x[0] = 355 | (s32)(address32(io_registers, 0x28) << 4) >> 4; 356 | affine_reference_y[0] = 357 | (s32)(address32(io_registers, 0x2C) << 4) >> 4; 358 | affine_reference_x[1] = 359 | (s32)(address32(io_registers, 0x38) << 4) >> 4; 360 | affine_reference_y[1] = 361 | (s32)(address32(io_registers, 0x3C) << 4) >> 4; 362 | 363 | for(i = 0; i < 4; i++) 364 | { 365 | if(dma[i].start_type == DMA_START_VBLANK) 366 | dma_transfer(dma + i); 367 | } 368 | } 369 | else 370 | 371 | if(vcount == 228) 372 | { 373 | // Transition from vblank to next screen 374 | dispstat &= ~0x01; 375 | frame_ticks++; 376 | 377 | #ifndef PSP_BUILD 378 | /* printf("frame update (%x), %d instructions total, %d RAM flushes\n", 379 | reg[REG_PC], instruction_count - last_frame, flush_ram_count); 380 | last_frame = instruction_count; 381 | print_memory_stats(&memory_reads_u8, memory_region_access_read_u8, 382 | "unsigned 8bit read"); 383 | print_memory_stats(&memory_reads_s8, memory_region_access_read_s8, 384 | "signed 8bit read"); 385 | print_memory_stats(&memory_reads_u16, memory_region_access_read_u16, 386 | "unsigned 16bit read"); 387 | print_memory_stats(&memory_reads_s16, memory_region_access_read_s16, 388 | "signed 16bit read"); 389 | print_memory_stats(&memory_reads_u32, memory_region_access_read_u32, 390 | "32bit read"); 391 | print_memory_stats(&memory_writes_u8, memory_region_access_write_u8, 392 | "8bit write"); 393 | print_memory_stats(&memory_writes_u16, memory_region_access_write_u16, 394 | "16bit write"); 395 | print_memory_stats(&memory_writes_u32, memory_region_access_write_u32, 396 | "32bit write"); 397 | printf("%d gbc audio updates\n", gbc_update_count); 398 | printf("%d oam updates\n", oam_update_count); */ 399 | gbc_update_count = 0; 400 | oam_update_count = 0; 401 | flush_ram_count = 0; 402 | #endif 403 | 404 | if(update_input()) 405 | return execute_cycles; 406 | 407 | update_gbc_sound(cpu_ticks); 408 | synchronize(); 409 | update_screen(); 410 | if(update_backup_flag) 411 | update_backup(); 412 | 413 | process_cheats(); 414 | 415 | vcount = 0; 416 | } 417 | 418 | if(vcount == (dispstat >> 8)) 419 | { 420 | // vcount trigger 421 | dispstat |= 0x04; 422 | if(dispstat & 0x20) 423 | { 424 | irq_raised |= IRQ_VCOUNT; 425 | } 426 | } 427 | else 428 | { 429 | dispstat &= ~0x04; 430 | } 431 | 432 | io_registers[REG_VCOUNT] = vcount; 433 | } 434 | io_registers[REG_DISPSTAT] = dispstat; 435 | } 436 | 437 | if(irq_raised) 438 | raise_interrupt(irq_raised); 439 | 440 | execute_cycles = video_count; 441 | 442 | check_timer(0); 443 | check_timer(1); 444 | check_timer(2); 445 | check_timer(3); 446 | 447 | return execute_cycles; 448 | } 449 | 450 | u64 last_screen_timestamp = 0; 451 | u32 frame_speed = 15000; 452 | 453 | #ifdef PSP_BUILD 454 | 455 | u32 real_frame_count = 0; 456 | u32 virtual_frame_count = 0; 457 | u32 num_skipped_frames = 0; 458 | 459 | void vblank_interrupt_handler(u32 sub, u32 *parg) 460 | { 461 | real_frame_count++; 462 | } 463 | 464 | void synchronize() 465 | { 466 | char char_buffer[64]; 467 | u64 new_ticks, time_delta; 468 | s32 used_frameskip = frameskip_value; 469 | 470 | if(!synchronize_flag) 471 | { 472 | print_string("--FF--", 0xFFFF, 0x000, 0, 0); 473 | used_frameskip = 4; 474 | virtual_frame_count = real_frame_count - 1; 475 | } 476 | 477 | skip_next_frame = 0; 478 | 479 | virtual_frame_count++; 480 | 481 | if(real_frame_count >= virtual_frame_count) 482 | { 483 | if((real_frame_count > virtual_frame_count) && 484 | (current_frameskip_type == auto_frameskip) && 485 | (num_skipped_frames < frameskip_value)) 486 | { 487 | skip_next_frame = 1; 488 | num_skipped_frames++; 489 | } 490 | else 491 | { 492 | virtual_frame_count = real_frame_count; 493 | num_skipped_frames = 0; 494 | } 495 | 496 | // Here so that the home button return will eventually work. 497 | // If it's not running fullspeed anyway this won't really hurt 498 | // it much more. 499 | 500 | delay_us(1); 501 | } 502 | else 503 | { 504 | if(synchronize_flag) 505 | sceDisplayWaitVblankStart(); 506 | } 507 | 508 | if(current_frameskip_type == manual_frameskip) 509 | { 510 | frameskip_counter = (frameskip_counter + 1) % 511 | (used_frameskip + 1); 512 | if(random_skip) 513 | { 514 | if(frameskip_counter != (rand() % (used_frameskip + 1))) 515 | skip_next_frame = 1; 516 | } 517 | else 518 | { 519 | if(frameskip_counter) 520 | skip_next_frame = 1; 521 | } 522 | } 523 | 524 | /* sprintf(char_buffer, "%08d %08d %d %d %d\n", 525 | real_frame_count, virtual_frame_count, num_skipped_frames, 526 | real_frame_count - virtual_frame_count, skip_next_frame); 527 | print_string(char_buffer, 0xFFFF, 0x0000, 0, 10); */ 528 | 529 | /* 530 | sprintf(char_buffer, "%02d %02d %06d %07d", frameskip, (u32)ms_needed, 531 | ram_translation_ptr - ram_translation_cache, rom_translation_ptr - 532 | rom_translation_cache); 533 | print_string(char_buffer, 0xFFFF, 0x0000, 0, 0); 534 | */ 535 | } 536 | 537 | #else 538 | 539 | u32 ticks_needed_total = 0; 540 | float us_needed = 0.0; 541 | u32 frames = 0; 542 | const u32 frame_interval = 60; 543 | 544 | void synchronize() 545 | { 546 | u64 new_ticks; 547 | u64 time_delta; 548 | char char_buffer[64]; 549 | 550 | get_ticks_us(&new_ticks); 551 | time_delta = new_ticks - last_screen_timestamp; 552 | last_screen_timestamp = new_ticks; 553 | ticks_needed_total += time_delta; 554 | 555 | skip_next_frame = 0; 556 | 557 | if((time_delta < frame_speed) && synchronize_flag) 558 | { 559 | delay_us(frame_speed - time_delta); 560 | } 561 | 562 | frames++; 563 | 564 | if(frames == frame_interval) 565 | { 566 | us_needed = (float)ticks_needed_total / frame_interval; 567 | ticks_needed_total = 0; 568 | frames = 0; 569 | } 570 | 571 | if(current_frameskip_type == manual_frameskip) 572 | { 573 | frameskip_counter = (frameskip_counter + 1) % 574 | (frameskip_value + 1); 575 | if(random_skip) 576 | { 577 | if(frameskip_counter != (rand() % (frameskip_value + 1))) 578 | skip_next_frame = 1; 579 | } 580 | else 581 | { 582 | if(frameskip_counter) 583 | skip_next_frame = 1; 584 | } 585 | } 586 | 587 | if(synchronize_flag == 0) 588 | print_string("--FF--", 0xFFFF, 0x000, 0, 0); 589 | 590 | sprintf(char_buffer, "gpSP: %.1fms %.1ffps", us_needed / 1000.0, 591 | 1000000.0 / us_needed); 592 | SDL_WM_SetCaption(char_buffer, "gpSP"); 593 | 594 | /* 595 | sprintf(char_buffer, "%02d %02d %06d %07d", frameskip, (u32)ms_needed, 596 | ram_translation_ptr - ram_translation_cache, rom_translation_ptr - 597 | rom_translation_cache); 598 | print_string(char_buffer, 0xFFFF, 0x0000, 0, 0); 599 | */ 600 | } 601 | 602 | #endif 603 | 604 | void quit() 605 | { 606 | if(!update_backup_flag) 607 | update_backup_force(); 608 | 609 | // sound_exit(0); 610 | 611 | #ifdef PSP_BUILD 612 | sceKernelExitGame(); 613 | #else 614 | SDL_Quit(); 615 | exit(0); 616 | #endif 617 | } 618 | 619 | void reset_gba() 620 | { 621 | init_main(); 622 | init_memory(); 623 | init_cpu(); 624 | reset_sound(); 625 | } 626 | 627 | #ifdef PSP_BUILD 628 | 629 | u32 file_length(u8 *filename, s32 dummy) 630 | { 631 | SceIoStat stats; 632 | sceIoGetstat(filename, &stats); 633 | return stats.st_size; 634 | } 635 | 636 | void delay_us(u32 us_count) 637 | { 638 | sceKernelDelayThread(us_count); 639 | } 640 | 641 | void get_ticks_us(u64 *tick_return) 642 | { 643 | u64 ticks; 644 | sceRtcGetCurrentTick(&ticks); 645 | 646 | *tick_return = (ticks * 1000000) / sceRtcGetTickResolution(); 647 | } 648 | 649 | #else 650 | 651 | u32 file_length(u8 *dummy, FILE *fp) 652 | { 653 | u32 length; 654 | 655 | fseek(fp, 0, SEEK_END); 656 | length = ftell(fp); 657 | fseek(fp, 0, SEEK_SET); 658 | 659 | return length; 660 | } 661 | 662 | void delay_us(u32 us_count) 663 | { 664 | SDL_Delay(us_count / 1000); 665 | } 666 | 667 | void get_ticks_us(u64 *ticks_return) 668 | { 669 | *ticks_return = (SDL_GetTicks() * 1000); 670 | } 671 | 672 | #endif 673 | 674 | void change_ext(u8 *src, u8 *buffer, u8 *extension) 675 | { 676 | u8 *dot_position; 677 | strcpy(buffer, src); 678 | dot_position = strrchr(buffer, '.'); 679 | 680 | if(dot_position) 681 | strcpy(dot_position, extension); 682 | } 683 | 684 | #define main_savestate_builder(type) \ 685 | void main_##type##_savestate(file_tag_type savestate_file) \ 686 | { \ 687 | file_##type##_variable(savestate_file, cpu_ticks); \ 688 | file_##type##_variable(savestate_file, execute_cycles); \ 689 | file_##type##_variable(savestate_file, video_count); \ 690 | file_##type##_array(savestate_file, timer); \ 691 | } \ 692 | 693 | main_savestate_builder(read); 694 | main_savestate_builder(write_mem); 695 | 696 | void print_out(u32 address, u32 pc) 697 | { 698 | char buffer[256]; 699 | sprintf(buffer, "patching from gp8 %x", address); 700 | print_string(buffer, 0xFFFF, 0x0000, 0, 0); 701 | update_screen(); 702 | delay_us(5000000); 703 | } 704 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef MAIN_H 21 | #define MAIN_H 22 | 23 | typedef enum 24 | { 25 | TIMER_INACTIVE, 26 | TIMER_PRESCALE, 27 | TIMER_CASCADE 28 | } timer_status_type; 29 | 30 | typedef enum 31 | { 32 | TIMER_NO_IRQ, 33 | TIMER_TRIGGER_IRQ 34 | } timer_irq_type; 35 | 36 | 37 | typedef enum 38 | { 39 | TIMER_DS_CHANNEL_NONE, 40 | TIMER_DS_CHANNEL_A, 41 | TIMER_DS_CHANNEL_B, 42 | TIMER_DS_CHANNEL_BOTH 43 | } timer_ds_channel_type; 44 | 45 | typedef struct 46 | { 47 | s32 count; 48 | u32 reload; 49 | u32 prescale; 50 | u32 stop_cpu_ticks; 51 | fixed16_16 frequency_step; 52 | timer_ds_channel_type direct_sound_channels; 53 | timer_irq_type irq; 54 | timer_status_type status; 55 | } timer_type; 56 | 57 | typedef enum 58 | { 59 | auto_frameskip, 60 | manual_frameskip, 61 | no_frameskip 62 | } frameskip_type; 63 | 64 | extern u32 cpu_ticks; 65 | extern u32 frame_ticks; 66 | extern u32 execute_cycles; 67 | extern frameskip_type current_frameskip_type; 68 | extern u32 frameskip_value; 69 | extern u32 random_skip; 70 | extern u32 global_cycles_per_instruction; 71 | extern u32 synchronize_flag; 72 | extern u32 skip_next_frame; 73 | 74 | extern timer_type timer[4]; 75 | static u32 prescale_table[] = { 0, 6, 8, 10 }; 76 | 77 | extern u32 cycle_memory_access; 78 | extern u32 cycle_pc_relative_access; 79 | extern u32 cycle_sp_relative_access; 80 | extern u32 cycle_block_memory_access; 81 | extern u32 cycle_block_memory_sp_access; 82 | extern u32 cycle_block_memory_words; 83 | extern u32 cycle_dma16_words; 84 | extern u32 cycle_dma32_words; 85 | extern u32 flush_ram_count; 86 | 87 | extern u64 base_timestamp; 88 | 89 | extern volatile u8 main_path[512]; 90 | 91 | extern u32 update_backup_flag; 92 | extern u32 clock_speed; 93 | 94 | u32 update_gba(); 95 | void reset_gba(); 96 | void synchronize(); 97 | void quit(); 98 | void delay_us(u32 us_count); 99 | void get_ticks_us(u64 *tick_return); 100 | void game_name_ext(u8 *src, u8 *buffer, u8 *extension); 101 | void main_write_mem_savestate(file_tag_type savestate_file); 102 | void main_read_savestate(file_tag_type savestate_file); 103 | 104 | #ifdef PSP_BUILD 105 | 106 | u32 file_length(u8 *filename, s32 dummy); 107 | 108 | extern u32 real_frame_count; 109 | extern u32 virtual_frame_count; 110 | extern u32 max_frameskip; 111 | extern u32 num_skipped_frames; 112 | 113 | #else 114 | 115 | u32 file_length(u8 *dummy, FILE *fp); 116 | 117 | #endif 118 | 119 | #define count_timer(timer_number) \ 120 | timer[timer_number].reload = 0x10000 - value; \ 121 | if(timer_number < 2) \ 122 | { \ 123 | u32 timer_reload = \ 124 | timer[timer_number].reload << timer[timer_number].prescale; \ 125 | sound_update_frequency_step(timer_number); \ 126 | } \ 127 | 128 | #define adjust_sound_buffer(timer_number, channel) \ 129 | if(timer[timer_number].direct_sound_channels & (0x01 << channel)) \ 130 | { \ 131 | direct_sound_channel[channel].buffer_index = \ 132 | (direct_sound_channel[channel].buffer_index + buffer_adjust) % \ 133 | BUFFER_SIZE; \ 134 | } \ 135 | 136 | #define trigger_timer(timer_number) \ 137 | if(value & 0x80) \ 138 | { \ 139 | if(timer[timer_number].status == TIMER_INACTIVE) \ 140 | { \ 141 | u32 prescale = prescale_table[value & 0x03]; \ 142 | u32 timer_reload = timer[timer_number].reload; \ 143 | \ 144 | if((value >> 2) & 0x01) \ 145 | timer[timer_number].status = TIMER_CASCADE; \ 146 | else \ 147 | timer[timer_number].status = TIMER_PRESCALE; \ 148 | \ 149 | timer[timer_number].prescale = prescale; \ 150 | timer[timer_number].irq = (value >> 6) & 0x01; \ 151 | \ 152 | address16(io_registers, 0x100 + (timer_number * 4)) = \ 153 | -timer_reload; \ 154 | \ 155 | timer_reload <<= prescale; \ 156 | timer[timer_number].count = timer_reload; \ 157 | \ 158 | if(timer_reload < execute_cycles) \ 159 | execute_cycles = timer_reload; \ 160 | \ 161 | if(timer_number < 2) \ 162 | { \ 163 | u32 buffer_adjust = \ 164 | (u32)(((float)(cpu_ticks - timer[timer_number].stop_cpu_ticks) * \ 165 | sound_frequency) / 16777216.0) * 2; \ 166 | \ 167 | sound_update_frequency_step(timer_number); \ 168 | adjust_sound_buffer(timer_number, 0); \ 169 | adjust_sound_buffer(timer_number, 1); \ 170 | } \ 171 | } \ 172 | } \ 173 | else \ 174 | { \ 175 | if(timer[timer_number].status != TIMER_INACTIVE) \ 176 | { \ 177 | timer[timer_number].status = TIMER_INACTIVE; \ 178 | timer[timer_number].stop_cpu_ticks = cpu_ticks; \ 179 | } \ 180 | } \ 181 | address16(io_registers, 0x102 + (timer_number * 4)) = value; \ 182 | 183 | #endif 184 | 185 | 186 | -------------------------------------------------------------------------------- /memory.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef MEMORY_H 21 | #define MEMORY_H 22 | 23 | typedef enum 24 | { 25 | DMA_START_IMMEDIATELY, 26 | DMA_START_VBLANK, 27 | DMA_START_HBLANK, 28 | DMA_START_SPECIAL, 29 | DMA_INACTIVE 30 | } dma_start_type; 31 | 32 | typedef enum 33 | { 34 | DMA_16BIT, 35 | DMA_32BIT 36 | } dma_length_type; 37 | 38 | typedef enum 39 | { 40 | DMA_NO_REPEAT, 41 | DMA_REPEAT 42 | } dma_repeat_type; 43 | 44 | typedef enum 45 | { 46 | DMA_INCREMENT, 47 | DMA_DECREMENT, 48 | DMA_FIXED, 49 | DMA_RELOAD 50 | } dma_increment_type; 51 | 52 | typedef enum 53 | { 54 | DMA_NO_IRQ, 55 | DMA_TRIGGER_IRQ 56 | } dma_irq_type; 57 | 58 | typedef enum 59 | { 60 | DMA_DIRECT_SOUND_A, 61 | DMA_DIRECT_SOUND_B, 62 | DMA_NO_DIRECT_SOUND 63 | } dma_ds_type; 64 | 65 | typedef struct 66 | { 67 | u32 dma_channel; 68 | u32 source_address; 69 | u32 dest_address; 70 | u32 length; 71 | dma_repeat_type repeat_type; 72 | dma_ds_type direct_sound_channel; 73 | dma_increment_type source_direction; 74 | dma_increment_type dest_direction; 75 | dma_length_type length_type; 76 | dma_start_type start_type; 77 | dma_irq_type irq; 78 | } dma_transfer_type; 79 | 80 | typedef enum 81 | { 82 | REG_DISPCNT = 0x000, 83 | REG_DISPSTAT = 0x002, 84 | REG_VCOUNT = 0x003, 85 | REG_BG0CNT = 0x004, 86 | REG_BG1CNT = 0x005, 87 | REG_BG2CNT = 0x006, 88 | REG_BG3CNT = 0x007, 89 | REG_BG0HOFS = 0x08, 90 | REG_BG0VOFS = 0x09, 91 | REG_BG1HOFS = 0x0A, 92 | REG_BG1VOFS = 0x0B, 93 | REG_BG2HOFS = 0x0C, 94 | REG_BG2VOFS = 0x0D, 95 | REG_BG3HOFS = 0x0E, 96 | REG_BG3VOFS = 0x0F, 97 | REG_BG2PA = 0x10, 98 | REG_BG2PB = 0x11, 99 | REG_BG2PC = 0x12, 100 | REG_BG2PD = 0x13, 101 | REG_BG2X_L = 0x14, 102 | REG_BG2X_H = 0x15, 103 | REG_BG2Y_L = 0x16, 104 | REG_BG2Y_H = 0x17, 105 | REG_BG3PA = 0x18, 106 | REG_BG3PB = 0x19, 107 | REG_BG3PC = 0x1A, 108 | REG_BG3PD = 0x1B, 109 | REG_BG3X_L = 0x1C, 110 | REG_BG3X_H = 0x1D, 111 | REG_BG3Y_L = 0x1E, 112 | REG_BG3Y_H = 0x1F, 113 | REG_WIN0H = 0x20, 114 | REG_WIN1H = 0x21, 115 | REG_WIN0V = 0x22, 116 | REG_WIN1V = 0x23, 117 | REG_WININ = 0x24, 118 | REG_WINOUT = 0x25, 119 | REG_BLDCNT = 0x28, 120 | REG_BLDALPHA = 0x29, 121 | REG_BLDY = 0x2A, 122 | REG_TM0D = 0x80, 123 | REG_TM0CNT = 0x81, 124 | REG_TM1D = 0x82, 125 | REG_TM1CNT = 0x83, 126 | REG_TM2D = 0x84, 127 | REG_TM2CNT = 0x85, 128 | REG_TM3D = 0x86, 129 | REG_TM3CNT = 0x87, 130 | REG_P1 = 0x098, 131 | REG_P1CNT = 0x099, 132 | REG_RCNT = 0x9A, 133 | REG_IE = 0x100, 134 | REG_IF = 0x101, 135 | REG_IME = 0x104, 136 | REG_HALTCNT = 0x180 137 | } hardware_register; 138 | 139 | typedef enum 140 | { 141 | FLASH_DEVICE_MACRONIX_64KB = 0x1C, 142 | FLASH_DEVICE_AMTEL_64KB = 0x3D, 143 | FLASH_DEVICE_SST_64K = 0xD4, 144 | FLASH_DEVICE_PANASONIC_64KB = 0x1B, 145 | FLASH_DEVICE_MACRONIX_128KB = 0x09 146 | } flash_device_id_type; 147 | 148 | typedef enum 149 | { 150 | FLASH_MANUFACTURER_MACRONIX = 0xC2, 151 | FLASH_MANUFACTURER_AMTEL = 0x1F, 152 | FLASH_MANUFACTURER_PANASONIC = 0x32, 153 | FLASH_MANUFACTURER_SST = 0xBF 154 | } flash_manufacturer_id_type; 155 | 156 | u8 function_cc read_memory8(u32 address); 157 | u32 function_cc read_memory16(u32 address); 158 | u16 function_cc read_memory16_signed(u32 address); 159 | u32 function_cc read_memory32(u32 address); 160 | cpu_alert_type function_cc write_memory8(u32 address, u8 value); 161 | cpu_alert_type function_cc write_memory16(u32 address, u16 value); 162 | cpu_alert_type function_cc write_memory32(u32 address, u32 value); 163 | 164 | extern u8 *memory_regions[16]; 165 | extern u32 memory_limits[16]; 166 | 167 | u32 waitstate_cycles_sequential[16][3]; 168 | 169 | extern u32 gamepak_size; 170 | extern u8 gamepak_title[13]; 171 | extern u8 gamepak_code[5]; 172 | extern u8 gamepak_maker[3]; 173 | extern u8 gamepak_filename[512]; 174 | 175 | cpu_alert_type dma_transfer(dma_transfer_type *dma); 176 | u8 *memory_region(u32 address, u32 *memory_limit); 177 | u32 load_gamepak(char *name); 178 | u32 load_backup(char *name); 179 | s32 load_bios(char *name); 180 | void update_backup(); 181 | void update_backup_force(); 182 | void init_memory(); 183 | u8 *load_gamepak_page(u32 physical_index); 184 | void memory_write_mem_savestate(file_tag_type savestate_file); 185 | void memory_read_savestate(file_tag_type savestate_file); 186 | void load_state(char *savestate_filename); 187 | void save_state(char *savestate_filename, u16 *screen_capture); 188 | 189 | extern u8 *gamepak_rom; 190 | extern u32 gamepak_ram_buffer_size; 191 | extern u32 oam_update; 192 | extern u32 gbc_sound_update; 193 | extern u32 gbc_sound_wave_update; 194 | extern dma_transfer_type dma[4]; 195 | 196 | u8 *write_mem_ptr; 197 | 198 | #ifdef PSP_BUILD_VRAM_STORAGE 199 | 200 | extern u16 *io_registers; 201 | extern u8 *ewram; 202 | extern u8 *iwram; 203 | extern u8 *vram; 204 | extern u16 *palette_ram; 205 | extern u16 *oam_ram; 206 | extern u16 *palette_ram_converted; 207 | //extern u8 *bios_rom; 208 | 209 | #else 210 | 211 | extern u16 palette_ram[512]; 212 | extern u16 oam_ram[512]; 213 | extern u16 palette_ram_converted[512]; 214 | extern u16 io_registers[1024 * 16]; 215 | extern u8 ewram[1024 * 256 * 2]; 216 | extern u8 iwram[1024 * 32 * 2]; 217 | extern u8 vram[1024 * 96 * 2]; 218 | 219 | #endif 220 | 221 | extern u8 bios_rom[1024 * 32]; 222 | extern u32 bios_read_protect; 223 | 224 | extern u8 *memory_map_read[8 * 1024]; 225 | extern u32 reg[64]; 226 | extern u8 *memory_map_write[8 * 1024]; 227 | 228 | extern flash_device_id_type flash_device_id; 229 | 230 | #endif 231 | -------------------------------------------------------------------------------- /psp/ICON0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BASLQC/gPSP/7e76c366762f09585c2965410697ccf76fd7d10a/psp/ICON0.png -------------------------------------------------------------------------------- /psp/Makefile: -------------------------------------------------------------------------------- 1 | # -x assembler-with-cpp 2 | # gpSP makefile 3 | # Gilead Kutnick - Exophase 4 | 5 | # Global definitions 6 | 7 | PSPSDK = ${shell psp-config --pspsdk-path} 8 | PREFIX = ${shell psp-config --psp-prefix} 9 | PSPDEV = ${shell psp-config --pspdev-path} 10 | 11 | OBJS = main.o cpu.o video.o memory.o sound.o input.o \ 12 | cpu_threaded.o gui.o zip.o cheats.o mips_stub.o 13 | 14 | TARGET = gpSP 15 | 16 | VPATH += .. 17 | CFLAGS += -O3 -DPSP_BUILD -G0 -funsigned-char 18 | CFLAGS += ${shell ${PSPDEV}/bin/sdl-config --cflags} 19 | ASFLAGS = ${CFLAGS} 20 | PSP_EBOOT_TITLE = gpSP v0.9 signed 21 | PSP_EBOOT_ICON = ICON0.PNG 22 | PSP_EBOOT_PIC1 = PIC1.PNG 23 | EXTRA_TARGETS = EBOOT.PBP 24 | 25 | BUILD_PRX = 1 26 | ENCRYPT = 1 27 | 28 | LIBS += ${shell ${PSPDEV}/bin/sdl-config --libs} -lpsppower \ 29 | -lz 30 | 31 | include ${PSPSDK}/lib/build.mak 32 | 33 | -------------------------------------------------------------------------------- /psp/PIC1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BASLQC/gPSP/7e76c366762f09585c2965410697ccf76fd7d10a/psp/PIC1.png -------------------------------------------------------------------------------- /sound.c: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include "common.h" 22 | 23 | u32 global_enable_audio = 1; 24 | 25 | direct_sound_struct direct_sound_channel[2]; 26 | gbc_sound_struct gbc_sound_channel[4]; 27 | 28 | u32 sound_frequency = 44100; 29 | 30 | SDL_AudioSpec sound_settings; 31 | SDL_mutex *sound_mutex; 32 | SDL_cond *sound_cv; 33 | 34 | u32 audio_buffer_size_number = 2; 35 | u32 audio_buffer_size; 36 | u32 sound_on = 0; 37 | s16 sound_buffer[BUFFER_SIZE]; 38 | u32 sound_buffer_base = 0; 39 | 40 | u32 sound_last_cpu_ticks = 0; 41 | fixed16_16 gbc_sound_tick_step; 42 | 43 | // Queue 1, 2, or 4 samples to the top of the DS FIFO, wrap around circularly 44 | 45 | #define sound_timer_queue(size, value) \ 46 | *((s##size *)(ds->fifo + ds->fifo_top)) = value; \ 47 | ds->fifo_top = (ds->fifo_top + 1) % 32; \ 48 | 49 | void sound_timer_queue8(u32 channel, u8 value) 50 | { 51 | direct_sound_struct *ds = direct_sound_channel + channel; 52 | sound_timer_queue(8, value); 53 | } 54 | 55 | void sound_timer_queue16(u32 channel, u16 value) 56 | { 57 | direct_sound_struct *ds = direct_sound_channel + channel; 58 | sound_timer_queue(8, value & 0xFF); 59 | sound_timer_queue(8, value >> 8); 60 | } 61 | 62 | void sound_timer_queue32(u32 channel, u32 value) 63 | { 64 | direct_sound_struct *ds = direct_sound_channel + channel; 65 | 66 | sound_timer_queue(8, value & 0xFF); 67 | sound_timer_queue(8, (value >> 8) & 0xFF); 68 | sound_timer_queue(8, (value >> 16) & 0xFF); 69 | sound_timer_queue(8, value >> 24); 70 | } 71 | 72 | // Unqueue 1 sample from the base of the DS FIFO and place it on the audio 73 | // buffer for as many samples as necessary. If the DS FIFO is 16 bytes or 74 | // smaller and if DMA is enabled for the sound channel initiate a DMA transfer 75 | // to the DS FIFO. 76 | 77 | #define render_sample_null() \ 78 | 79 | #define render_sample_left() \ 80 | sound_buffer[buffer_index] += current_sample + \ 81 | fp16_16_to_u32((next_sample - current_sample) * fifo_fractional) \ 82 | 83 | #define render_sample_right() \ 84 | sound_buffer[buffer_index + 1] += current_sample + \ 85 | fp16_16_to_u32((next_sample - current_sample) * fifo_fractional) \ 86 | 87 | #define render_sample_both() \ 88 | dest_sample = current_sample + \ 89 | fp16_16_to_u32((next_sample - current_sample) * fifo_fractional); \ 90 | sound_buffer[buffer_index] += dest_sample; \ 91 | sound_buffer[buffer_index + 1] += dest_sample \ 92 | 93 | #define render_samples(type) \ 94 | while(fifo_fractional <= 0xFFFF) \ 95 | { \ 96 | render_sample_##type(); \ 97 | fifo_fractional += frequency_step; \ 98 | buffer_index = (buffer_index + 2) % BUFFER_SIZE; \ 99 | } \ 100 | 101 | void sound_timer(fixed16_16 frequency_step, u32 channel) 102 | { 103 | direct_sound_struct *ds = direct_sound_channel + channel; 104 | 105 | fixed16_16 fifo_fractional = ds->fifo_fractional; 106 | u32 buffer_index = ds->buffer_index; 107 | s16 current_sample, next_sample, dest_sample; 108 | 109 | current_sample = ds->fifo[ds->fifo_base] << 4; 110 | ds->fifo_base = (ds->fifo_base + 1) % 32; 111 | next_sample = ds->fifo[ds->fifo_base] << 4; 112 | 113 | if(sound_on == 1) 114 | { 115 | if(ds->volume == DIRECT_SOUND_VOLUME_50) 116 | { 117 | current_sample >>= 1; 118 | next_sample >>= 1; 119 | } 120 | 121 | switch(ds->status) 122 | { 123 | case DIRECT_SOUND_INACTIVE: 124 | render_samples(null); 125 | break; 126 | 127 | case DIRECT_SOUND_RIGHT: 128 | render_samples(right); 129 | break; 130 | 131 | case DIRECT_SOUND_LEFT: 132 | render_samples(left); 133 | break; 134 | 135 | case DIRECT_SOUND_LEFTRIGHT: 136 | render_samples(both); 137 | break; 138 | } 139 | } 140 | else 141 | { 142 | render_samples(null); 143 | } 144 | 145 | ds->buffer_index = buffer_index; 146 | ds->fifo_fractional = fp16_16_fractional_part(fifo_fractional); 147 | 148 | if(((ds->fifo_top - ds->fifo_base) % 32) <= 16) 149 | { 150 | if(dma[1].direct_sound_channel == channel) 151 | dma_transfer(dma + 1); 152 | 153 | if(dma[2].direct_sound_channel == channel) 154 | dma_transfer(dma + 2); 155 | } 156 | } 157 | 158 | void sound_reset_fifo(u32 channel) 159 | { 160 | direct_sound_struct *ds = direct_sound_channel; 161 | 162 | memset(ds->fifo, 0, 32); 163 | } 164 | 165 | // Initial pattern data = 4bits (signed) 166 | // Channel volume = 12bits 167 | // Envelope volume = 14bits 168 | // Master volume = 2bits 169 | 170 | // Recalculate left and right volume as volume changes. 171 | // To calculate the current sample, use (sample * volume) >> 16 172 | 173 | // Square waves range from -8 (low) to 7 (high) 174 | 175 | s8 square_pattern_duty[4][8] = 176 | { 177 | { 0xF8, 0xF8, 0xF8, 0xF8, 0x07, 0xF8, 0xF8, 0xF8 }, 178 | { 0xF8, 0xF8, 0xF8, 0xF8, 0x07, 0x07, 0xF8, 0xF8 }, 179 | { 0xF8, 0xF8, 0x07, 0x07, 0x07, 0x07, 0xF8, 0xF8 }, 180 | { 0x07, 0x07, 0x07, 0x07, 0xF8, 0xF8, 0x07, 0x07 }, 181 | }; 182 | 183 | s8 wave_samples[64]; 184 | 185 | u32 noise_table15[1024]; 186 | u32 noise_table7[4]; 187 | 188 | u32 gbc_sound_master_volume_table[4] = { 1, 2, 4, 0 }; 189 | 190 | u32 gbc_sound_channel_volume_table[8] = 191 | { 192 | fixed_div(0, 7, 12), 193 | fixed_div(1, 7, 12), 194 | fixed_div(2, 7, 12), 195 | fixed_div(3, 7, 12), 196 | fixed_div(4, 7, 12), 197 | fixed_div(5, 7, 12), 198 | fixed_div(6, 7, 12), 199 | fixed_div(7, 7, 12) 200 | }; 201 | 202 | u32 gbc_sound_envelope_volume_table[16] = 203 | { 204 | fixed_div(0, 15, 14), 205 | fixed_div(1, 15, 14), 206 | fixed_div(2, 15, 14), 207 | fixed_div(3, 15, 14), 208 | fixed_div(4, 15, 14), 209 | fixed_div(5, 15, 14), 210 | fixed_div(6, 15, 14), 211 | fixed_div(7, 15, 14), 212 | fixed_div(8, 15, 14), 213 | fixed_div(9, 15, 14), 214 | fixed_div(10, 15, 14), 215 | fixed_div(11, 15, 14), 216 | fixed_div(12, 15, 14), 217 | fixed_div(13, 15, 14), 218 | fixed_div(14, 15, 14), 219 | fixed_div(15, 15, 14) 220 | }; 221 | 222 | u32 gbc_sound_buffer_index = 0; 223 | u32 gbc_sound_last_cpu_ticks = 0; 224 | u32 gbc_sound_partial_ticks = 0; 225 | 226 | u32 gbc_sound_master_volume_left; 227 | u32 gbc_sound_master_volume_right; 228 | u32 gbc_sound_master_volume; 229 | 230 | #define update_volume_channel_envelope(channel) \ 231 | volume_##channel = gbc_sound_envelope_volume_table[envelope_volume] * \ 232 | gbc_sound_channel_volume_table[gbc_sound_master_volume_##channel] * \ 233 | gbc_sound_master_volume_table[gbc_sound_master_volume] \ 234 | 235 | #define update_volume_channel_noenvelope(channel) \ 236 | volume_##channel = gs->wave_volume * \ 237 | gbc_sound_channel_volume_table[gbc_sound_master_volume_##channel] * \ 238 | gbc_sound_master_volume_table[gbc_sound_master_volume] \ 239 | 240 | #define update_volume(type) \ 241 | update_volume_channel_##type(left); \ 242 | update_volume_channel_##type(right) \ 243 | 244 | #define update_tone_sweep() \ 245 | if(gs->sweep_status) \ 246 | { \ 247 | u32 sweep_ticks = gs->sweep_ticks - 1; \ 248 | \ 249 | if(sweep_ticks == 0) \ 250 | { \ 251 | u32 rate = gs->rate; \ 252 | \ 253 | if(gs->sweep_direction) \ 254 | rate = rate - (rate >> gs->sweep_shift); \ 255 | else \ 256 | rate = rate + (rate >> gs->sweep_shift); \ 257 | \ 258 | if(rate > 2048) \ 259 | rate = 2048; \ 260 | \ 261 | frequency_step = float_to_fp16_16(((131072.0 / (2048 - rate)) * 8.0) / \ 262 | sound_frequency); \ 263 | \ 264 | gs->frequency_step = frequency_step; \ 265 | gs->rate = rate; \ 266 | \ 267 | sweep_ticks = gs->sweep_initial_ticks; \ 268 | } \ 269 | gs->sweep_ticks = sweep_ticks; \ 270 | } \ 271 | 272 | #define update_tone_nosweep() \ 273 | 274 | #define update_tone_envelope() \ 275 | if(gs->envelope_status) \ 276 | { \ 277 | u32 envelope_ticks = gs->envelope_ticks - 1; \ 278 | envelope_volume = gs->envelope_volume; \ 279 | \ 280 | if(envelope_ticks == 0) \ 281 | { \ 282 | if(gs->envelope_direction) \ 283 | { \ 284 | if(envelope_volume != 15) \ 285 | envelope_volume = gs->envelope_volume + 1; \ 286 | } \ 287 | else \ 288 | { \ 289 | if(envelope_volume != 0) \ 290 | envelope_volume = gs->envelope_volume - 1; \ 291 | } \ 292 | \ 293 | update_volume(envelope); \ 294 | \ 295 | gs->envelope_volume = envelope_volume; \ 296 | gs->envelope_ticks = gs->envelope_initial_ticks; \ 297 | } \ 298 | else \ 299 | { \ 300 | gs->envelope_ticks = envelope_ticks; \ 301 | } \ 302 | } \ 303 | 304 | #define update_tone_noenvelope() \ 305 | 306 | #define gbc_sound_synchronize() \ 307 | while(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) > \ 308 | (audio_buffer_size * 2)) \ 309 | { \ 310 | SDL_CondWait(sound_cv, sound_mutex); \ 311 | } \ 312 | 313 | #define update_tone_counters(envelope_op, sweep_op) \ 314 | tick_counter += gbc_sound_tick_step; \ 315 | if(tick_counter > 0xFFFF) \ 316 | { \ 317 | if(gs->length_status) \ 318 | { \ 319 | u32 length_ticks = gs->length_ticks - 1; \ 320 | gs->length_ticks = length_ticks; \ 321 | \ 322 | if(length_ticks == 0) \ 323 | { \ 324 | gs->active_flag = 0; \ 325 | break; \ 326 | } \ 327 | } \ 328 | \ 329 | update_tone_##envelope_op(); \ 330 | update_tone_##sweep_op(); \ 331 | \ 332 | tick_counter &= 0xFFFF; \ 333 | } \ 334 | 335 | #define gbc_sound_render_sample_right() \ 336 | sound_buffer[buffer_index + 1] += (current_sample * volume_right) >> 22 \ 337 | 338 | #define gbc_sound_render_sample_left() \ 339 | sound_buffer[buffer_index] += (current_sample * volume_left) >> 22 \ 340 | 341 | #define gbc_sound_render_sample_both() \ 342 | gbc_sound_render_sample_right(); \ 343 | gbc_sound_render_sample_left() \ 344 | 345 | #define gbc_sound_render_samples(type, sample_length, envelope_op, sweep_op) \ 346 | for(i = 0; i < buffer_ticks; i++) \ 347 | { \ 348 | current_sample = \ 349 | sample_data[fp16_16_to_u32(sample_index) % sample_length]; \ 350 | gbc_sound_render_sample_##type(); \ 351 | \ 352 | sample_index += frequency_step; \ 353 | buffer_index = (buffer_index + 2) % BUFFER_SIZE; \ 354 | \ 355 | update_tone_counters(envelope_op, sweep_op); \ 356 | } \ 357 | 358 | #define gbc_noise_wrap_full 32767 359 | 360 | #define gbc_noise_wrap_half 126 361 | 362 | #define get_noise_sample_full() \ 363 | current_sample = \ 364 | ((s32)(noise_table15[fp16_16_to_u32(sample_index) >> 5] << \ 365 | (fp16_16_to_u32(sample_index) & 0x1F)) >> 31) & 0x0F \ 366 | 367 | #define get_noise_sample_half() \ 368 | current_sample = \ 369 | ((s32)(noise_table7[fp16_16_to_u32(sample_index) >> 5] << \ 370 | (fp16_16_to_u32(sample_index) & 0x1F)) >> 31) & 0x0F \ 371 | 372 | #define gbc_sound_render_noise(type, noise_type, envelope_op, sweep_op) \ 373 | for(i = 0; i < buffer_ticks; i++) \ 374 | { \ 375 | get_noise_sample_##noise_type(); \ 376 | gbc_sound_render_sample_##type(); \ 377 | \ 378 | sample_index += frequency_step; \ 379 | \ 380 | if(sample_index >= u32_to_fp16_16(gbc_noise_wrap_##noise_type)) \ 381 | sample_index -= u32_to_fp16_16(gbc_noise_wrap_##noise_type); \ 382 | \ 383 | buffer_index = (buffer_index + 2) % BUFFER_SIZE; \ 384 | update_tone_counters(envelope_op, sweep_op); \ 385 | } \ 386 | 387 | #define gbc_sound_render_channel(type, sample_length, envelope_op, sweep_op) \ 388 | buffer_index = gbc_sound_buffer_index; \ 389 | sample_index = gs->sample_index; \ 390 | frequency_step = gs->frequency_step; \ 391 | tick_counter = gs->tick_counter; \ 392 | \ 393 | update_volume(envelope_op); \ 394 | \ 395 | switch(gs->status) \ 396 | { \ 397 | case GBC_SOUND_INACTIVE: \ 398 | break; \ 399 | \ 400 | case GBC_SOUND_LEFT: \ 401 | gbc_sound_render_##type(left, sample_length, envelope_op, sweep_op); \ 402 | break; \ 403 | \ 404 | case GBC_SOUND_RIGHT: \ 405 | gbc_sound_render_##type(right, sample_length, envelope_op, sweep_op); \ 406 | break; \ 407 | \ 408 | case GBC_SOUND_LEFTRIGHT: \ 409 | gbc_sound_render_##type(both, sample_length, envelope_op, sweep_op); \ 410 | break; \ 411 | } \ 412 | \ 413 | gs->sample_index = sample_index; \ 414 | gs->tick_counter = tick_counter; \ 415 | 416 | #define gbc_sound_load_wave_ram(bank) \ 417 | wave_bank = wave_samples + (bank * 32); \ 418 | for(i = 0, i2 = 0; i < 16; i++, i2 += 2) \ 419 | { \ 420 | current_sample = wave_ram[i]; \ 421 | wave_bank[i2] = (((current_sample >> 4) & 0x0F) - 8); \ 422 | wave_bank[i2 + 1] = ((current_sample & 0x0F) - 8); \ 423 | } \ 424 | 425 | void synchronize_sound() 426 | { 427 | SDL_LockMutex(sound_mutex); 428 | 429 | gbc_sound_synchronize(); 430 | 431 | SDL_UnlockMutex(sound_mutex); 432 | } 433 | 434 | void update_gbc_sound(u32 cpu_ticks) 435 | { 436 | fixed16_16 buffer_ticks = float_to_fp16_16(((float)(cpu_ticks - 437 | gbc_sound_last_cpu_ticks) * sound_frequency) / 16777216.0); 438 | u32 i, i2; 439 | gbc_sound_struct *gs = gbc_sound_channel; 440 | fixed16_16 sample_index, frequency_step; 441 | fixed16_16 tick_counter; 442 | u32 buffer_index; 443 | s32 volume_left, volume_right; 444 | u32 envelope_volume; 445 | s32 current_sample; 446 | u32 sound_status = address16(io_registers, 0x84) & 0xFFF0; 447 | s8 *sample_data; 448 | s8 *wave_bank; 449 | u8 *wave_ram = ((u8 *)io_registers) + 0x90; 450 | 451 | gbc_sound_partial_ticks += fp16_16_fractional_part(buffer_ticks); 452 | buffer_ticks = fp16_16_to_u32(buffer_ticks); 453 | 454 | if(gbc_sound_partial_ticks > 0xFFFF) 455 | { 456 | buffer_ticks += 1; 457 | gbc_sound_partial_ticks &= 0xFFFF; 458 | } 459 | 460 | SDL_LockMutex(sound_mutex); 461 | 462 | if(synchronize_flag) 463 | { 464 | if(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) > 465 | (audio_buffer_size * 3 / 2)) 466 | { 467 | while(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) > 468 | (audio_buffer_size * 3 / 2)) 469 | { 470 | SDL_CondWait(sound_cv, sound_mutex); 471 | } 472 | 473 | #ifdef PSP_BUILD 474 | if(current_frameskip_type == auto_frameskip) 475 | { 476 | sceDisplayWaitVblankStart(); 477 | real_frame_count = 0; 478 | virtual_frame_count = 0; 479 | } 480 | #endif 481 | } 482 | } 483 | 484 | if(sound_on == 1) 485 | { 486 | gs = gbc_sound_channel + 0; 487 | if(gs->active_flag) 488 | { 489 | sound_status |= 0x01; 490 | sample_data = gs->sample_data; 491 | envelope_volume = gs->envelope_volume; 492 | gbc_sound_render_channel(samples, 8, envelope, sweep); 493 | } 494 | 495 | gs = gbc_sound_channel + 1; 496 | if(gs->active_flag) 497 | { 498 | sound_status |= 0x02; 499 | sample_data = gs->sample_data; 500 | envelope_volume = gs->envelope_volume; 501 | gbc_sound_render_channel(samples, 8, envelope, nosweep); 502 | } 503 | 504 | gs = gbc_sound_channel + 2; 505 | if(gbc_sound_wave_update) 506 | { 507 | if(gs->wave_bank == 1) 508 | { 509 | gbc_sound_load_wave_ram(1); 510 | } 511 | else 512 | { 513 | gbc_sound_load_wave_ram(0); 514 | } 515 | 516 | gbc_sound_wave_update = 0; 517 | } 518 | 519 | if((gs->active_flag) && (gs->master_enable)) 520 | { 521 | sound_status |= 0x04; 522 | sample_data = wave_samples; 523 | if(gs->wave_type == 0) 524 | { 525 | if(gs->wave_bank == 1) 526 | sample_data += 32; 527 | 528 | gbc_sound_render_channel(samples, 32, noenvelope, nosweep); 529 | } 530 | else 531 | { 532 | gbc_sound_render_channel(samples, 64, noenvelope, nosweep); 533 | } 534 | } 535 | 536 | gs = gbc_sound_channel + 3; 537 | if(gs->active_flag) 538 | { 539 | sound_status |= 0x08; 540 | envelope_volume = gs->envelope_volume; 541 | 542 | if(gs->noise_type == 1) 543 | { 544 | gbc_sound_render_channel(noise, half, envelope, nosweep); 545 | } 546 | else 547 | { 548 | gbc_sound_render_channel(noise, full, envelope, nosweep); 549 | } 550 | } 551 | } 552 | 553 | address16(io_registers, 0x84) = sound_status; 554 | 555 | SDL_CondSignal(sound_cv); 556 | 557 | SDL_UnlockMutex(sound_mutex); 558 | 559 | gbc_sound_last_cpu_ticks = cpu_ticks; 560 | gbc_sound_buffer_index = 561 | (gbc_sound_buffer_index + (buffer_ticks * 2)) % BUFFER_SIZE; 562 | } 563 | 564 | #define sound_copy_normal() \ 565 | current_sample = source[i] \ 566 | 567 | #define sound_copy(source_offset, length, render_type) \ 568 | _length = (length) / 2; \ 569 | source = (s16 *)(sound_buffer + source_offset); \ 570 | for(i = 0; i < _length; i++) \ 571 | { \ 572 | sound_copy_##render_type(); \ 573 | if(current_sample > 2047) \ 574 | current_sample = 2047; \ 575 | if(current_sample < -2048) \ 576 | current_sample = -2048; \ 577 | \ 578 | stream_base[i] = current_sample << 4; \ 579 | source[i] = 0; \ 580 | } \ 581 | 582 | #define sound_copy_null(source_offset, length) \ 583 | _length = (length) / 2; \ 584 | source = (s16 *)(sound_buffer + source_offset); \ 585 | for(i = 0; i < _length; i++) \ 586 | { \ 587 | stream_base[i] = 0; \ 588 | source[i] = 0; \ 589 | } \ 590 | 591 | 592 | void sound_callback(void *userdata, Uint8 *stream, int length) 593 | { 594 | u32 sample_length = length / 2; 595 | u32 _length; 596 | u32 i; 597 | s16 *stream_base = (s16 *)stream; 598 | s16 *source; 599 | s32 current_sample; 600 | 601 | SDL_LockMutex(sound_mutex); 602 | 603 | while(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) < 604 | length) 605 | { 606 | SDL_CondWait(sound_cv, sound_mutex); 607 | } 608 | 609 | if(global_enable_audio) 610 | { 611 | if((sound_buffer_base + sample_length) >= BUFFER_SIZE) 612 | { 613 | u32 partial_length = (BUFFER_SIZE - sound_buffer_base) * 2; 614 | sound_copy(sound_buffer_base, partial_length, normal); 615 | source = (s16 *)sound_buffer; 616 | sound_copy(0, length - partial_length, normal); 617 | sound_buffer_base = (length - partial_length) / 2; 618 | } 619 | else 620 | { 621 | sound_copy(sound_buffer_base, length, normal); 622 | sound_buffer_base += sample_length; 623 | } 624 | } 625 | else 626 | { 627 | if((sound_buffer_base + sample_length) >= BUFFER_SIZE) 628 | { 629 | u32 partial_length = (BUFFER_SIZE - sound_buffer_base) * 2; 630 | sound_copy_null(sound_buffer_base, partial_length); 631 | source = (s16 *)sound_buffer; 632 | sound_copy(0, length - partial_length, normal); 633 | sound_buffer_base = (length - partial_length) / 2; 634 | } 635 | else 636 | { 637 | sound_copy_null(sound_buffer_base, length); 638 | sound_buffer_base += sample_length; 639 | } 640 | } 641 | 642 | SDL_CondSignal(sound_cv); 643 | 644 | SDL_UnlockMutex(sound_mutex); 645 | } 646 | 647 | // Special thanks to blarrg for the LSFR frequency used in Meridian, as posted 648 | // on the forum at http://meridian.overclocked.org: 649 | // http://meridian.overclocked.org/cgi-bin/wwwthreads/showpost.pl?Board=merid 650 | // angeneraldiscussion&Number=2069&page=0&view=expanded&mode=threaded&sb=4 651 | // Hope you don't mind me borrowing it ^_- 652 | 653 | void init_noise_table(u32 *table, u32 period, u32 bit_length) 654 | { 655 | u32 shift_register = 0xFF; 656 | u32 mask = ~(1 << bit_length); 657 | s32 table_pos, bit_pos; 658 | u32 current_entry; 659 | u32 table_period = (period + 31) / 32; 660 | 661 | // Bits are stored in reverse order so they can be more easily moved to 662 | // bit 31, for sign extended shift down. 663 | 664 | for(table_pos = 0; table_pos < table_period; table_pos++) 665 | { 666 | current_entry = 0; 667 | for(bit_pos = 31; bit_pos >= 0; bit_pos--) 668 | { 669 | current_entry |= (shift_register & 0x01) << bit_pos; 670 | 671 | shift_register = 672 | ((1 & (shift_register ^ (shift_register >> 1))) << bit_length) | 673 | ((shift_register >> 1) & mask); 674 | } 675 | 676 | table[table_pos] = current_entry; 677 | } 678 | } 679 | 680 | void reset_sound() 681 | { 682 | direct_sound_struct *ds = direct_sound_channel; 683 | gbc_sound_struct *gs = gbc_sound_channel; 684 | u32 i; 685 | 686 | sound_on = 0; 687 | sound_buffer_base = 0; 688 | sound_last_cpu_ticks = 0; 689 | memset(sound_buffer, 0, audio_buffer_size); 690 | 691 | for(i = 0; i < 2; i++, ds++) 692 | { 693 | ds->buffer_index = 0; 694 | ds->status = DIRECT_SOUND_INACTIVE; 695 | ds->fifo_top = 0; 696 | ds->fifo_base = 0; 697 | ds->fifo_fractional = 0; 698 | ds->last_cpu_ticks = 0; 699 | memset(ds->fifo, 0, 32); 700 | } 701 | 702 | gbc_sound_buffer_index = 0; 703 | gbc_sound_last_cpu_ticks = 0; 704 | gbc_sound_partial_ticks = 0; 705 | 706 | gbc_sound_master_volume_left = 0; 707 | gbc_sound_master_volume_right = 0; 708 | gbc_sound_master_volume = 0; 709 | memset(wave_samples, 0, 64); 710 | 711 | for(i = 0; i < 4; i++, gs++) 712 | { 713 | gs->status = GBC_SOUND_INACTIVE; 714 | gs->sample_data = square_pattern_duty[2]; 715 | gs->active_flag = 0; 716 | } 717 | } 718 | 719 | void sound_exit() 720 | { 721 | gbc_sound_buffer_index = 722 | (sound_buffer_base + audio_buffer_size) % BUFFER_SIZE; 723 | SDL_PauseAudio(1); 724 | SDL_CondSignal(sound_cv); 725 | } 726 | 727 | void init_sound() 728 | { 729 | #ifdef PSP_BUILD 730 | audio_buffer_size = (audio_buffer_size_number * 1024) + 2048; 731 | #else 732 | audio_buffer_size = 16384; 733 | #endif 734 | 735 | SDL_AudioSpec desired_spec = 736 | { 737 | sound_frequency, 738 | AUDIO_S16, 739 | 2, 740 | 0, 741 | audio_buffer_size / 4, 742 | 0, 743 | 0, 744 | sound_callback, 745 | NULL 746 | }; 747 | 748 | gbc_sound_tick_step = 749 | float_to_fp16_16(256.0 / sound_frequency); 750 | 751 | init_noise_table(noise_table15, 32767, 14); 752 | init_noise_table(noise_table7, 127, 6); 753 | 754 | reset_sound(); 755 | 756 | SDL_OpenAudio(&desired_spec, &sound_settings); 757 | sound_frequency = sound_settings.freq; 758 | sound_mutex = SDL_CreateMutex(); 759 | sound_cv = SDL_CreateCond(); 760 | SDL_PauseAudio(0); 761 | } 762 | 763 | #define sound_savestate_builder(type) \ 764 | void sound_##type##_savestate(file_tag_type savestate_file) \ 765 | { \ 766 | file_##type##_variable(savestate_file, sound_on); \ 767 | file_##type##_variable(savestate_file, sound_buffer_base); \ 768 | file_##type##_variable(savestate_file, sound_last_cpu_ticks); \ 769 | file_##type##_variable(savestate_file, gbc_sound_buffer_index); \ 770 | file_##type##_variable(savestate_file, gbc_sound_last_cpu_ticks); \ 771 | file_##type##_variable(savestate_file, gbc_sound_partial_ticks); \ 772 | file_##type##_variable(savestate_file, gbc_sound_master_volume_left); \ 773 | file_##type##_variable(savestate_file, gbc_sound_master_volume_right); \ 774 | file_##type##_variable(savestate_file, gbc_sound_master_volume); \ 775 | file_##type##_array(savestate_file, wave_samples); \ 776 | file_##type##_array(savestate_file, direct_sound_channel); \ 777 | file_##type##_array(savestate_file, gbc_sound_channel); \ 778 | } \ 779 | 780 | sound_savestate_builder(read); 781 | sound_savestate_builder(write_mem); 782 | 783 | -------------------------------------------------------------------------------- /sound.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef SOUND_H 21 | #define SOUND_H 22 | 23 | #define BUFFER_SIZE 65536 24 | 25 | // A lot of sound cards on PC can't handle such small buffers but this 26 | // seems to work well on PSP. 27 | 28 | #ifdef PSP_BUILD 29 | 30 | #define SOUND_BUFFER_SIZE 4096 31 | 32 | #else 33 | 34 | #define SOUND_BUFFER_SIZE 16384 35 | 36 | #endif 37 | 38 | typedef enum 39 | { 40 | DIRECT_SOUND_INACTIVE, 41 | DIRECT_SOUND_RIGHT, 42 | DIRECT_SOUND_LEFT, 43 | DIRECT_SOUND_LEFTRIGHT 44 | } direct_sound_status_type; 45 | 46 | typedef enum 47 | { 48 | DIRECT_SOUND_VOLUME_50, 49 | DIRECT_SOUND_VOLUME_100 50 | } direct_sound_volume_type; 51 | 52 | typedef struct 53 | { 54 | s8 fifo[32]; 55 | u32 fifo_base; 56 | u32 fifo_top; 57 | fixed16_16 fifo_fractional; 58 | // The + 1 is to give some extra room for linear interpolation 59 | // when wrapping around. 60 | u32 buffer_index; 61 | direct_sound_status_type status; 62 | direct_sound_volume_type volume; 63 | u32 last_cpu_ticks; 64 | } direct_sound_struct; 65 | 66 | typedef enum 67 | { 68 | GBC_SOUND_INACTIVE, 69 | GBC_SOUND_RIGHT, 70 | GBC_SOUND_LEFT, 71 | GBC_SOUND_LEFTRIGHT 72 | } gbc_sound_status_type; 73 | 74 | 75 | typedef struct 76 | { 77 | u32 rate; 78 | fixed16_16 frequency_step; 79 | fixed16_16 sample_index; 80 | fixed16_16 tick_counter; 81 | u32 total_volume; 82 | u32 envelope_initial_volume; 83 | u32 envelope_volume; 84 | u32 envelope_direction; 85 | u32 envelope_status; 86 | u32 envelope_step; 87 | u32 envelope_ticks; 88 | u32 envelope_initial_ticks; 89 | u32 sweep_status; 90 | u32 sweep_direction; 91 | u32 sweep_ticks; 92 | u32 sweep_initial_ticks; 93 | u32 sweep_shift; 94 | u32 length_status; 95 | u32 length_ticks; 96 | u32 noise_type; 97 | u32 wave_type; 98 | u32 wave_bank; 99 | u32 wave_volume; 100 | gbc_sound_status_type status; 101 | u32 active_flag; 102 | u32 master_enable; 103 | s8 *sample_data; 104 | } gbc_sound_struct; 105 | 106 | extern direct_sound_struct direct_sound_channel[2]; 107 | extern gbc_sound_struct gbc_sound_channel[4]; 108 | extern s8 square_pattern_duty[4][8]; 109 | extern u32 gbc_sound_master_volume_left; 110 | extern u32 gbc_sound_master_volume_right; 111 | extern u32 gbc_sound_master_volume; 112 | 113 | extern u32 sound_frequency; 114 | extern u32 sound_on; 115 | 116 | extern u32 global_enable_audio; 117 | extern u32 enable_low_pass_filter; 118 | extern u32 audio_buffer_size_number; 119 | 120 | extern SDL_mutex *sound_mutex; 121 | extern SDL_cond *sound_cv; 122 | 123 | void sound_timer_queue8(u32 channel, u8 value); 124 | void sound_timer_queue16(u32 channel, u16 value); 125 | void sound_timer_queue32(u32 channel, u32 value); 126 | void sound_timer(fixed16_16 frequency_step, u32 channel); 127 | void sound_reset_fifo(u32 channel); 128 | void update_gbc_sound(u32 cpu_ticks); 129 | void init_sound(); 130 | void sound_write_mem_savestate(file_tag_type savestate_file); 131 | void sound_read_savestate(file_tag_type savestate_file); 132 | 133 | #define gbc_sound_tone_control_low(channel, address) \ 134 | { \ 135 | u32 initial_volume = (value >> 12) & 0x0F; \ 136 | u32 envelope_ticks = ((value >> 8) & 0x07) * 4; \ 137 | gbc_sound_channel[channel].length_ticks = 64 - (value & 0x3F); \ 138 | gbc_sound_channel[channel].sample_data = \ 139 | square_pattern_duty[(value >> 6) & 0x03]; \ 140 | gbc_sound_channel[channel].envelope_direction = (value >> 11) & 0x01; \ 141 | gbc_sound_channel[channel].envelope_initial_volume = initial_volume; \ 142 | gbc_sound_channel[channel].envelope_volume = initial_volume; \ 143 | gbc_sound_channel[channel].envelope_initial_ticks = envelope_ticks; \ 144 | gbc_sound_channel[channel].envelope_ticks = envelope_ticks; \ 145 | gbc_sound_channel[channel].envelope_status = (envelope_ticks != 0); \ 146 | gbc_sound_channel[channel].envelope_volume = initial_volume; \ 147 | gbc_sound_update = 1; \ 148 | address16(io_registers, address) = value; \ 149 | } \ 150 | 151 | #define gbc_sound_tone_control_high(channel, address) \ 152 | { \ 153 | u32 rate = value & 0x7FF; \ 154 | gbc_sound_channel[channel].rate = rate; \ 155 | gbc_sound_channel[channel].frequency_step = \ 156 | float_to_fp16_16(((131072.0 / (2048 - rate)) * 8.0) / sound_frequency); \ 157 | gbc_sound_channel[channel].length_status = (value >> 14) & 0x01; \ 158 | if(value & 0x8000) \ 159 | { \ 160 | gbc_sound_channel[channel].active_flag = 1; \ 161 | gbc_sound_channel[channel].sample_index -= float_to_fp16_16(1.0 / 12.0); \ 162 | gbc_sound_channel[channel].envelope_ticks = \ 163 | gbc_sound_channel[channel].envelope_initial_ticks; \ 164 | gbc_sound_channel[channel].envelope_volume = \ 165 | gbc_sound_channel[channel].envelope_initial_volume; \ 166 | } \ 167 | \ 168 | gbc_sound_update = 1; \ 169 | address16(io_registers, address) = value; \ 170 | } \ 171 | 172 | #define gbc_sound_tone_control_sweep() \ 173 | { \ 174 | u32 sweep_ticks = ((value >> 4) & 0x07) * 2; \ 175 | gbc_sound_channel[0].sweep_shift = value & 0x07; \ 176 | gbc_sound_channel[0].sweep_direction = (value >> 3) & 0x01; \ 177 | gbc_sound_channel[0].sweep_status = (value != 8); \ 178 | gbc_sound_channel[0].sweep_ticks = sweep_ticks; \ 179 | gbc_sound_channel[0].sweep_initial_ticks = sweep_ticks; \ 180 | gbc_sound_update = 1; \ 181 | address16(io_registers, 0x60) = value; \ 182 | } \ 183 | 184 | #define gbc_sound_wave_control() \ 185 | { \ 186 | gbc_sound_channel[2].wave_type = (value >> 5) & 0x01; \ 187 | gbc_sound_channel[2].wave_bank = (value >> 6) & 0x01; \ 188 | if(value & 0x80) \ 189 | { \ 190 | gbc_sound_channel[2].master_enable = 1; \ 191 | } \ 192 | else \ 193 | { \ 194 | gbc_sound_channel[2].master_enable = 0; \ 195 | } \ 196 | \ 197 | gbc_sound_update = 1; \ 198 | address16(io_registers, 0x70) = value; \ 199 | } \ 200 | 201 | static u32 gbc_sound_wave_volume[4] = { 0, 16384, 8192, 4096 }; 202 | 203 | #define gbc_sound_tone_control_low_wave() \ 204 | { \ 205 | gbc_sound_channel[2].length_ticks = 256 - (value & 0xFF); \ 206 | if((value >> 15) & 0x01) \ 207 | { \ 208 | gbc_sound_channel[2].wave_volume = 12288; \ 209 | } \ 210 | else \ 211 | { \ 212 | gbc_sound_channel[2].wave_volume = \ 213 | gbc_sound_wave_volume[(value >> 13) & 0x03]; \ 214 | } \ 215 | gbc_sound_update = 1; \ 216 | address16(io_registers, 0x72) = value; \ 217 | } \ 218 | 219 | #define gbc_sound_tone_control_high_wave() \ 220 | { \ 221 | u32 rate = value & 0x7FF; \ 222 | gbc_sound_channel[2].rate = rate; \ 223 | gbc_sound_channel[2].frequency_step = \ 224 | float_to_fp16_16((2097152.0 / (2048 - rate)) / sound_frequency); \ 225 | gbc_sound_channel[2].length_status = (value >> 14) & 0x01; \ 226 | if(value & 0x8000) \ 227 | { \ 228 | gbc_sound_channel[2].sample_index = 0; \ 229 | gbc_sound_channel[2].active_flag = 1; \ 230 | } \ 231 | gbc_sound_update = 1; \ 232 | address16(io_registers, 0x74) = value; \ 233 | } \ 234 | 235 | #define gbc_sound_noise_control() \ 236 | { \ 237 | u32 dividing_ratio = value & 0x07; \ 238 | u32 frequency_shift = (value >> 4) & 0x0F; \ 239 | if(dividing_ratio == 0) \ 240 | { \ 241 | gbc_sound_channel[3].frequency_step = \ 242 | float_to_fp16_16(1048576.0 / (1 << (frequency_shift + 1)) / \ 243 | sound_frequency); \ 244 | } \ 245 | else \ 246 | { \ 247 | gbc_sound_channel[3].frequency_step = \ 248 | float_to_fp16_16(524288.0 / (dividing_ratio * \ 249 | (1 << (frequency_shift + 1))) / sound_frequency); \ 250 | } \ 251 | gbc_sound_channel[3].noise_type = (value >> 3) & 0x01; \ 252 | gbc_sound_channel[3].length_status = (value >> 14) & 0x01; \ 253 | if(value & 0x8000) \ 254 | { \ 255 | gbc_sound_channel[3].sample_index = 0; \ 256 | gbc_sound_channel[3].active_flag = 1; \ 257 | gbc_sound_channel[3].envelope_ticks = \ 258 | gbc_sound_channel[3].envelope_initial_ticks; \ 259 | gbc_sound_channel[3].envelope_volume = \ 260 | gbc_sound_channel[3].envelope_initial_volume; \ 261 | } \ 262 | gbc_sound_update = 1; \ 263 | address16(io_registers, 0x7C) = value; \ 264 | } \ 265 | 266 | #define gbc_trigger_sound_channel(channel) \ 267 | gbc_sound_master_volume_right = value & 0x07; \ 268 | gbc_sound_master_volume_left = (value >> 4) & 0x07; \ 269 | gbc_sound_channel[channel].status = ((value >> (channel + 8)) & 0x01) | \ 270 | ((value >> (channel + 11)) & 0x03) \ 271 | 272 | #define gbc_trigger_sound() \ 273 | { \ 274 | gbc_trigger_sound_channel(0); \ 275 | gbc_trigger_sound_channel(1); \ 276 | gbc_trigger_sound_channel(2); \ 277 | gbc_trigger_sound_channel(3); \ 278 | address16(io_registers, 0x80) = value; \ 279 | } \ 280 | 281 | #define trigger_sound() \ 282 | { \ 283 | timer[0].direct_sound_channels = (((value >> 10) & 0x01) == 0) | \ 284 | ((((value >> 14) & 0x01) == 0) << 1); \ 285 | timer[1].direct_sound_channels = (((value >> 10) & 0x01) == 1) | \ 286 | ((((value >> 14) & 0x01) == 1) << 1); \ 287 | direct_sound_channel[0].volume = (value >> 2) & 0x01; \ 288 | direct_sound_channel[0].status = (value >> 8) & 0x03; \ 289 | direct_sound_channel[1].volume = (value >> 3) & 0x01; \ 290 | direct_sound_channel[1].status = (value >> 12) & 0x03; \ 291 | gbc_sound_master_volume = value & 0x03; \ 292 | \ 293 | if((value >> 11) & 0x01) \ 294 | sound_reset_fifo(0); \ 295 | if((value >> 15) & 0x01) \ 296 | sound_reset_fifo(1); \ 297 | address16(io_registers, 0x82) = value; \ 298 | } \ 299 | 300 | #define sound_on() \ 301 | if(value & 0x80) \ 302 | { \ 303 | if(sound_on != 1) \ 304 | { \ 305 | sound_on = 1; \ 306 | } \ 307 | } \ 308 | else \ 309 | { \ 310 | u32 i; \ 311 | for(i = 0; i < 4; i++) \ 312 | { \ 313 | gbc_sound_channel[i].active_flag = 0; \ 314 | } \ 315 | sound_on = 0; \ 316 | } \ 317 | address16(io_registers, 0x84) = \ 318 | (address16(io_registers, 0x84) & 0x000F) | (value & 0xFFF0); \ 319 | 320 | #define sound_update_frequency_step(timer_number) \ 321 | timer[timer_number].frequency_step = \ 322 | float_to_fp16_16(16777216.0 / (timer_reload * sound_frequency)) \ 323 | 324 | 325 | #endif 326 | -------------------------------------------------------------------------------- /video.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef VIDEO_H 21 | #define VIDEO_H 22 | 23 | void update_scanline(); 24 | void update_screen(); 25 | void init_video(); 26 | void video_resolution_large(); 27 | void video_resolution_small(); 28 | void print_string(const char *str, u16 fg_color, u16 bg_color, 29 | u32 x, u32 y); 30 | void print_string_pad(const char *str, u16 fg_color, u16 bg_color, 31 | u32 x, u32 y, u32 pad); 32 | void print_string_ext(const char *str, u16 fg_color, u16 bg_color, 33 | u32 x, u32 y, void *_dest_ptr, u32 pitch, u32 pad); 34 | void clear_screen(u16 color); 35 | void blit_to_screen(u16 *src, u32 w, u32 h, u32 x, u32 y); 36 | u16 *copy_screen(); 37 | void flip_screen(); 38 | void video_write_mem_savestate(file_tag_type savestate_file); 39 | void video_read_savestate(file_tag_type savestate_file); 40 | 41 | extern u32 frame_speed; 42 | 43 | extern s32 affine_reference_x[2]; 44 | extern s32 affine_reference_y[2]; 45 | 46 | typedef void (* tile_render_function)(u32 layer_number, u32 start, u32 end, 47 | void *dest_ptr); 48 | typedef void (* bitmap_render_function)(u32 start, u32 end, void *dest_ptr); 49 | 50 | typedef struct 51 | { 52 | tile_render_function normal_render_base; 53 | tile_render_function normal_render_transparent; 54 | tile_render_function alpha_render_base; 55 | tile_render_function alpha_render_transparent; 56 | tile_render_function color16_render_base; 57 | tile_render_function color16_render_transparent; 58 | tile_render_function color32_render_base; 59 | tile_render_function color32_render_transparent; 60 | } tile_layer_render_struct; 61 | 62 | typedef struct 63 | { 64 | bitmap_render_function normal_render; 65 | } bitmap_layer_render_struct; 66 | 67 | typedef enum 68 | { 69 | unscaled, 70 | scaled_aspect, 71 | fullscreen, 72 | } video_scale_type; 73 | 74 | typedef enum 75 | { 76 | filter_nearest, 77 | filter_bilinear 78 | } video_filter_type; 79 | 80 | extern video_scale_type screen_scale; 81 | extern video_scale_type current_scale; 82 | extern video_filter_type screen_filter; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /x86/Makefile: -------------------------------------------------------------------------------- 1 | # gpSP makefile 2 | # Gilead Kutnick - Exophase 3 | 4 | # Global definitions 5 | 6 | CC = gcc 7 | STRIP = strip 8 | AS = as 9 | 10 | PREFIX = /usr 11 | OBJS = main.o cpu.o memory.o video.o input.o sound.o \ 12 | cpu_threaded.o gui.o x86_stub.o cheats.o zip.o 13 | BIN = gpsp.exe 14 | 15 | # Platform specific definitions 16 | 17 | VPATH += .. 18 | CFLAGS += 19 | INCLUDES = -I${PREFIX}/include `sdl-config --cflags` 20 | LIBS = -L${PREFIX}/lib `sdl-config --libs` -mconsole -lz 21 | 22 | # Compilation: 23 | 24 | .SUFFIXES: .c .S 25 | 26 | %.o: %.c 27 | ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< 28 | 29 | %.o: %.S 30 | ${AS} -o $@ $< 31 | 32 | all: ${OBJS} 33 | ${CC} ${OBJS} ${LIBS} -o ${BIN} 34 | ${STRIP} ${BIN} 35 | 36 | clean: 37 | rm -f *.o ${BIN} 38 | 39 | -------------------------------------------------------------------------------- /x86/x86_stub.S: -------------------------------------------------------------------------------- 1 | # gameplaySP 2 | # 3 | # Copyright (C) 2006 Exophase 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License as 7 | # published by the Free Software Foundation; either version 2 of 8 | # the License, or (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | .align 4 20 | 21 | .global _x86_update_gba 22 | .global _x86_indirect_branch_arm 23 | .global _x86_indirect_branch_thumb 24 | .global _x86_indirect_branch_dual 25 | .global _execute_store_u8 26 | .global _execute_store_u16 27 | .global _execute_store_u32 28 | .global _execute_store_cpsr 29 | .global _execute_arm_translate 30 | .global _step_debug_x86 31 | 32 | .global _memory_map_read 33 | .global _memory_map_write 34 | .global _reg 35 | 36 | .global _oam_update 37 | 38 | .global _iwram 39 | .global _ewram 40 | .global _vram 41 | .global _oam_ram 42 | .global _bios_rom 43 | .global _io_registers 44 | 45 | .extern _spsr 46 | 47 | .equ REG_SP, (13 * 4) 48 | .equ REG_LR, (14 * 4) 49 | .equ REG_PC, (15 * 4) 50 | .equ REG_N_FLAG, (16 * 4) 51 | .equ REG_Z_FLAG, (17 * 4) 52 | .equ REG_C_FLAG, (18 * 4) 53 | .equ REG_V_FLAG, (19 * 4) 54 | .equ REG_CPSR, (20 * 4) 55 | .equ REG_SAVE, (21 * 4) 56 | .equ REG_SAVE2, (22 * 4) 57 | .equ REG_SAVE3, (23 * 4) 58 | .equ CPU_MODE, (29 * 4) 59 | .equ CPU_HALT_STATE, (30 * 4) 60 | .equ CHANGED_PC_STATUS, (31 * 4) 61 | 62 | # destroys ecx and edx 63 | 64 | .macro collapse_flag offset, shift 65 | mov _reg + \offset, %ecx 66 | shl $\shift, %ecx 67 | or %ecx, %edx 68 | .endm 69 | 70 | .macro collapse_flags 71 | xor %edx, %edx 72 | collapse_flag REG_N_FLAG, 31 73 | collapse_flag REG_Z_FLAG, 30 74 | collapse_flag REG_C_FLAG, 29 75 | collapse_flag REG_V_FLAG, 28 76 | mov REG_CPSR(%ebx), %ecx 77 | and $0xFF, %ecx 78 | or %ecx, %edx 79 | mov %edx, REG_CPSR(%ebx) 80 | .endm 81 | 82 | .macro extract_flag shift, offset 83 | mov REG_CPSR(%ebx), %edx 84 | shr $\shift, %edx 85 | and $0x01, %edx 86 | mov %edx, _reg + \offset 87 | .endm 88 | 89 | .macro extract_flags 90 | extract_flag 31, REG_N_FLAG 91 | extract_flag 30, REG_Z_FLAG 92 | extract_flag 29, REG_C_FLAG 93 | extract_flag 28, REG_V_FLAG 94 | .endm 95 | 96 | # Process a hardware event. Since an interrupt might be 97 | # raised we have to check if the PC has changed. 98 | 99 | # eax: current address 100 | 101 | st: 102 | .asciz "u\n" 103 | 104 | _x86_update_gba: 105 | mov %eax, REG_PC(%ebx) # current PC = eax 106 | collapse_flags # update cpsr, trashes ecx and edx 107 | 108 | call _update_gba # process the next event 109 | 110 | mov %eax, %edi # edi = new cycle count 111 | # did the PC change? 112 | cmpl $1, CHANGED_PC_STATUS(%ebx) 113 | je lookup_pc 114 | ret # if not, go back to caller 115 | 116 | # Perform this on an indirect branch that will definitely go to 117 | # ARM code, IE anything that changes the PC in ARM mode except 118 | # for BX and data processing to PC with the S bit set. 119 | 120 | # eax: GBA address to branch to 121 | # edi: Cycle counter 122 | 123 | _x86_indirect_branch_arm: 124 | call _block_lookup_address_arm 125 | jmp *%eax 126 | 127 | # For indirect branches that'll definitely go to Thumb. In 128 | # Thumb mode any indirect branches except for BX. 129 | 130 | _x86_indirect_branch_thumb: 131 | call _block_lookup_address_thumb 132 | jmp *%eax 133 | 134 | # For indirect branches that can go to either Thumb or ARM, 135 | # mainly BX (also data processing to PC with S bit set, be 136 | # sure to adjust the target with a 1 in the lowest bit for this) 137 | 138 | _x86_indirect_branch_dual: 139 | call _block_lookup_address_dual 140 | jmp *%eax 141 | 142 | 143 | # General ext memory routines 144 | 145 | ext_store_ignore: 146 | ret # ignore these writes 147 | 148 | write_epilogue: 149 | cmp $0, %eax # 0 return means nothing happened 150 | jz no_alert # if so we can leave 151 | 152 | collapse_flags # make sure flags are good for function call 153 | cmp $2, %eax # see if it was an SMC trigger 154 | je smc_write 155 | 156 | alert_loop: 157 | call _update_gba # process the next event 158 | 159 | # see if the halt status has changed 160 | mov CPU_HALT_STATE(%ebx), %edx 161 | 162 | cmp $0, %edx # 0 means it has 163 | jnz alert_loop # if not go again 164 | 165 | mov %eax, %edi # edi = new cycle count 166 | jmp lookup_pc # pc has definitely changed 167 | 168 | no_alert: 169 | ret 170 | 171 | ext_store_eeprom: 172 | jmp _write_eeprom # perform eeprom write 173 | 174 | 175 | # 8bit ext memory routines 176 | 177 | ext_store_io8: 178 | and $0x3FF, %eax # wrap around address 179 | and $0xFF, %edx 180 | call _write_io_register8 # perform 8bit I/O register write 181 | jmp write_epilogue # see if it requires any system update 182 | 183 | ext_store_palette8: 184 | and $0x3FE, %eax # wrap around address and align to 16bits 185 | jmp ext_store_palette16b # perform 16bit palette write 186 | 187 | ext_store_vram8: 188 | and $0x1FFFE, %eax # wrap around address and align to 16bits 189 | mov %dl, %dh # copy lower 8bits of value into full 16bits 190 | cmp $0x18000, %eax # see if address is in upper region 191 | jb ext_store_vram8b 192 | sub $0x8000, %eax # if so wrap down 193 | 194 | ext_store_vram8b: 195 | mov %dx, _vram(%eax) # perform 16bit store 196 | ret 197 | 198 | ext_store_oam8: 199 | movl $1, _oam_update # flag OAM update 200 | and $0x3FE, %eax # wrap around address and align to 16bits 201 | mov %dl, %dh # copy lower 8bits of value into full 16bits 202 | mov %dx, _oam_ram(%eax) # perform 16bit store 203 | ret 204 | 205 | ext_store_backup: 206 | and $0xFF, %edx # make value 8bit 207 | and $0xFFFF, %eax # mask address 208 | jmp _write_backup # perform backup write 209 | 210 | ext_store_u8_jtable: 211 | .long ext_store_ignore # 0x00 BIOS, ignore 212 | .long ext_store_ignore # 0x01 invalid, ignore 213 | .long ext_store_ignore # 0x02 EWRAM, should have been hit already 214 | .long ext_store_ignore # 0x03 IWRAM, should have been hit already 215 | .long ext_store_io8 # 0x04 I/O registers 216 | .long ext_store_palette8 # 0x05 Palette RAM 217 | .long ext_store_vram8 # 0x06 VRAM 218 | .long ext_store_oam8 # 0x07 OAM RAM 219 | .long ext_store_ignore # 0x08 gamepak (no RTC accepted in 8bit) 220 | .long ext_store_ignore # 0x09 gamepak, ignore 221 | .long ext_store_ignore # 0x0A gamepak, ignore 222 | .long ext_store_ignore # 0x0B gamepak, ignore 223 | .long ext_store_ignore # 0x0C gamepak, ignore 224 | .long ext_store_eeprom # 0x0D EEPROM (possibly) 225 | .long ext_store_backup # 0x0E Flash ROM/SRAM 226 | 227 | ext_store_u8: 228 | mov %eax, %ecx # ecx = address 229 | shr $24, %ecx # ecx = address >> 24 230 | cmp $15, %ecx 231 | ja ext_store_ignore 232 | # ecx = ext_store_u8_jtable[address >> 24] 233 | mov ext_store_u8_jtable(, %ecx, 4), %ecx 234 | jmp *%ecx # jump to table index 235 | 236 | # eax: address to write to 237 | # edx: value to write 238 | # ecx: current pc 239 | 240 | _execute_store_u8: 241 | mov %ecx, REG_PC(%ebx) # write out the PC 242 | mov %eax, %ecx # ecx = address 243 | test $0xF0000000, %ecx # check address range 244 | jnz ext_store_u8 # if above perform an extended write 245 | shr $15, %ecx # ecx = page number of address 246 | # load the corresponding memory map offset 247 | mov _memory_map_write(, %ecx, 4), %ecx 248 | test %ecx, %ecx # see if it's NULL 249 | jz ext_store_u8 # if so perform an extended write 250 | and $0x7FFF, %eax # isolate the lower 15bits of the address 251 | mov %dl, (%eax, %ecx) # store the value 252 | # check for self-modifying code 253 | testb $0xFF, -32768(%eax, %ecx) 254 | jne smc_write 255 | ret # return 256 | 257 | _execute_store_u16: 258 | mov %ecx, REG_PC(%ebx) # write out the PC 259 | and $~0x01, %eax # fix alignment 260 | mov %eax, %ecx # ecx = address 261 | test $0xF0000000, %ecx # check address range 262 | jnz ext_store_u16 # if above perform an extended write 263 | shr $15, %ecx # ecx = page number of address 264 | # load the corresponding memory map offset 265 | mov _memory_map_write(, %ecx, 4), %ecx 266 | test %ecx, %ecx # see if it's NULL 267 | jz ext_store_u16 # if so perform an extended write 268 | and $0x7FFF, %eax # isolate the lower 15bits of the address 269 | mov %dx, (%eax, %ecx) # store the value 270 | # check for self-modifying code 271 | testw $0xFFFF, -32768(%eax, %ecx) 272 | jne smc_write 273 | ret # return 274 | 275 | # 16bit ext memory routines 276 | 277 | ext_store_io16: 278 | and $0x3FF, %eax # wrap around address 279 | and $0xFFFF, %edx 280 | call _write_io_register16 # perform 16bit I/O register write 281 | jmp write_epilogue # see if it requires any system update 282 | 283 | ext_store_palette16: 284 | and $0x3FF, %eax # wrap around address 285 | 286 | ext_store_palette16b: # entry point for 8bit write 287 | mov %dx, _palette_ram(%eax) # write out palette value 288 | mov %edx, %ecx # cx = dx 289 | shl $11, %ecx # cx <<= 11 (red component is in high bits) 290 | mov %dh, %cl # bottom bits of cx = top bits of dx 291 | shr $2, %cl # move the blue component to the bottom of cl 292 | and $0x03E0, %dx # isolate green component of dx 293 | shl $1, %dx # make green component 6bits 294 | or %edx, %ecx # combine green component into ecx 295 | # write out the freshly converted palette value 296 | mov %cx, _palette_ram_converted(%eax) 297 | ret # done 298 | 299 | ext_store_vram16: 300 | and $0x1FFFF, %eax # wrap around address 301 | cmp $0x18000, %eax # see if address is in upper region 302 | jb ext_store_vram16b 303 | sub $0x8000, %eax # if so wrap down 304 | 305 | ext_store_vram16b: 306 | mov %dx, _vram(%eax) # perform 16bit store 307 | ret 308 | 309 | ext_store_oam16: 310 | movl $1, _oam_update # flag OAM update 311 | and $0x3FF, %eax # wrap around address 312 | mov %dx, _oam_ram(%eax) # perform 16bit store 313 | ret 314 | 315 | ext_store_rtc: 316 | and $0xFFFF, %edx # make value 16bit 317 | and $0xFF, %eax # mask address 318 | jmp _write_rtc # write out RTC register 319 | 320 | ext_store_u16_jtable: 321 | .long ext_store_ignore # 0x00 BIOS, ignore 322 | .long ext_store_ignore # 0x01 invalid, ignore 323 | .long ext_store_ignore # 0x02 EWRAM, should have been hit already 324 | .long ext_store_ignore # 0x03 IWRAM, should have been hit already 325 | .long ext_store_io16 # 0x04 I/O registers 326 | .long ext_store_palette16 # 0x05 Palette RAM 327 | .long ext_store_vram16 # 0x06 VRAM 328 | .long ext_store_oam16 # 0x07 OAM RAM 329 | .long ext_store_rtc # 0x08 gamepak or RTC 330 | .long ext_store_ignore # 0x09 gamepak, ignore 331 | .long ext_store_ignore # 0x0A gamepak, ignore 332 | .long ext_store_ignore # 0x0B gamepak, ignore 333 | .long ext_store_ignore # 0x0C gamepak, ignore 334 | .long ext_store_eeprom # 0x0D EEPROM (possibly) 335 | .long ext_store_ignore # 0x0E Flash ROM/SRAM must be 8bit 336 | 337 | ext_store_u16: 338 | mov %eax, %ecx # ecx = address 339 | shr $24, %ecx # ecx = address >> 24 340 | cmp $15, %ecx 341 | ja ext_store_ignore 342 | # ecx = ext_store_u16_jtable[address >> 24] 343 | mov ext_store_u16_jtable(, %ecx, 4), %ecx 344 | jmp *%ecx # jump to table index 345 | 346 | _execute_store_u32: 347 | mov %ecx, REG_PC(%ebx) # write out the PC 348 | and $~0x03, %eax # fix alignment 349 | mov %eax, %ecx # ecx = address 350 | test $0xF0000000, %ecx # check address range 351 | jnz ext_store_u32 # if above perform an extended write 352 | shr $15, %ecx # ecx = page number of address 353 | # load the corresponding memory map offset 354 | mov _memory_map_write(, %ecx, 4), %ecx 355 | test %ecx, %ecx # see if it's NULL 356 | jz ext_store_u32 # if so perform an extended write 357 | and $0x7FFF, %eax # isolate the lower 15bits of the address 358 | mov %edx, (%eax, %ecx) # store the value 359 | # check for self-modifying code 360 | testl $0xFFFFFFFF, -32768(%eax, %ecx) 361 | jne smc_write 362 | ret # return it 363 | 364 | # 32bit ext memory routines 365 | 366 | ext_store_io32: 367 | and $0x3FF, %eax # wrap around address 368 | call _write_io_register32 # perform 32bit I/O register write 369 | jmp write_epilogue # see if it requires any system update 370 | 371 | ext_store_palette32: 372 | and $0x3FF, %eax # wrap around address 373 | call ext_store_palette16b # write first 16bits 374 | add $2, %eax # go to next address 375 | shr $16, %edx # go to next 16bits 376 | jmp ext_store_palette16b # write next 16bits 377 | 378 | ext_store_vram32: 379 | and $0x1FFFF, %eax # wrap around address 380 | cmp $0x18000, %eax # see if address is in upper region 381 | jb ext_store_vram32b 382 | sub $0x8000, %eax # if so wrap down 383 | 384 | ext_store_vram32b: 385 | mov %edx, _vram(%eax) # perform 32bit store 386 | ret 387 | 388 | ext_store_oam32: 389 | movl $1, _oam_update # flag OAM update 390 | and $0x3FF, %eax # wrap around address 391 | mov %edx, _oam_ram(%eax) # perform 32bit store 392 | ret 393 | 394 | ext_store_u32_jtable: 395 | .long ext_store_ignore # 0x00 BIOS, ignore 396 | .long ext_store_ignore # 0x01 invalid, ignore 397 | .long ext_store_ignore # 0x02 EWRAM, should have been hit already 398 | .long ext_store_ignore # 0x03 IWRAM, should have been hit already 399 | .long ext_store_io32 # 0x04 I/O registers 400 | .long ext_store_palette32 # 0x05 Palette RAM 401 | .long ext_store_vram32 # 0x06 VRAM 402 | .long ext_store_oam32 # 0x07 OAM RAM 403 | .long ext_store_ignore # 0x08 gamepak, ignore (no RTC in 32bit) 404 | .long ext_store_ignore # 0x09 gamepak, ignore 405 | .long ext_store_ignore # 0x0A gamepak, ignore 406 | .long ext_store_ignore # 0x0B gamepak, ignore 407 | .long ext_store_ignore # 0x0C gamepak, ignore 408 | .long ext_store_eeprom # 0x0D EEPROM (possibly) 409 | .long ext_store_ignore # 0x0E Flash ROM/SRAM must be 8bit 410 | 411 | 412 | ext_store_u32: 413 | mov %eax, %ecx # ecx = address 414 | shr $24, %ecx # ecx = address >> 24 415 | cmp $15, %ecx 416 | ja ext_store_ignore 417 | # ecx = ext_store_u32_jtable[address >> 24] 418 | mov ext_store_u32_jtable(, %ecx, 4), %ecx 419 | jmp *%ecx 420 | 421 | # %eax = new_cpsr 422 | # %edx = store_mask 423 | 424 | _execute_store_cpsr: 425 | mov %edx, REG_SAVE(%ebx) # write out store_mask 426 | mov %ecx, REG_SAVE2(%ebx) # write out PC too 427 | mov %eax, %ecx # ecx = new_cpsr 428 | and %edx, %ecx # ecx = new_cpsr & store_mask 429 | mov REG_CPSR(%ebx), %eax # eax = cpsr 430 | not %edx # edx = ~store_mask 431 | and %edx, %eax # eax = cpsr & ~store_mask 432 | or %ecx, %eax # eax = new cpsr combined with old 433 | extract_flags # extract flags 434 | call _execute_store_cpsr_body # do the dirty work in this C function 435 | 436 | cmp $0, %eax # see if return value is 0 437 | jnz changed_pc_cpsr # might have changed the PC 438 | 439 | ret # return 440 | 441 | changed_pc_cpsr: 442 | add $4, %esp # get rid of current return address 443 | call _block_lookup_address_arm # lookup new PC 444 | jmp *%eax 445 | 446 | smc_write: 447 | call _flush_translation_cache_ram 448 | 449 | lookup_pc: 450 | add $4, %esp 451 | movl $0, CHANGED_PC_STATUS(%ebx) 452 | mov REG_PC(%ebx), %eax 453 | testl $0x20, REG_CPSR(%ebx) 454 | jz lookup_pc_arm 455 | 456 | lookup_pc_thumb: 457 | call _block_lookup_address_thumb 458 | jmp *%eax 459 | 460 | lookup_pc_arm: 461 | call _block_lookup_address_arm 462 | jmp *%eax 463 | 464 | # eax: cycle counter 465 | 466 | _execute_arm_translate: 467 | movl $_reg, %ebx # load base register 468 | extract_flags # load flag variables 469 | movl %eax, %edi # load edi cycle counter 470 | 471 | movl REG_PC(%ebx), %eax # load PC 472 | call _block_lookup_address_arm 473 | jmp *%eax # jump to it 474 | 475 | _step_debug_x86: 476 | collapse_flags 477 | # mov $100, %edi 478 | mov %edi, %edx 479 | jmp _step_debug 480 | 481 | .comm _memory_map_read 0x8000 482 | .comm _memory_map_write 0x8000 483 | .comm _reg 0x100 484 | 485 | 486 | -------------------------------------------------------------------------------- /zip.c: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * Copyright (C) 2006 SiberianSTAR 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License as 8 | * published by the Free Software Foundation; either version 2 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include 22 | #include "common.h" 23 | 24 | #define ZIP_BUFFER_SIZE (128 * 1024) 25 | 26 | struct SZIPFileDataDescriptor 27 | { 28 | s32 CRC32; 29 | s32 CompressedSize; 30 | s32 UncompressedSize; 31 | } __attribute__((packed)); 32 | 33 | struct SZIPFileHeader 34 | { 35 | s32 Sig; 36 | s16 VersionToExtract; 37 | s16 GeneralBitFlag; 38 | s16 CompressionMethod; 39 | s16 LastModFileTime; 40 | s16 LastModFileDate; 41 | struct SZIPFileDataDescriptor DataDescriptor; 42 | s16 FilenameLength; 43 | s16 ExtraFieldLength; 44 | } __attribute__((packed)); 45 | 46 | u32 load_file_zip(char *filename) 47 | { 48 | struct SZIPFileHeader data; 49 | u8 tmp[1024]; 50 | s32 retval = -1; 51 | u8 *buffer = NULL; 52 | u8 *cbuffer; 53 | u8 *ext; 54 | 55 | file_open(fd, filename, read); 56 | 57 | if(!file_check_valid(fd)) 58 | return -1; 59 | 60 | while(1) 61 | { 62 | file_read(fd, &data, sizeof(struct SZIPFileHeader)); 63 | 64 | // zip file end 65 | if(data.Sig != 0x04034b50) 66 | break; 67 | 68 | file_read(fd, tmp, data.FilenameLength); 69 | tmp[data.FilenameLength] = 0; // end string 70 | 71 | if(data.ExtraFieldLength) 72 | file_seek(fd, data.ExtraFieldLength, SEEK_CUR); 73 | 74 | if(data.GeneralBitFlag & 0x0008) 75 | { 76 | file_read(fd, &data.DataDescriptor, 77 | sizeof(struct SZIPFileDataDescriptor)); 78 | } 79 | 80 | ext = strrchr(tmp, '.') + 1; 81 | 82 | // file is too big 83 | if(data.DataDescriptor.UncompressedSize > gamepak_ram_buffer_size) 84 | goto outcode; 85 | 86 | if(!strcasecmp(ext, "bin") || !strcasecmp(ext, "gba")) 87 | { 88 | buffer = gamepak_rom; 89 | 90 | // ok, found 91 | switch(data.CompressionMethod) 92 | { 93 | case 0: 94 | retval = data.DataDescriptor.UncompressedSize; 95 | file_read(fd, buffer, retval); 96 | 97 | goto outcode; 98 | 99 | case 8: 100 | { 101 | z_stream stream; 102 | s32 err; 103 | 104 | cbuffer = malloc(ZIP_BUFFER_SIZE); 105 | 106 | stream.next_in = (Bytef*)cbuffer; 107 | stream.avail_in = (u32)ZIP_BUFFER_SIZE; 108 | 109 | stream.next_out = (Bytef*)buffer; 110 | retval = stream.avail_out = data.DataDescriptor.UncompressedSize; 111 | 112 | stream.zalloc = (alloc_func)0; 113 | stream.zfree = (free_func)0; 114 | 115 | err = inflateInit2(&stream, -MAX_WBITS); 116 | 117 | file_read(fd, cbuffer, ZIP_BUFFER_SIZE); 118 | 119 | if(err == Z_OK) 120 | { 121 | while(err != Z_STREAM_END) 122 | { 123 | err = inflate(&stream, Z_SYNC_FLUSH); 124 | if(err == Z_BUF_ERROR) 125 | { 126 | stream.avail_in = ZIP_BUFFER_SIZE; 127 | stream.next_in = (Bytef*)cbuffer; 128 | file_read(fd, cbuffer, ZIP_BUFFER_SIZE); 129 | } 130 | } 131 | err = Z_OK; 132 | inflateEnd(&stream); 133 | } 134 | free(cbuffer); 135 | goto outcode; 136 | } 137 | } 138 | } 139 | } 140 | 141 | outcode: 142 | file_close(fd); 143 | 144 | return retval; 145 | } 146 | -------------------------------------------------------------------------------- /zip.h: -------------------------------------------------------------------------------- 1 | /* gameplaySP 2 | * 3 | * Copyright (C) 2006 Exophase 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef COMMON_H 21 | #define COMMON_H 22 | 23 | u32 load_file_zip(char *filename); 24 | 25 | #endif 26 | 27 | --------------------------------------------------------------------------------