1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7#include <string>
8#include <numeric>
9#include <assert.h>
10
11#ifdef UNZIP_SUPPORT
12# ifdef SYSTEM_ZIP
13# include <minizip/unzip.h>
14# else
15# include "unzip/unzip.h"
16# endif
17#endif
18
19#ifdef JMA_SUPPORT
20#include "jma/s9x-jma.h"
21#endif
22
23#include <ctype.h>
24#include <sys/stat.h>
25
26#include "snes9x.h"
27#include "memmap.h"
28#include "apu/apu.h"
29#include "fxemu.h"
30#include "sdd1.h"
31#include "srtc.h"
32#include "controls.h"
33#include "cheats.h"
34#include "movie.h"
35#include "display.h"
36#include "sha256.h"
37
38#ifndef SET_UI_COLOR
39#define SET_UI_COLOR(r, g, b) ;
40#endif
41
42#ifndef max
43#define max(a, b) (((a) > (b)) ? (a) : (b))
44#endif
45
46#ifndef min
47#define min(a, b) (((a) < (b)) ? (a) : (b))
48#endif
49
50static bool8 stopMovie = TRUE;
51static char LastRomFilename[PATH_MAX + 1] = "";
52
53// from NSRT
54static const char *nintendo_licensees[] =
55{
56 "Unlicensed",
57 "Nintendo",
58 "Rocket Games/Ajinomoto",
59 "Imagineer-Zoom",
60 "Gray Matter",
61 "Zamuse",
62 "Falcom",
63 NULL,
64 "Capcom",
65 "Hot B Co.",
66 "Jaleco",
67 "Coconuts Japan",
68 "Coconuts Japan/G.X.Media",
69 "Micronet",
70 "Technos",
71 "Mebio Software",
72 "Shouei System",
73 "Starfish",
74 NULL,
75 "Mitsui Fudosan/Dentsu",
76 NULL,
77 "Warashi Inc.",
78 NULL,
79 "Nowpro",
80 NULL,
81 "Game Village",
82 "IE Institute",
83 NULL,
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 NULL,
91 NULL,
92 "Banarex",
93 "Starfish",
94 "Infocom",
95 "Electronic Arts Japan",
96 NULL,
97 "Cobra Team",
98 "Human/Field",
99 "KOEI",
100 "Hudson Soft",
101 "S.C.P./Game Village",
102 "Yanoman",
103 NULL,
104 "Tecmo Products",
105 "Japan Glary Business",
106 "Forum/OpenSystem",
107 "Virgin Games (Japan)",
108 "SMDE",
109 "Yojigen",
110 NULL,
111 "Daikokudenki",
112 NULL,
113 NULL,
114 NULL,
115 NULL,
116 NULL,
117 "Creatures Inc.",
118 "TDK Deep Impresion",
119 NULL,
120 NULL,
121 NULL,
122 NULL,
123 NULL,
124 NULL,
125 NULL,
126 NULL,
127 NULL,
128 "Destination Software/KSS",
129 "Sunsoft/Tokai Engineering",
130 "POW (Planning Office Wada)/VR 1 Japan",
131 "Micro World",
132 NULL,
133 "San-X",
134 "Enix",
135 "Loriciel/Electro Brain",
136 "Kemco Japan",
137 "Seta Co.,Ltd.",
138 "Culture Brain",
139 "Irem Corp.",
140 "Palsoft",
141 "Visit Co., Ltd.",
142 "Intec",
143 "System Sacom",
144 "Poppo",
145 "Ubisoft Japan",
146 NULL,
147 "Media Works",
148 "NEC InterChannel",
149 "Tam",
150 "Gajin/Jordan",
151 "Smilesoft",
152 NULL,
153 NULL,
154 "Mediakite",
155 NULL,
156 NULL,
157 NULL,
158 NULL,
159 NULL,
160 NULL,
161 NULL,
162 NULL,
163 NULL,
164 "Viacom",
165 "Carrozzeria",
166 "Dynamic",
167 NULL,
168 "Magifact",
169 "Hect",
170 "Codemasters",
171 "Taito/GAGA Communications",
172 "Laguna",
173 "Telstar Fun & Games/Event/Taito",
174 NULL,
175 "Arcade Zone Ltd.",
176 "Entertainment International/Empire Software",
177 "Loriciel",
178 "Gremlin Graphics",
179 NULL,
180 NULL,
181 NULL,
182 NULL,
183 NULL,
184 NULL,
185 NULL,
186 NULL,
187 NULL,
188 NULL,
189 NULL,
190 NULL,
191 NULL,
192 NULL,
193 NULL,
194 NULL,
195 NULL,
196 NULL,
197 NULL,
198 NULL,
199 NULL,
200 "Seika Corp.",
201 "UBI SOFT Entertainment Software",
202 "Sunsoft US",
203 NULL,
204 "Life Fitness",
205 NULL,
206 "System 3",
207 "Spectrum Holobyte",
208 NULL,
209 "Irem",
210 NULL,
211 "Raya Systems",
212 "Renovation Products",
213 "Malibu Games",
214 NULL,
215 "Eidos/U.S. Gold",
216 "Playmates Interactive",
217 NULL,
218 NULL,
219 "Fox Interactive",
220 "Time Warner Interactive",
221 NULL,
222 NULL,
223 NULL,
224 NULL,
225 NULL,
226 "Disney Interactive",
227 NULL,
228 "Black Pearl",
229 NULL,
230 "Advanced Productions",
231 NULL,
232 NULL,
233 "GT Interactive",
234 "RARE",
235 "Crave Entertainment",
236 "Absolute Entertainment",
237 "Acclaim",
238 "Activision",
239 "American Sammy",
240 "Take 2/GameTek",
241 "Hi Tech",
242 "LJN Ltd.",
243 NULL,
244 "Mattel",
245 NULL,
246 "Mindscape/Red Orb Entertainment",
247 "Romstar",
248 "Taxan",
249 "Midway/Tradewest",
250 NULL,
251 "American Softworks Corp.",
252 "Majesco Sales Inc.",
253 "3DO",
254 NULL,
255 NULL,
256 "Hasbro",
257 "NewKidCo",
258 "Telegames",
259 "Metro3D",
260 NULL,
261 "Vatical Entertainment",
262 "LEGO Media",
263 NULL,
264 "Xicat Interactive",
265 "Cryo Interactive",
266 NULL,
267 NULL,
268 "Red Storm Entertainment",
269 "Microids",
270 NULL,
271 "Conspiracy/Swing",
272 "Titus",
273 "Virgin Interactive",
274 "Maxis",
275 NULL,
276 "LucasArts Entertainment",
277 NULL,
278 NULL,
279 "Ocean",
280 NULL,
281 "Electronic Arts",
282 NULL,
283 "Laser Beam",
284 NULL,
285 NULL,
286 "Elite Systems",
287 "Electro Brain",
288 "The Learning Company",
289 "BBC",
290 NULL,
291 "Software 2000",
292 NULL,
293 "BAM! Entertainment",
294 "Studio 3",
295 NULL,
296 NULL,
297 NULL,
298 "Classified Games",
299 NULL,
300 "TDK Mediactive",
301 NULL,
302 "DreamCatcher",
303 "JoWood Produtions",
304 "SEGA",
305 "Wannado Edition",
306 "LSP (Light & Shadow Prod.)",
307 "ITE Media",
308 "Infogrames",
309 "Interplay",
310 "JVC (US)",
311 "Parker Brothers",
312 NULL,
313 "SCI (Sales Curve Interactive)/Storm",
314 NULL,
315 NULL,
316 "THQ Software",
317 "Accolade Inc.",
318 "Triffix Entertainment",
319 NULL,
320 "Microprose Software",
321 "Universal Interactive/Sierra/Simon & Schuster",
322 NULL,
323 "Kemco",
324 "Rage Software",
325 "Encore",
326 NULL,
327 "Zoo",
328 "Kiddinx",
329 "Simon & Schuster Interactive",
330 "Asmik Ace Entertainment Inc./AIA",
331 "Empire Interactive",
332 NULL,
333 NULL,
334 "Jester Interactive",
335 NULL,
336 "Rockstar Games",
337 "Scholastic",
338 "Ignition Entertainment",
339 "Summitsoft",
340 "Stadlbauer",
341 NULL,
342 NULL,
343 NULL,
344 "Misawa",
345 "Teichiku",
346 "Namco Ltd.",
347 "LOZC",
348 "KOEI",
349 NULL,
350 "Tokuma Shoten Intermedia",
351 "Tsukuda Original",
352 "DATAM-Polystar",
353 NULL,
354 NULL,
355 "Bullet-Proof Software",
356 "Vic Tokai Inc.",
357 NULL,
358 "Character Soft",
359 "I'Max",
360 "Saurus",
361 NULL,
362 NULL,
363 "General Entertainment",
364 NULL,
365 NULL,
366 "I'Max",
367 "Success",
368 NULL,
369 "SEGA Japan",
370 NULL,
371 NULL,
372 NULL,
373 NULL,
374 NULL,
375 NULL,
376 NULL,
377 NULL,
378 NULL,
379 NULL,
380 "Takara",
381 "Chun Soft",
382 "Video System Co., Ltd./McO'River",
383 "BEC",
384 NULL,
385 "Varie",
386 "Yonezawa/S'pal",
387 "Kaneko",
388 NULL,
389 "Victor Interactive Software/Pack-in-Video",
390 "Nichibutsu/Nihon Bussan",
391 "Tecmo",
392 "Imagineer",
393 NULL,
394 NULL,
395 "Nova",
396 "Den'Z",
397 "Bottom Up",
398 NULL,
399 "TGL (Technical Group Laboratory)",
400 NULL,
401 "Hasbro Japan",
402 NULL,
403 "Marvelous Entertainment",
404 NULL,
405 "Keynet Inc.",
406 "Hands-On Entertainment",
407 NULL,
408 NULL,
409 NULL,
410 NULL,
411 NULL,
412 NULL,
413 NULL,
414 NULL,
415 NULL,
416 "Telenet",
417 "Hori",
418 NULL,
419 NULL,
420 "Konami",
421 "K.Amusement Leasing Co.",
422 "Kawada",
423 "Takara",
424 NULL,
425 "Technos Japan Corp.",
426 "JVC (Europe/Japan)/Victor Musical Industries",
427 NULL,
428 "Toei Animation",
429 "Toho",
430 NULL,
431 "Namco",
432 "Media Rings Corp.",
433 "J-Wing",
434 NULL,
435 "Pioneer LDC",
436 "KID",
437 "Mediafactory",
438 NULL,
439 NULL,
440 NULL,
441 "Infogrames Hudson",
442 NULL,
443 NULL,
444 NULL,
445 NULL,
446 NULL,
447 NULL,
448 NULL,
449 NULL,
450 NULL,
451 NULL,
452 "Acclaim Japan",
453 "ASCII Co./Nexoft",
454 "Bandai",
455 NULL,
456 "Enix",
457 NULL,
458 "HAL Laboratory/Halken",
459 "SNK",
460 NULL,
461 "Pony Canyon Hanbai",
462 "Culture Brain",
463 "Sunsoft",
464 "Toshiba EMI",
465 "Sony Imagesoft",
466 NULL,
467 "Sammy",
468 "Magical",
469 "Visco",
470 NULL,
471 "Compile",
472 NULL,
473 "MTO Inc.",
474 NULL,
475 "Sunrise Interactive",
476 NULL,
477 "Global A Entertainment",
478 "Fuuki",
479 NULL,
480 NULL,
481 NULL,
482 NULL,
483 NULL,
484 NULL,
485 NULL,
486 NULL,
487 NULL,
488 "Taito",
489 NULL,
490 "Kemco",
491 "Square",
492 "Tokuma Shoten",
493 "Data East",
494 "Tonkin House",
495 NULL,
496 "KOEI",
497 NULL,
498 "Konami/Ultra/Palcom",
499 "NTVIC/VAP",
500 "Use Co., Ltd.",
501 "Meldac",
502 "Pony Canyon (Japan)/FCI (US)",
503 "Angel/Sotsu Agency/Sunrise",
504 "Yumedia/Aroma Co., Ltd.",
505 NULL,
506 NULL,
507 "Boss",
508 "Axela/Crea-Tech",
509 "Sekaibunka-Sha/Sumire kobo/Marigul Management Inc.",
510 "Konami Computer Entertainment Osaka",
511 NULL,
512 NULL,
513 "Enterbrain",
514 NULL,
515 NULL,
516 NULL,
517 NULL,
518 NULL,
519 NULL,
520 NULL,
521 NULL,
522 NULL,
523 NULL,
524 "Taito/Disco",
525 "Sofel",
526 "Quest Corp.",
527 "Sigma",
528 "Ask Kodansha",
529 NULL,
530 "Naxat",
531 "Copya System",
532 "Capcom Co., Ltd.",
533 "Banpresto",
534 "TOMY",
535 "Acclaim/LJN Japan",
536 NULL,
537 "NCS",
538 "Human Entertainment",
539 "Altron",
540 "Jaleco",
541 "Gaps Inc.",
542 NULL,
543 NULL,
544 NULL,
545 NULL,
546 NULL,
547 "Elf",
548 NULL,
549 NULL,
550 NULL,
551 NULL,
552 NULL,
553 NULL,
554 NULL,
555 NULL,
556 NULL,
557 NULL,
558 NULL,
559 NULL,
560 "Jaleco",
561 NULL,
562 "Yutaka",
563 "Varie",
564 "T&ESoft",
565 "Epoch Co., Ltd.",
566 NULL,
567 "Athena",
568 "Asmik",
569 "Natsume",
570 "King Records",
571 "Atlus",
572 "Epic/Sony Records (Japan)",
573 NULL,
574 "IGS (Information Global Service)",
575 NULL,
576 "Chatnoir",
577 "Right Stuff",
578 NULL,
579 "NTT COMWARE",
580 NULL,
581 "Spike",
582 "Konami Computer Entertainment Tokyo",
583 "Alphadream Corp.",
584 NULL,
585 "Sting",
586 NULL,
587 NULL,
588 NULL,
589 NULL,
590 NULL,
591 NULL,
592 NULL,
593 NULL,
594 NULL,
595 NULL,
596 "A Wave",
597 "Motown Software",
598 "Left Field Entertainment",
599 "Extreme Entertainment Group",
600 "TecMagik",
601 NULL,
602 NULL,
603 NULL,
604 NULL,
605 "Cybersoft",
606 NULL,
607 "Psygnosis",
608 NULL,
609 NULL,
610 "Davidson/Western Tech.",
611 "Unlicensed",
612 NULL,
613 NULL,
614 NULL,
615 NULL,
616 "The Game Factory Europe",
617 "Hip Games",
618 "Aspyr",
619 NULL,
620 NULL,
621 "Mastiff",
622 "iQue",
623 "Digital Tainment Pool",
624 "XS Games",
625 "Daiwon",
626 NULL,
627 NULL,
628 NULL,
629 NULL,
630 NULL,
631 NULL,
632 NULL,
633 "PCCW Japan",
634 NULL,
635 NULL,
636 "KiKi Co. Ltd.",
637 "Open Sesame Inc.",
638 "Sims",
639 "Broccoli",
640 "Avex",
641 "D3 Publisher",
642 NULL,
643 "Konami Computer Entertainment Japan",
644 NULL,
645 "Square-Enix",
646 "KSG",
647 "Micott & Basara Inc.",
648 NULL,
649 "Orbital Media",
650 NULL,
651 NULL,
652 NULL,
653 NULL,
654 NULL,
655 NULL,
656 NULL,
657 NULL,
658 NULL,
659 NULL,
660 NULL,
661 NULL,
662 NULL,
663 NULL,
664 NULL,
665 NULL,
666 "The Game Factory USA",
667 NULL,
668 NULL,
669 "Treasure",
670 "Aruze",
671 "Ertain",
672 "SNK Playmore",
673 NULL,
674 NULL,
675 NULL,
676 NULL,
677 NULL,
678 NULL,
679 NULL,
680 NULL,
681 NULL,
682 NULL,
683 NULL,
684 NULL,
685 NULL,
686 NULL,
687 NULL,
688 NULL,
689 NULL,
690 NULL,
691 NULL,
692 NULL,
693 NULL,
694 NULL,
695 NULL,
696 NULL,
697 NULL,
698 NULL,
699 NULL,
700 NULL,
701 NULL,
702 NULL,
703 NULL,
704 NULL,
705 NULL,
706 NULL,
707 NULL,
708 NULL,
709 NULL,
710 NULL,
711 NULL,
712 NULL,
713 NULL,
714 NULL,
715 NULL,
716 NULL,
717 NULL,
718 NULL,
719 NULL,
720 NULL,
721 "Yojigen"
722};
723
724static const uint32 crc32Table[256] =
725{
726 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
727 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
728 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
729 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
730 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
731 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
732 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
733 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
734 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
735 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
736 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
737 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
738 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
739 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
740 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
741 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
742 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
743 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
744 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
745 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
746 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
747 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
748 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
749 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
750 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
751 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
752 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
753 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
754 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
755 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
756 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
757 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
758 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
759 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
760 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
761 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
762 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
763 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
764 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
765 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
766 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
767 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
768 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
769};
770
771static void S9xDeinterleaveType1 (int, uint8 *);
772static void S9xDeinterleaveType2 (int, uint8 *);
773static void S9xDeinterleaveGD24 (int, uint8 *);
774static bool8 allASCII (uint8 *, int);
775static bool8 is_SufamiTurbo_BIOS (const uint8 *, uint32);
776static bool8 is_SufamiTurbo_Cart (const uint8 *, uint32);
777static bool8 is_BSCart_BIOS (const uint8 *, uint32);
778static bool8 is_BSCartSA1_BIOS(const uint8 *, uint32);
779static bool8 is_GNEXT_Add_On (const uint8 *, uint32);
780static uint32 caCRC32 (uint8 *, uint32, uint32 crc32 = 0xffffffff);
781static bool8 ReadUPSPatch (Stream *, long, int32 &);
782static long ReadInt (Stream *, unsigned);
783static bool8 ReadIPSPatch (Stream *, long, int32 &);
784#ifdef UNZIP_SUPPORT
785static int unzFindExtension (unzFile &, const char *, bool restart = TRUE, bool print = TRUE, bool allowExact = FALSE);
786#endif
787
788// deinterleave
789
790static void S9xDeinterleaveType1 (int size, uint8 *base)
791{
792 Settings.DisplayColor = BUILD_PIXEL(0, 31, 0);
793 SET_UI_COLOR(0, 255, 0);
794
795 uint8 blocks[256];
796 int nblocks = size >> 16;
797
798 for (int i = 0; i < nblocks; i++)
799 {
800 blocks[i * 2] = i + nblocks;
801 blocks[i * 2 + 1] = i;
802 }
803
804 uint8 *tmp = (uint8 *) malloc(0x8000);
805 if (tmp)
806 {
807 for (int i = 0; i < nblocks * 2; i++)
808 {
809 for (int j = i; j < nblocks * 2; j++)
810 {
811 if (blocks[j] == i)
812 {
813 memmove(tmp, &base[blocks[j] * 0x8000], 0x8000);
814 memmove(&base[blocks[j] * 0x8000], &base[blocks[i] * 0x8000], 0x8000);
815 memmove(&base[blocks[i] * 0x8000], tmp, 0x8000);
816 uint8 b = blocks[j];
817 blocks[j] = blocks[i];
818 blocks[i] = b;
819 break;
820 }
821 }
822 }
823
824 free(tmp);
825 }
826}
827
828static void S9xDeinterleaveType2 (int size, uint8 *base)
829{
830 // for odd Super FX images
831 Settings.DisplayColor = BUILD_PIXEL(31, 14, 6);
832 SET_UI_COLOR(255, 119, 25);
833
834 uint8 blocks[256];
835 int nblocks = size >> 16;
836 int step = 64;
837
838 while (nblocks <= step)
839 step >>= 1;
840 nblocks = step;
841
842 for (int i = 0; i < nblocks * 2; i++)
843 blocks[i] = (i & ~0xf) | ((i & 3) << 2) | ((i & 12) >> 2);
844
845 uint8 *tmp = (uint8 *) malloc(0x10000);
846 if (tmp)
847 {
848 for (int i = 0; i < nblocks * 2; i++)
849 {
850 for (int j = i; j < nblocks * 2; j++)
851 {
852 if (blocks[j] == i)
853 {
854 memmove(tmp, &base[blocks[j] * 0x10000], 0x10000);
855 memmove(&base[blocks[j] * 0x10000], &base[blocks[i] * 0x10000], 0x10000);
856 memmove(&base[blocks[i] * 0x10000], tmp, 0x10000);
857 uint8 b = blocks[j];
858 blocks[j] = blocks[i];
859 blocks[i] = b;
860 break;
861 }
862 }
863 }
864
865 free(tmp);
866 }
867}
868
869static void S9xDeinterleaveGD24 (int size, uint8 *base)
870{
871 // for 24Mb images dumped with Game Doctor
872 if (size != 0x300000)
873 return;
874
875 Settings.DisplayColor = BUILD_PIXEL(0, 31, 31);
876 SET_UI_COLOR(0, 255, 255);
877
878 uint8 *tmp = (uint8 *) malloc(0x80000);
879 if (tmp)
880 {
881 memmove(tmp, &base[0x180000], 0x80000);
882 memmove(&base[0x180000], &base[0x200000], 0x80000);
883 memmove(&base[0x200000], &base[0x280000], 0x80000);
884 memmove(&base[0x280000], tmp, 0x80000);
885
886 free(tmp);
887
888 S9xDeinterleaveType1(size, base);
889 }
890}
891
892// allocation and deallocation
893
894bool8 CMemory::Init (void)
895{
896 RAM = (uint8 *) malloc(0x20000);
897 SRAM = (uint8 *) malloc(0x20000);
898 VRAM = (uint8 *) malloc(0x10000);
899 ROM = (uint8 *) malloc(MAX_ROM_SIZE + 0x200 + 0x8000);
900
901 IPPU.TileCache[TILE_2BIT] = (uint8 *) malloc(MAX_2BIT_TILES * 64);
902 IPPU.TileCache[TILE_4BIT] = (uint8 *) malloc(MAX_4BIT_TILES * 64);
903 IPPU.TileCache[TILE_8BIT] = (uint8 *) malloc(MAX_8BIT_TILES * 64);
904 IPPU.TileCache[TILE_2BIT_EVEN] = (uint8 *) malloc(MAX_2BIT_TILES * 64);
905 IPPU.TileCache[TILE_2BIT_ODD] = (uint8 *) malloc(MAX_2BIT_TILES * 64);
906 IPPU.TileCache[TILE_4BIT_EVEN] = (uint8 *) malloc(MAX_4BIT_TILES * 64);
907 IPPU.TileCache[TILE_4BIT_ODD] = (uint8 *) malloc(MAX_4BIT_TILES * 64);
908
909 IPPU.TileCached[TILE_2BIT] = (uint8 *) malloc(MAX_2BIT_TILES);
910 IPPU.TileCached[TILE_4BIT] = (uint8 *) malloc(MAX_4BIT_TILES);
911 IPPU.TileCached[TILE_8BIT] = (uint8 *) malloc(MAX_8BIT_TILES);
912 IPPU.TileCached[TILE_2BIT_EVEN] = (uint8 *) malloc(MAX_2BIT_TILES);
913 IPPU.TileCached[TILE_2BIT_ODD] = (uint8 *) malloc(MAX_2BIT_TILES);
914 IPPU.TileCached[TILE_4BIT_EVEN] = (uint8 *) malloc(MAX_4BIT_TILES);
915 IPPU.TileCached[TILE_4BIT_ODD] = (uint8 *) malloc(MAX_4BIT_TILES);
916
917 if (!RAM || !SRAM || !VRAM || !ROM ||
918 !IPPU.TileCache[TILE_2BIT] ||
919 !IPPU.TileCache[TILE_4BIT] ||
920 !IPPU.TileCache[TILE_8BIT] ||
921 !IPPU.TileCache[TILE_2BIT_EVEN] ||
922 !IPPU.TileCache[TILE_2BIT_ODD] ||
923 !IPPU.TileCache[TILE_4BIT_EVEN] ||
924 !IPPU.TileCache[TILE_4BIT_ODD] ||
925 !IPPU.TileCached[TILE_2BIT] ||
926 !IPPU.TileCached[TILE_4BIT] ||
927 !IPPU.TileCached[TILE_8BIT] ||
928 !IPPU.TileCached[TILE_2BIT_EVEN] ||
929 !IPPU.TileCached[TILE_2BIT_ODD] ||
930 !IPPU.TileCached[TILE_4BIT_EVEN] ||
931 !IPPU.TileCached[TILE_4BIT_ODD])
932 {
933 Deinit();
934 return (FALSE);
935 }
936
937 memset(RAM, 0, 0x20000);
938 memset(SRAM, 0, 0x20000);
939 memset(VRAM, 0, 0x10000);
940 memset(ROM, 0, MAX_ROM_SIZE + 0x200 + 0x8000);
941
942 memset(IPPU.TileCache[TILE_2BIT], 0, MAX_2BIT_TILES * 64);
943 memset(IPPU.TileCache[TILE_4BIT], 0, MAX_4BIT_TILES * 64);
944 memset(IPPU.TileCache[TILE_8BIT], 0, MAX_8BIT_TILES * 64);
945 memset(IPPU.TileCache[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES * 64);
946 memset(IPPU.TileCache[TILE_2BIT_ODD], 0, MAX_2BIT_TILES * 64);
947 memset(IPPU.TileCache[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES * 64);
948 memset(IPPU.TileCache[TILE_4BIT_ODD], 0, MAX_4BIT_TILES * 64);
949
950 memset(IPPU.TileCached[TILE_2BIT], 0, MAX_2BIT_TILES);
951 memset(IPPU.TileCached[TILE_4BIT], 0, MAX_4BIT_TILES);
952 memset(IPPU.TileCached[TILE_8BIT], 0, MAX_8BIT_TILES);
953 memset(IPPU.TileCached[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES);
954 memset(IPPU.TileCached[TILE_2BIT_ODD], 0, MAX_2BIT_TILES);
955 memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES);
956 memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES);
957
958 // FillRAM uses first 32K of ROM image area, otherwise space just
959 // wasted. Might be read by the SuperFX code.
960
961 FillRAM = ROM;
962
963 // Add 0x8000 to ROM image pointer to stop SuperFX code accessing
964 // unallocated memory (can cause crash on some ports).
965
966 ROM += 0x8000;
967
968 C4RAM = ROM + 0x400000 + 8192 * 8; // C4
969 OBC1RAM = ROM + 0x400000; // OBC1
970 BIOSROM = ROM + 0x300000; // BS
971 BSRAM = ROM + 0x400000; // BS
972
973 SuperFX.pvRegisters = FillRAM + 0x3000;
974 SuperFX.nRamBanks = 2; // Most only use 1. 1=64KB=512Mb, 2=128KB=1024Mb
975 SuperFX.pvRam = SRAM;
976 SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024);
977 SuperFX.pvRom = (uint8 *) ROM;
978
979 PostRomInitFunc = NULL;
980
981 return (TRUE);
982}
983
984void CMemory::Deinit (void)
985{
986 if (RAM)
987 {
988 free(RAM);
989 RAM = NULL;
990 }
991
992 if (SRAM)
993 {
994 free(SRAM);
995 SRAM = NULL;
996 }
997
998 if (VRAM)
999 {
1000 free(VRAM);
1001 VRAM = NULL;
1002 }
1003
1004 if (ROM)
1005 {
1006 ROM -= 0x8000;
1007 free(ROM);
1008 ROM = NULL;
1009 }
1010
1011 for (int t = 0; t < 7; t++)
1012 {
1013 if (IPPU.TileCache[t])
1014 {
1015 free(IPPU.TileCache[t]);
1016 IPPU.TileCache[t] = NULL;
1017 }
1018
1019 if (IPPU.TileCached[t])
1020 {
1021 free(IPPU.TileCached[t]);
1022 IPPU.TileCached[t] = NULL;
1023 }
1024 }
1025
1026 Safe(NULL);
1027 SafeANK(NULL);
1028}
1029
1030// file management and ROM detection
1031
1032static bool8 allASCII (uint8 *b, int size)
1033{
1034 for (int i = 0; i < size; i++)
1035 {
1036 if (b[i] < 32 || b[i] > 126)
1037 return (FALSE);
1038 }
1039
1040 return (TRUE);
1041}
1042
1043static bool8 is_SufamiTurbo_BIOS (const uint8 *data, uint32 size)
1044{
1045 if (size == 0x40000 &&
1046 strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) == 0)
1047 return (TRUE);
1048 else
1049 return (FALSE);
1050}
1051
1052static bool8 is_SufamiTurbo_Cart (const uint8 *data, uint32 size)
1053{
1054 if (size >= 0x80000 && size <= 0x100000 &&
1055 strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) != 0)
1056 return (TRUE);
1057 else
1058 return (FALSE);
1059}
1060
1061static bool8 is_BSCart_BIOS(const uint8 *data, uint32 size)
1062{
1063 if ((data[0x7FB2] == 0x5A) && (data[0x7FB5] != 0x20) && (data[0x7FDA] == 0x33))
1064 {
1065 Memory.LoROM = TRUE;
1066 Memory.HiROM = FALSE;
1067
1068 return (TRUE);
1069 }
1070 else if ((data[0xFFB2] == 0x5A) && (data[0xFFB5] != 0x20) && (data[0xFFDA] == 0x33))
1071 {
1072 Memory.LoROM = FALSE;
1073 Memory.HiROM = TRUE;
1074
1075 return (TRUE);
1076 }
1077 else
1078 return (FALSE);
1079}
1080
1081static bool8 is_BSCartSA1_BIOS (const uint8 *data, uint32 size)
1082{
1083 //Same basic check as BSCart
1084 if (!is_BSCart_BIOS(data, size))
1085 return (FALSE);
1086
1087 //Checks if the game is Itoi's Bass Fishing No. 1 (ZBPJ) or SD Gundam G-NEXT (ZX3J)
1088 if (strncmp((char *)(data + 0x7fb2), "ZBPJ", 4) == 0 || strncmp((char *)(data + 0x7fb2), "ZX3J", 4) == 0)
1089 return (TRUE);
1090 else
1091 return (FALSE);
1092}
1093
1094static bool8 is_GNEXT_Add_On (const uint8 *data, uint32 size)
1095{
1096 if (size == 0x80000)
1097 return (TRUE);
1098 else
1099 return (FALSE);
1100}
1101
1102int CMemory::ScoreHiROM (bool8 skip_header, int32 romoff)
1103{
1104 uint8 *buf = ROM + 0xff00 + romoff + (skip_header ? 0x200 : 0);
1105 int score = 0;
1106
1107 if (buf[0xd5] & 0x1)
1108 score += 2;
1109
1110 // Mode23 is SA-1
1111 if (buf[0xd5] == 0x23)
1112 score -= 2;
1113
1114 if (buf[0xd4] == 0x20)
1115 score += 2;
1116
1117 if ((buf[0xdc] + (buf[0xdd] << 8)) + (buf[0xde] + (buf[0xdf] << 8)) == 0xffff)
1118 {
1119 score += 2;
1120 if (0 != (buf[0xde] + (buf[0xdf] << 8)))
1121 score++;
1122 }
1123
1124 if (buf[0xda] == 0x33)
1125 score += 2;
1126
1127 if ((buf[0xd5] & 0xf) < 4)
1128 score += 2;
1129
1130 if (!(buf[0xfd] & 0x80))
1131 score -= 6;
1132
1133 if ((buf[0xfc] + (buf[0xfd] << 8)) > 0xffb0)
1134 score -= 2; // reduced after looking at a scan by Cowering
1135
1136 if (CalculatedSize > 1024 * 1024 * 3)
1137 score += 4;
1138
1139 if ((1 << (buf[0xd7] - 7)) > 48)
1140 score -= 1;
1141
1142 if (!allASCII(&buf[0xb0], 6))
1143 score -= 1;
1144
1145 if (!allASCII(&buf[0xc0], ROM_NAME_LEN - 1))
1146 score -= 1;
1147
1148 return (score);
1149}
1150
1151int CMemory::ScoreLoROM (bool8 skip_header, int32 romoff)
1152{
1153 uint8 *buf = ROM + 0x7f00 + romoff + (skip_header ? 0x200 : 0);
1154 int score = 0;
1155
1156 if (!(buf[0xd5] & 0x1))
1157 score += 3;
1158
1159 // Mode23 is SA-1
1160 if (buf[0xd5] == 0x23)
1161 score += 2;
1162
1163 if ((buf[0xdc] + (buf[0xdd] << 8)) + (buf[0xde] + (buf[0xdf] << 8)) == 0xffff)
1164 {
1165 score += 2;
1166 if (0 != (buf[0xde] + (buf[0xdf] << 8)))
1167 score++;
1168 }
1169
1170 if (buf[0xda] == 0x33)
1171 score += 2;
1172
1173 if ((buf[0xd5] & 0xf) < 4)
1174 score += 2;
1175
1176 if (!(buf[0xfd] & 0x80))
1177 score -= 6;
1178
1179 if ((buf[0xfc] + (buf[0xfd] << 8)) > 0xffb0)
1180 score -= 2; // reduced per Cowering suggestion
1181
1182 if (CalculatedSize <= 1024 * 1024 * 16)
1183 score += 2;
1184
1185 if ((1 << (buf[0xd7] - 7)) > 48)
1186 score -= 1;
1187
1188 if (!allASCII(&buf[0xb0], 6))
1189 score -= 1;
1190
1191 if (!allASCII(&buf[0xc0], ROM_NAME_LEN - 1))
1192 score -= 1;
1193
1194 return (score);
1195}
1196
1197int CMemory::First512BytesCountZeroes() const
1198{
1199 const uint8 *buf = ROM;
1200 int zeroCount = 0;
1201 for (int i = 0; i < 512; i++)
1202 {
1203 if (buf[i] == 0)
1204 {
1205 zeroCount++;
1206 }
1207 }
1208 return zeroCount;
1209}
1210
1211uint32 CMemory::HeaderRemove (uint32 size, uint8 *buf)
1212{
1213 uint32 calc_size = (size / 0x2000) * 0x2000;
1214
1215 if ((size - calc_size == 512 && !Settings.ForceNoHeader) || Settings.ForceHeader)
1216 {
1217 uint8 *NSRTHead = buf + 0x1D0; // NSRT Header Location
1218
1219 // detect NSRT header
1220 if (!strncmp("NSRT", (char *) &NSRTHead[24], 4))
1221 {
1222 if (NSRTHead[28] == 22)
1223 {
1224 if (((std::accumulate(NSRTHead, NSRTHead + sizeof(NSRTHeader), 0) & 0xFF) == NSRTHead[30]) &&
1225 (NSRTHead[30] + NSRTHead[31] == 255) && ((NSRTHead[0] & 0x0F) <= 13) &&
1226 (((NSRTHead[0] & 0xF0) >> 4) <= 3) && ((NSRTHead[0] & 0xF0) >> 4))
1227 memcpy(NSRTHeader, NSRTHead, sizeof(NSRTHeader));
1228 }
1229 }
1230
1231 memmove(buf, buf + 512, calc_size);
1232 HeaderCount++;
1233 size -= 512;
1234 }
1235
1236 return (size);
1237}
1238
1239uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, uint32 maxsize)
1240{
1241 // <- ROM size without header
1242 // ** Memory.HeaderCount
1243 // ** Memory.ROMFilename
1244
1245 uint32 totalSize = 0;
1246 char fname[PATH_MAX + 1];
1247 char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], name[_MAX_FNAME + 1], exts[_MAX_EXT + 1];
1248 char *ext;
1249
1250#if defined(__WIN32__) || defined(__MACOSX__)
1251 ext = &exts[1];
1252#else
1253 ext = &exts[0];
1254#endif
1255
1256 memset(NSRTHeader, 0, sizeof(NSRTHeader));
1257 HeaderCount = 0;
1258
1259 _splitpath(filename, drive, dir, name, exts);
1260 _makepath(fname, drive, dir, name, exts);
1261
1262 int nFormat = FILE_DEFAULT;
1263 if (strcasecmp(ext, "zip") == 0 || strcasecmp(ext, "msu1") == 0)
1264 nFormat = FILE_ZIP;
1265 else
1266 if (strcasecmp(ext, "jma") == 0)
1267 nFormat = FILE_JMA;
1268
1269 switch (nFormat)
1270 {
1271 case FILE_ZIP:
1272 {
1273 #ifdef UNZIP_SUPPORT
1274 if (!LoadZip(fname, &totalSize, buffer))
1275 {
1276 S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Invalid Zip archive.");
1277 return (0);
1278 }
1279
1280 strcpy(ROMFilename, fname);
1281 #else
1282 S9xMessage(S9X_ERROR, S9X_ROM_INFO, "This binary was not created with Zip support.");
1283 return (0);
1284 #endif
1285 break;
1286 }
1287
1288 case FILE_JMA:
1289 {
1290 #ifdef JMA_SUPPORT
1291 size_t size = load_jma_file(fname, buffer);
1292 if (!size)
1293 {
1294 S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Invalid JMA archive.");
1295 return (0);
1296 }
1297
1298 totalSize = HeaderRemove(size, buffer);
1299
1300 strcpy(ROMFilename, fname);
1301 #else
1302 S9xMessage(S9X_ERROR, S9X_ROM_INFO, "This binary was not created with JMA support.");
1303 return (0);
1304 #endif
1305 break;
1306 }
1307
1308 case FILE_DEFAULT:
1309 default:
1310 {
1311 STREAM fp = OPEN_STREAM(fname, "rb");
1312 if (!fp)
1313 return (0);
1314
1315 strcpy(ROMFilename, fname);
1316
1317 int len = 0;
1318 uint32 size = 0;
1319 bool8 more = FALSE;
1320 uint8 *ptr = buffer;
1321
1322 do
1323 {
1324 size = READ_STREAM(ptr, maxsize + 0x200 - (ptr - buffer), fp);
1325 CLOSE_STREAM(fp);
1326
1327 size = HeaderRemove(size, ptr);
1328 totalSize += size;
1329 ptr += size;
1330
1331 // check for multi file roms
1332 if (ptr - buffer < maxsize + 0x200 &&
1333 (isdigit(ext[0]) && ext[1] == 0 && ext[0] < '9'))
1334 {
1335 more = TRUE;
1336 ext[0]++;
1337 _makepath(fname, drive, dir, name, exts);
1338 }
1339 else
1340 if (ptr - buffer < maxsize + 0x200 &&
1341 (((len = strlen(name)) == 7 || len == 8) &&
1342 strncasecmp(name, "sf", 2) == 0 &&
1343 isdigit(name[2]) && isdigit(name[3]) && isdigit(name[4]) && isdigit(name[5]) &&
1344 isalpha(name[len - 1])))
1345 {
1346 more = TRUE;
1347 name[len - 1]++;
1348 _makepath(fname, drive, dir, name, exts);
1349 }
1350 else
1351 more = FALSE;
1352
1353 } while (more && (fp = OPEN_STREAM(fname, "rb")) != NULL);
1354
1355 break;
1356 }
1357 }
1358
1359 if (HeaderCount == 0)
1360 S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found.");
1361 else
1362 if (HeaderCount == 1)
1363 S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found ROM file header (and ignored it).");
1364 else
1365 S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found multiple ROM file headers (and ignored them).");
1366
1367 return ((uint32) totalSize);
1368}
1369
1370bool8 CMemory::LoadROMMem (const uint8 *source, uint32 sourceSize)
1371{
1372 if(!source || sourceSize > MAX_ROM_SIZE)
1373 return FALSE;
1374
1375 strcpy(ROMFilename,"MemoryROM");
1376
1377 do
1378 {
1379 memset(ROM,0, MAX_ROM_SIZE);
1380 memset(&Multi, 0,sizeof(Multi));
1381 memcpy(ROM,source,sourceSize);
1382 }
1383 while(!LoadROMInt(sourceSize));
1384
1385 return TRUE;
1386}
1387
1388bool8 CMemory::LoadROM (const char *filename)
1389{
1390 if(!filename || !*filename)
1391 return FALSE;
1392
1393 int32 totalFileSize;
1394
1395 do
1396 {
1397 memset(ROM,0, MAX_ROM_SIZE);
1398 memset(&Multi, 0,sizeof(Multi));
1399 totalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE);
1400
1401 if (!totalFileSize)
1402 return (FALSE);
1403
1404 CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize);
1405 }
1406 while(!LoadROMInt(totalFileSize));
1407
1408 return TRUE;
1409}
1410
1411bool8 CMemory::LoadROMInt (int32 ROMfillSize)
1412{
1413 Settings.DisplayColor = BUILD_PIXEL(31, 31, 31);
1414 SET_UI_COLOR(255, 255, 255);
1415
1416 CalculatedSize = 0;
1417 ExtendedFormat = NOPE;
1418
1419 int hi_score, lo_score;
1420 int score_headered;
1421 int score_nonheadered;
1422
1423 hi_score = ScoreHiROM(FALSE);
1424 lo_score = ScoreLoROM(FALSE);
1425 score_nonheadered = max(hi_score, lo_score);
1426 score_headered = max(ScoreHiROM(TRUE), ScoreLoROM(TRUE));
1427
1428 bool size_is_likely_headered = ((ROMfillSize - 512) & 0xFFFF) == 0;
1429 if (size_is_likely_headered) { score_headered += 2; } else { score_headered -= 2; }
1430 if (First512BytesCountZeroes() >= 0x1E0) { score_headered += 2; } else { score_headered -= 2; }
1431
1432 bool headered_score_highest = score_headered > score_nonheadered;
1433
1434 if (HeaderCount == 0 && !Settings.ForceNoHeader && headered_score_highest)
1435 {
1436 memmove(ROM, ROM + 512, ROMfillSize - 512);
1437 ROMfillSize -= 512;
1438 S9xMessage(S9X_INFO, S9X_HEADER_WARNING, "Try 'force no-header' option if the game doesn't work");
1439 // modifying ROM, so we need to rescore
1440 hi_score = ScoreHiROM(FALSE);
1441 lo_score = ScoreLoROM(FALSE);
1442 }
1443
1444 CalculatedSize = ((ROMfillSize + 0x1fff) / 0x2000) * 0x2000;
1445
1446 if (CalculatedSize > 0x400000 &&
1447 (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x3423 && // exclude SA-1
1448 (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x3523 &&
1449 (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x4332 && // exclude S-DD1
1450 (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x4532 &&
1451 (ROM[0xffd5] + (ROM[0xffd6] << 8)) != 0xF93a && // exclude SPC7110
1452 (ROM[0xffd5] + (ROM[0xffd6] << 8)) != 0xF53a)
1453 ExtendedFormat = YEAH;
1454
1455 // if both vectors are invalid, it's type 1 interleaved LoROM
1456 if (ExtendedFormat == NOPE &&
1457 ((ROM[0x7ffc] + (ROM[0x7ffd] << 8)) < 0x8000) &&
1458 ((ROM[0xfffc] + (ROM[0xfffd] << 8)) < 0x8000))
1459 {
1460 if (!Settings.ForceInterleaved && !Settings.ForceNotInterleaved)
1461 S9xDeinterleaveType1(ROMfillSize, ROM);
1462 }
1463
1464 // CalculatedSize is now set, so rescore
1465 hi_score = ScoreHiROM(FALSE);
1466 lo_score = ScoreLoROM(FALSE);
1467
1468 uint8 *RomHeader = ROM;
1469
1470 if (ExtendedFormat != NOPE)
1471 {
1472 int swappedhirom, swappedlorom;
1473
1474 swappedhirom = ScoreHiROM(FALSE, 0x400000);
1475 swappedlorom = ScoreLoROM(FALSE, 0x400000);
1476
1477 // set swapped here
1478 if (max(swappedlorom, swappedhirom) >= max(lo_score, hi_score))
1479 {
1480 ExtendedFormat = BIGFIRST;
1481 hi_score = swappedhirom;
1482 lo_score = swappedlorom;
1483 RomHeader += 0x400000;
1484 }
1485 else
1486 ExtendedFormat = SMALLFIRST;
1487 }
1488
1489 bool8 interleaved, tales = FALSE;
1490
1491 interleaved = Settings.ForceInterleaved || Settings.ForceInterleaved2 || Settings.ForceInterleaveGD24;
1492
1493 if (Settings.ForceLoROM || (!Settings.ForceHiROM && lo_score >= hi_score))
1494 {
1495 LoROM = TRUE;
1496 HiROM = FALSE;
1497
1498 // ignore map type byte if not 0x2x or 0x3x
1499 if ((RomHeader[0x7fd5] & 0xf0) == 0x20 || (RomHeader[0x7fd5] & 0xf0) == 0x30)
1500 {
1501 switch (RomHeader[0x7fd5] & 0xf)
1502 {
1503 case 1:
1504 interleaved = TRUE;
1505 break;
1506
1507 case 5:
1508 interleaved = TRUE;
1509 tales = TRUE;
1510 break;
1511 }
1512 }
1513 }
1514 else
1515 {
1516 LoROM = FALSE;
1517 HiROM = TRUE;
1518
1519 if ((RomHeader[0xffd5] & 0xf0) == 0x20 || (RomHeader[0xffd5] & 0xf0) == 0x30)
1520 {
1521 switch (RomHeader[0xffd5] & 0xf)
1522 {
1523 case 0:
1524 case 3:
1525 interleaved = TRUE;
1526 break;
1527 }
1528 }
1529 }
1530
1531 // this two games fail to be detected
1532 if (!Settings.ForceHiROM && !Settings.ForceLoROM)
1533 {
1534 if (strncmp((char *) &ROM[0x7fc0], "YUYU NO QUIZ DE GO!GO!", 22) == 0 ||
1535 (strncmp((char *) &ROM[0xffc0], "BATMAN--REVENGE JOKER", 21) == 0))
1536 {
1537 LoROM = TRUE;
1538 HiROM = FALSE;
1539 interleaved = FALSE;
1540 tales = FALSE;
1541 }
1542 }
1543
1544 if (!Settings.ForceNotInterleaved && interleaved)
1545 {
1546 S9xMessage(S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "ROM image is in interleaved format - converting...");
1547
1548 if (tales)
1549 {
1550 if (ExtendedFormat == BIGFIRST)
1551 {
1552 S9xDeinterleaveType1(0x400000, ROM);
1553 S9xDeinterleaveType1(CalculatedSize - 0x400000, ROM + 0x400000);
1554 }
1555 else
1556 {
1557 S9xDeinterleaveType1(CalculatedSize - 0x400000, ROM);
1558 S9xDeinterleaveType1(0x400000, ROM + CalculatedSize - 0x400000);
1559 }
1560
1561 LoROM = FALSE;
1562 HiROM = TRUE;
1563 }
1564 else
1565 if (Settings.ForceInterleaveGD24 && CalculatedSize == 0x300000)
1566 {
1567 bool8 t = LoROM;
1568 LoROM = HiROM;
1569 HiROM = t;
1570 S9xDeinterleaveGD24(CalculatedSize, ROM);
1571 }
1572 else
1573 if (Settings.ForceInterleaved2)
1574 S9xDeinterleaveType2(CalculatedSize, ROM);
1575 else
1576 {
1577 bool8 t = LoROM;
1578 LoROM = HiROM;
1579 HiROM = t;
1580 S9xDeinterleaveType1(CalculatedSize, ROM);
1581 }
1582
1583 hi_score = ScoreHiROM(FALSE);
1584 lo_score = ScoreLoROM(FALSE);
1585
1586 if ((HiROM && (lo_score >= hi_score || hi_score < 0)) ||
1587 (LoROM && (hi_score > lo_score || lo_score < 0)))
1588 {
1589 S9xMessage(S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, "ROM lied about its type! Trying again.");
1590 Settings.ForceNotInterleaved = TRUE;
1591 Settings.ForceInterleaved = FALSE;
1592 return (FALSE);
1593 }
1594 }
1595
1596 if (ExtendedFormat == SMALLFIRST)
1597 tales = TRUE;
1598
1599 if (tales)
1600 {
1601 uint8 *tmp = (uint8 *) malloc(CalculatedSize - 0x400000);
1602 if (tmp)
1603 {
1604 S9xMessage(S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "Fixing swapped ExHiROM...");
1605 memmove(tmp, ROM, CalculatedSize - 0x400000);
1606 memmove(ROM, ROM + CalculatedSize - 0x400000, 0x400000);
1607 memmove(ROM + 0x400000, tmp, CalculatedSize - 0x400000);
1608 free(tmp);
1609 }
1610 }
1611
1612 if (strncmp(LastRomFilename, ROMFilename, PATH_MAX + 1))
1613 {
1614 strncpy(LastRomFilename, ROMFilename, PATH_MAX + 1);
1615 LastRomFilename[PATH_MAX] = 0;
1616 }
1617
1618 memset(&SNESGameFixes, 0, sizeof(SNESGameFixes));
1619 SNESGameFixes.SRAMInitialValue = 0x60;
1620
1621 InitROM();
1622
1623 S9xReset();
1624
1625 S9xDeleteCheats();
1626 S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
1627
1628 return (TRUE);
1629}
1630
1631bool8 CMemory::LoadMultiCartMem (const uint8 *sourceA, uint32 sourceASize,
1632 const uint8 *sourceB, uint32 sourceBSize,
1633 const uint8 *bios, uint32 biosSize)
1634{
1635 uint32 offset = 0;
1636 memset(ROM, 0, MAX_ROM_SIZE);
1637 memset(&Multi, 0, sizeof(Multi));
1638
1639 if(bios) {
1640 if(!is_SufamiTurbo_BIOS(bios,biosSize))
1641 return FALSE;
1642
1643 memcpy(ROM,bios,biosSize);
1644 offset+=biosSize;
1645 }
1646
1647 if(sourceA) {
1648 memcpy(ROM + offset,sourceA,sourceASize);
1649 Multi.cartOffsetA = offset;
1650 Multi.cartSizeA = sourceASize;
1651 offset += sourceASize;
1652 strcpy(Multi.fileNameA,"MemCartA");
1653 }
1654
1655 if(sourceB) {
1656 memcpy(ROM + offset,sourceB,sourceBSize);
1657 Multi.cartOffsetB = offset;
1658 Multi.cartSizeB = sourceBSize;
1659 offset += sourceBSize;
1660 strcpy(Multi.fileNameB,"MemCartB");
1661 }
1662
1663 return LoadMultiCartInt();
1664}
1665
1666bool8 CMemory::LoadMultiCart (const char *cartA, const char *cartB)
1667{
1668 memset(ROM, 0, MAX_ROM_SIZE);
1669 memset(&Multi, 0, sizeof(Multi));
1670
1671 Settings.DisplayColor = BUILD_PIXEL(31, 31, 31);
1672 SET_UI_COLOR(255, 255, 255);
1673
1674 if (cartB && cartB[0])
1675 Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE);
1676
1677 if (Multi.cartSizeB) {
1678 strcpy(Multi.fileNameB, cartB);
1679
1680 CheckForAnyPatch(cartB, HeaderCount != 0, Multi.cartSizeB);
1681
1682 Multi.cartOffsetB = 0x400000;
1683 memcpy(ROM + Multi.cartOffsetB,ROM,Multi.cartSizeB);
1684 }
1685
1686 if (cartA && cartA[0])
1687 Multi.cartSizeA = FileLoader(ROM, cartA, MAX_ROM_SIZE);
1688
1689 if (Multi.cartSizeA) {
1690 strcpy(Multi.fileNameA, cartA);
1691
1692 CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA);
1693 }
1694
1695 return LoadMultiCartInt();
1696}
1697
1698bool8 CMemory::LoadMultiCartInt ()
1699{
1700 bool8 r = TRUE;
1701
1702 CalculatedSize = 0;
1703 ExtendedFormat = NOPE;
1704
1705 if (Multi.cartSizeA)
1706 {
1707 if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetA, Multi.cartSizeA))
1708 Multi.cartType = 4;
1709 else
1710 if (is_BSCartSA1_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA))
1711 Multi.cartType = 5;
1712 else
1713 if (is_BSCart_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA))
1714 Multi.cartType = 3;
1715 }
1716 else
1717 if (Multi.cartSizeB)
1718 {
1719 if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetB, Multi.cartSizeB))
1720 Multi.cartType = 4;
1721 }
1722 else
1723 Multi.cartType = 4; // assuming BIOS only
1724
1725
1726 if(Multi.cartType == 4 && Multi.cartOffsetA == 0) { // try to load bios from file
1727 Multi.cartOffsetA = 0x40000;
1728 if(Multi.cartSizeA)
1729 memmove(ROM + Multi.cartOffsetA, ROM, Multi.cartSizeA + Multi.cartSizeB);
1730 else if(Multi.cartOffsetB) // clear cart A so the bios can detect that it's not present
1731 memset(ROM, 0, Multi.cartOffsetB);
1732
1733 FILE *fp;
1734 size_t size;
1735 char path[PATH_MAX + 1];
1736
1737 strcpy(path, S9xGetDirectory(BIOS_DIR));
1738 strcat(path, SLASH_STR);
1739 strcat(path, "STBIOS.bin");
1740
1741 fp = fopen(path, "rb");
1742 if (fp)
1743 {
1744 size = fread((void *) ROM, 1, 0x40000, fp);
1745 fclose(fp);
1746 if (!is_SufamiTurbo_BIOS(ROM, size))
1747 return (FALSE);
1748 }
1749 else
1750 return (FALSE);
1751
1752 strcpy(ROMFilename, path);
1753 }
1754
1755 switch (Multi.cartType)
1756 {
1757 case 4:
1758 r = LoadSufamiTurbo();
1759 break;
1760
1761 case 3:
1762 case 5:
1763 r = LoadBSCart();
1764 break;
1765
1766 default:
1767 r = FALSE;
1768 }
1769
1770 if (!r)
1771 {
1772 memset(&Multi, 0, sizeof(Multi));
1773 return (FALSE);
1774 }
1775
1776 if (Multi.cartSizeA)
1777 strcpy(ROMFilename, Multi.fileNameA);
1778 else
1779 if (Multi.cartSizeB)
1780 strcpy(ROMFilename, Multi.fileNameB);
1781
1782 memset(&SNESGameFixes, 0, sizeof(SNESGameFixes));
1783 SNESGameFixes.SRAMInitialValue = 0x60;
1784
1785 InitROM();
1786
1787 S9xReset();
1788
1789 S9xDeleteCheats();
1790 S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
1791
1792 return (TRUE);
1793}
1794
1795bool8 CMemory::LoadSufamiTurbo ()
1796{
1797 Multi.sramA = SRAM;
1798 Multi.sramB = SRAM + 0x10000;
1799
1800 if (Multi.cartSizeA)
1801 {
1802 Multi.sramSizeA = 4; // ROM[0x37]?
1803 Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0;
1804 }
1805
1806 if (Multi.cartSizeB)
1807 {
1808 if (!is_SufamiTurbo_Cart(ROM + Multi.cartOffsetB, Multi.cartSizeB))
1809 Multi.cartSizeB = 0;
1810 }
1811
1812 if (Multi.cartSizeB)
1813 {
1814 Multi.sramSizeB = 4; // ROM[0x37]?
1815 Multi.sramMaskB = Multi.sramSizeB ? ((1 << (Multi.sramSizeB + 3)) * 128 - 1) : 0;
1816 }
1817
1818 LoROM = TRUE;
1819 HiROM = FALSE;
1820 CalculatedSize = 0x40000;
1821
1822 return (TRUE);
1823}
1824
1825bool8 CMemory::LoadBSCart ()
1826{
1827 Multi.sramA = SRAM;
1828 Multi.sramB = NULL;
1829
1830 if (LoROM)
1831 Multi.sramSizeA = ROM[0x7fd8];
1832 else
1833 Multi.sramSizeA = ROM[0xffd8];
1834
1835 Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0;
1836 Multi.sramSizeB = 0;
1837 Multi.sramMaskB = 0;
1838
1839 CalculatedSize = Multi.cartSizeA;
1840
1841 if (Multi.cartSizeB == 0 && Multi.cartSizeA <= (int32)(MAX_ROM_SIZE - 0x100000 - Multi.cartOffsetA))
1842 {
1843 //Initialize 1MB Empty Memory Pack only if cart B is cleared
1844 //It does not make a Memory Pack if game is loaded like a normal ROM
1845 Multi.cartOffsetB = Multi.cartOffsetA + CalculatedSize;
1846 Multi.cartSizeB = 0x100000;
1847 memset(Memory.ROM + Multi.cartOffsetB, 0xFF, 0x100000);
1848 }
1849
1850 return (TRUE);
1851}
1852
1853bool8 CMemory::LoadGNEXT ()
1854{
1855 Multi.sramA = SRAM;
1856 Multi.sramB = NULL;
1857
1858 Multi.sramSizeA = ROM[0x7fd8];
1859 Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0;
1860 Multi.sramSizeB = 0;
1861 Multi.sramMaskB = 0;
1862
1863 if (Multi.cartSizeB)
1864 {
1865 if (!is_GNEXT_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB))
1866 Multi.cartSizeB = 0;
1867 }
1868
1869 LoROM = TRUE;
1870 HiROM = FALSE;
1871 CalculatedSize = Multi.cartSizeA;
1872
1873 return (TRUE);
1874}
1875
1876bool8 CMemory::LoadSRTC (void)
1877{
1878 FILE *fp;
1879
1880 fp = fopen(S9xGetFilename(".rtc", SRAM_DIR), "rb");
1881 if (!fp)
1882 return (FALSE);
1883
1884 if (fread(RTCData.reg, 1, 20, fp) < 20)
1885 memset (RTCData.reg, 0, 20);
1886 fclose(fp);
1887
1888 return (TRUE);
1889}
1890
1891bool8 CMemory::SaveSRTC (void)
1892{
1893 FILE *fp;
1894
1895 fp = fopen(S9xGetFilename(".rtc", SRAM_DIR), "wb");
1896 if (!fp)
1897 return (FALSE);
1898
1899 if (fwrite(RTCData.reg, 1, 20, fp) < 20)
1900 {
1901 printf ("Failed to save clock data.\n");
1902 }
1903 fclose(fp);
1904
1905 return (TRUE);
1906}
1907
1908void CMemory::ClearSRAM (bool8 onlyNonSavedSRAM)
1909{
1910 if (onlyNonSavedSRAM)
1911 if (!(Settings.SuperFX && ROMType < 0x15) && !(Settings.SA1 && ROMType == 0x34)) // can have SRAM
1912 return;
1913
1914 memset(SRAM, SNESGameFixes.SRAMInitialValue, 0x20000);
1915}
1916
1917bool8 CMemory::LoadSRAM (const char *filename)
1918{
1919 FILE *file;
1920 int size, len;
1921 char sramName[PATH_MAX + 1];
1922
1923 strcpy(sramName, filename);
1924
1925 ClearSRAM();
1926
1927 if (Multi.cartType && Multi.sramSizeB)
1928 {
1929 char temp[PATH_MAX + 1];
1930
1931 strcpy(temp, ROMFilename);
1932 strcpy(ROMFilename, Multi.fileNameB);
1933
1934 size = (1 << (Multi.sramSizeB + 3)) * 128;
1935
1936 file = fopen(S9xGetFilename(".srm", SRAM_DIR), "rb");
1937 if (file)
1938 {
1939 len = fread((char *) Multi.sramB, 1, 0x10000, file);
1940 fclose(file);
1941 if (len - size == 512)
1942 memmove(Multi.sramB, Multi.sramB + 512, size);
1943 }
1944
1945 strcpy(ROMFilename, temp);
1946 }
1947
1948 size = SRAMSize ? (1 << (SRAMSize + 3)) * 128 : 0;
1949 if (size > 0x20000)
1950 size = 0x20000;
1951
1952 if (size)
1953 {
1954 file = fopen(sramName, "rb");
1955 if (file)
1956 {
1957 len = fread((char *) SRAM, 1, 0x20000, file);
1958 fclose(file);
1959 if (len - size == 512)
1960 memmove(SRAM, SRAM + 512, size);
1961
1962 if (Settings.SRTC || Settings.SPC7110RTC)
1963 LoadSRTC();
1964
1965 return (TRUE);
1966 }
1967 else
1968 if (Settings.BS && !Settings.BSXItself)
1969 {
1970 // The BS game's SRAM was not found
1971 // Try to read BS-X.srm instead
1972 char path[PATH_MAX + 1];
1973
1974 strcpy(path, S9xGetDirectory(SRAM_DIR));
1975 strcat(path, SLASH_STR);
1976 strcat(path, "BS-X.srm");
1977
1978 file = fopen(path, "rb");
1979 if (file)
1980 {
1981 len = fread((char *) SRAM, 1, 0x20000, file);
1982 fclose(file);
1983 if (len - size == 512)
1984 memmove(SRAM, SRAM + 512, size);
1985
1986 S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found: BS-X.srm was read instead.");
1987 return (TRUE);
1988 }
1989 else
1990 {
1991 S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found, BS-X.srm wasn't found either.");
1992 return (FALSE);
1993 }
1994 }
1995
1996 return (FALSE);
1997 }
1998
1999 return (TRUE);
2000}
2001
2002bool8 CMemory::SaveSRAM (const char *filename)
2003{
2004 if (Settings.SuperFX && ROMType < 0x15) // doesn't have SRAM
2005 return (TRUE);
2006
2007 if (Settings.SA1 && ROMType == 0x34) // doesn't have SRAM
2008 return (TRUE);
2009
2010 FILE *file;
2011 int size;
2012 char sramName[PATH_MAX + 1];
2013
2014 strcpy(sramName, filename);
2015
2016 if (Multi.cartType && Multi.sramSizeB)
2017 {
2018 char name[PATH_MAX + 1], temp[PATH_MAX + 1];
2019
2020 strcpy(temp, ROMFilename);
2021 strcpy(ROMFilename, Multi.fileNameB);
2022 strcpy(name, S9xGetFilename(".srm", SRAM_DIR));
2023
2024 size = (1 << (Multi.sramSizeB + 3)) * 128;
2025
2026 file = fopen(name, "wb");
2027 if (file)
2028 {
2029 if (!fwrite((char *) Multi.sramB, size, 1, file))
2030 printf ("Couldn't write to subcart SRAM file.\n");
2031 fclose(file);
2032 }
2033
2034 strcpy(ROMFilename, temp);
2035 }
2036
2037 size = SRAMSize ? (1 << (SRAMSize + 3)) * 128 : 0;
2038 if (size > 0x20000)
2039 size = 0x20000;
2040
2041 if (size)
2042 {
2043 file = fopen(sramName, "wb");
2044 if (file)
2045 {
2046 if (!fwrite((char *) SRAM, size, 1, file))
2047 printf ("Couldn't write to SRAM file.\n");
2048 fclose(file);
2049
2050 if (Settings.SRTC || Settings.SPC7110RTC)
2051 SaveSRTC();
2052
2053 return (TRUE);
2054 }
2055 }
2056
2057 return (FALSE);
2058}
2059
2060bool8 CMemory::SaveMPAK (const char *filename)
2061{
2062 if (Settings.BS || (Multi.cartSizeB && (Multi.cartType == 3)))
2063 {
2064 FILE *file;
2065 int size;
2066 char mempakName[PATH_MAX + 1];
2067
2068 strcpy(mempakName, filename);
2069 size = 0x100000;
2070 if (size)
2071 {
2072 file = fopen(mempakName, "wb");
2073 if (file)
2074 {
2075 size_t written;
2076 written = fwrite((char *)Memory.ROM + Multi.cartOffsetB, size, 1, file);
2077 fclose(file);
2078
2079 return (written > 0);
2080 }
2081 }
2082 }
2083 return (FALSE);
2084}
2085
2086// initialization
2087
2088static uint32 caCRC32 (uint8 *array, uint32 size, uint32 crc32)
2089{
2090 for (uint32 i = 0; i < size; i++)
2091 crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ array[i]) & 0xFF];
2092
2093 return (~crc32);
2094}
2095
2096char * CMemory::Safe (const char *s)
2097{
2098 static char *safe = NULL;
2099 static int safe_len = 0;
2100
2101 if (s == NULL)
2102 {
2103 if (safe)
2104 {
2105 free(safe);
2106 safe = NULL;
2107 }
2108
2109 return (NULL);
2110 }
2111
2112 int len = strlen(s);
2113 if (!safe || len + 1 > safe_len)
2114 {
2115 if (safe)
2116 free(safe);
2117
2118 safe_len = len + 1;
2119 safe = (char *) malloc(safe_len);
2120 }
2121
2122 for (int i = 0; i < len; i++)
2123 {
2124 if (s[i] >= 32 && s[i] < 127)
2125 safe[i] = s[i];
2126 else
2127 safe[i] = '_';
2128 }
2129
2130 safe[len] = 0;
2131
2132 return (safe);
2133}
2134
2135char * CMemory::SafeANK (const char *s)
2136{
2137 static char *safe = NULL;
2138 static int safe_len = 0;
2139
2140 if (s == NULL)
2141 {
2142 if (safe)
2143 {
2144 free(safe);
2145 safe = NULL;
2146 }
2147
2148 return (NULL);
2149 }
2150
2151 int len = strlen(s);
2152 if (!safe || len + 1 > safe_len)
2153 {
2154 if (safe)
2155 free(safe);
2156
2157 safe_len = len + 1;
2158 safe = (char *) malloc(safe_len);
2159 }
2160
2161 for (int i = 0; i < len; i++)
2162 {
2163 if (s[i] >= 32 && s[i] < 127) // ASCII
2164 safe [i] = s[i];
2165 else
2166 if (ROMRegion == 0 && ((uint8) s[i] >= 0xa0 && (uint8) s[i] < 0xe0)) // JIS X 201 - Katakana
2167 safe [i] = s[i];
2168 else
2169 safe [i] = '_';
2170 }
2171
2172 safe [len] = 0;
2173
2174 return (safe);
2175}
2176
2177void CMemory::ParseSNESHeader (uint8 *RomHeader)
2178{
2179 bool8 bs = Settings.BS & !Settings.BSXItself;
2180
2181 strncpy(ROMName, (char *) &RomHeader[0x10], ROM_NAME_LEN - 1);
2182 if (bs)
2183 memset(ROMName + 16, 0x20, ROM_NAME_LEN - 17);
2184
2185 if (bs)
2186 {
2187 if (!(((RomHeader[0x29] & 0x20) && CalculatedSize < 0x100000) ||
2188 (!(RomHeader[0x29] & 0x20) && CalculatedSize == 0x100000)))
2189 printf("BS: Size mismatch\n");
2190
2191 // FIXME
2192 int p = 0;
2193 while ((1 << p) < (int) CalculatedSize)
2194 p++;
2195 ROMSize = p - 10;
2196 }
2197 else
2198 ROMSize = RomHeader[0x27];
2199
2200 SRAMSize = bs ? 5 /* BS-X */ : RomHeader[0x28];
2201 ROMSpeed = bs ? RomHeader[0x28] : RomHeader[0x25];
2202 ROMType = bs ? 0xE5 /* BS-X */ : RomHeader[0x26];
2203 ROMRegion = bs ? 0 : RomHeader[0x29];
2204
2205 ROMChecksum = RomHeader[0x2E] + (RomHeader[0x2F] << 8);
2206 ROMComplementChecksum = RomHeader[0x2C] + (RomHeader[0x2D] << 8);
2207
2208 memmove(ROMId, &RomHeader[0x02], 4);
2209
2210 if (RomHeader[0x2A] != 0x33)
2211 CompanyId = ((RomHeader[0x2A] >> 4) & 0x0F) * 36 + (RomHeader[0x2A] & 0x0F);
2212 else
2213 if (isalnum(RomHeader[0x00]) && isalnum(RomHeader[0x01]))
2214 {
2215 int l, r, l2, r2;
2216 l = toupper(RomHeader[0x00]);
2217 r = toupper(RomHeader[0x01]);
2218 l2 = (l > '9') ? l - '7' : l - '0';
2219 r2 = (r > '9') ? r - '7' : r - '0';
2220 CompanyId = l2 * 36 + r2;
2221 }
2222}
2223
2224void CMemory::InitROM (void)
2225{
2226 Settings.SuperFX = FALSE;
2227 Settings.DSP = 0;
2228 Settings.SA1 = FALSE;
2229 Settings.C4 = FALSE;
2230 Settings.SDD1 = FALSE;
2231 Settings.SPC7110 = FALSE;
2232 Settings.SPC7110RTC = FALSE;
2233 Settings.OBC1 = FALSE;
2234 Settings.SETA = 0;
2235 Settings.SRTC = FALSE;
2236 Settings.BS = FALSE;
2237 Settings.MSU1 = FALSE;
2238
2239 SuperFX.nRomBanks = CalculatedSize >> 15;
2240
2241 //// Parse ROM header and read ROM informatoin
2242
2243 CompanyId = -1;
2244 memset(ROMId, 0, 5);
2245
2246 uint8 *RomHeader = ROM + 0x7FB0;
2247 if (ExtendedFormat == BIGFIRST)
2248 RomHeader += 0x400000;
2249 if (HiROM)
2250 RomHeader += 0x8000;
2251
2252 S9xInitBSX(); // Set BS header before parsing
2253
2254 ParseSNESHeader(RomHeader);
2255
2256 //// Detect and initialize chips
2257 //// detection codes are compatible with NSRT
2258
2259 // DSP1/2/3/4
2260 if (ROMType == 0x03)
2261 {
2262 if (ROMSpeed == 0x30)
2263 Settings.DSP = 4; // DSP4
2264 else
2265 Settings.DSP = 1; // DSP1
2266 }
2267 else
2268 if (ROMType == 0x05)
2269 {
2270 if (ROMSpeed == 0x20)
2271 Settings.DSP = 2; // DSP2
2272 else
2273 if (ROMSpeed == 0x30 && RomHeader[0x2a] == 0xb2)
2274 Settings.DSP = 3; // DSP3
2275 else
2276 Settings.DSP = 1; // DSP1
2277 }
2278
2279 switch (Settings.DSP)
2280 {
2281 case 1: // DSP1
2282 if (HiROM)
2283 {
2284 DSP0.boundary = 0x7000;
2285 DSP0.maptype = M_DSP1_HIROM;
2286 }
2287 else
2288 if (CalculatedSize > 0x100000)
2289 {
2290 DSP0.boundary = 0x4000;
2291 DSP0.maptype = M_DSP1_LOROM_L;
2292 }
2293 else
2294 {
2295 DSP0.boundary = 0xc000;
2296 DSP0.maptype = M_DSP1_LOROM_S;
2297 }
2298
2299 SetDSP = &DSP1SetByte;
2300 GetDSP = &DSP1GetByte;
2301 break;
2302
2303 case 2: // DSP2
2304 DSP0.boundary = 0x10000;
2305 DSP0.maptype = M_DSP2_LOROM;
2306 SetDSP = &DSP2SetByte;
2307 GetDSP = &DSP2GetByte;
2308 break;
2309
2310 case 3: // DSP3
2311 DSP0.boundary = 0xc000;
2312 DSP0.maptype = M_DSP3_LOROM;
2313 SetDSP = &DSP3SetByte;
2314 GetDSP = &DSP3GetByte;
2315 break;
2316
2317 case 4: // DSP4
2318 DSP0.boundary = 0xc000;
2319 DSP0.maptype = M_DSP4_LOROM;
2320 SetDSP = &DSP4SetByte;
2321 GetDSP = &DSP4GetByte;
2322 break;
2323
2324 default:
2325 SetDSP = NULL;
2326 GetDSP = NULL;
2327 break;
2328 }
2329
2330 uint32 identifier = ((ROMType & 0xff) << 8) + (ROMSpeed & 0xff);
2331
2332 switch (identifier)
2333 {
2334 // SRTC
2335 case 0x5535:
2336 Settings.SRTC = TRUE;
2337 S9xInitSRTC();
2338 break;
2339
2340 // SPC7110
2341 case 0xF93A:
2342 Settings.SPC7110RTC = TRUE;
2343 // Fall through
2344 case 0xF53A:
2345 Settings.SPC7110 = TRUE;
2346 S9xInitSPC7110();
2347 break;
2348
2349 // OBC1
2350 case 0x2530:
2351 Settings.OBC1 = TRUE;
2352 break;
2353
2354 // SA1
2355 case 0x3423:
2356 case 0x3523:
2357 Settings.SA1 = TRUE;
2358 break;
2359
2360 // SuperFX
2361 case 0x1320:
2362 case 0x1420:
2363 case 0x1520:
2364 case 0x1A20:
2365 Settings.SuperFX = TRUE;
2366 S9xInitSuperFX();
2367 if (ROM[0x7FDA] == 0x33)
2368 SRAMSize = ROM[0x7FBD];
2369 else
2370 SRAMSize = 5;
2371 break;
2372
2373 // SDD1
2374 case 0x4332:
2375 case 0x4532:
2376 Settings.SDD1 = TRUE;
2377 break;
2378
2379 // ST018
2380 case 0xF530:
2381 Settings.SETA = ST_018;
2382 SetSETA = NULL;
2383 GetSETA = NULL;
2384 SRAMSize = 2;
2385 SNESGameFixes.SRAMInitialValue = 0x00;
2386 break;
2387
2388 // ST010/011
2389 case 0xF630:
2390 if (ROM[0x7FD7] == 0x09)
2391 {
2392 Settings.SETA = ST_011;
2393 SetSETA = &S9xSetST011;
2394 GetSETA = &S9xGetST011;
2395 }
2396 else
2397 {
2398 Settings.SETA = ST_010;
2399 SetSETA = &S9xSetST010;
2400 GetSETA = &S9xGetST010;
2401 }
2402
2403 SRAMSize = 2;
2404 SNESGameFixes.SRAMInitialValue = 0x00;
2405 break;
2406
2407 // C4
2408 case 0xF320:
2409 Settings.C4 = TRUE;
2410 break;
2411 }
2412
2413 // MSU1
2414 Settings.MSU1 = S9xMSU1ROMExists();
2415
2416 //// Map memory and calculate checksum
2417
2418 Map_Initialize();
2419 CalculatedChecksum = 0;
2420
2421 if (HiROM)
2422 {
2423 if (Settings.BS)
2424 /* Do nothing */;
2425 else
2426 if (Settings.SPC7110)
2427 Map_SPC7110HiROMMap();
2428 else
2429 if (ExtendedFormat != NOPE)
2430 Map_ExtendedHiROMMap();
2431 else
2432 if (Multi.cartType == 3)
2433 Map_BSCartHiROMMap();
2434 else
2435 Map_HiROMMap();
2436 }
2437 else
2438 {
2439 if (Settings.BS)
2440 /* Do nothing */;
2441 else
2442 if (Settings.SETA && Settings.SETA != ST_018)
2443 Map_SetaDSPLoROMMap();
2444 else
2445 if (Settings.SuperFX)
2446 Map_SuperFXLoROMMap();
2447 else
2448 if (Settings.SA1)
2449 {
2450 if (Multi.cartType == 5)
2451 Map_BSSA1LoROMMap();
2452 else
2453 Map_SA1LoROMMap();
2454 }
2455 else
2456 if (Settings.SDD1)
2457 Map_SDD1LoROMMap();
2458 else
2459 if (ExtendedFormat != NOPE)
2460 Map_JumboLoROMMap();
2461 else
2462 if (strncmp(ROMName, "WANDERERS FROM YS", 17) == 0)
2463 Map_NoMAD1LoROMMap();
2464 else
2465 if (Multi.cartType == 3)
2466 if (strncmp(ROMName, "SOUND NOVEL-TCOOL", 17) == 0 ||
2467 strncmp(ROMName, "DERBY STALLION 96", 17) == 0)
2468 Map_BSCartLoROMMap(1);
2469 else
2470 Map_BSCartLoROMMap(0);
2471 else
2472 if (strncmp(ROMName, "SOUND NOVEL-TCOOL", 17) == 0 ||
2473 strncmp(ROMName, "DERBY STALLION 96", 17) == 0)
2474 Map_ROM24MBSLoROMMap();
2475 else
2476 if (strncmp(ROMName, "THOROUGHBRED BREEDER3", 21) == 0 ||
2477 strncmp(ROMName, "RPG-TCOOL 2", 11) == 0)
2478 Map_SRAM512KLoROMMap();
2479 else
2480 if (strncmp(ROMName, "ADD-ON BASE CASSETE", 19) == 0)
2481 {
2482 if (Multi.cartType == 4)
2483 {
2484 SRAMSize = Multi.sramSizeA;
2485 Map_SufamiTurboLoROMMap();
2486 }
2487 else
2488 {
2489 SRAMSize = 5;
2490 Map_SufamiTurboPseudoLoROMMap();
2491 }
2492 }
2493 else
2494 Map_LoROMMap();
2495 }
2496
2497 Checksum_Calculate();
2498
2499 bool8 isChecksumOK = (ROMChecksum + ROMComplementChecksum == 0xffff) &
2500 (ROMChecksum == CalculatedChecksum);
2501
2502 //// Build more ROM information
2503
2504 // CRC32
2505 if (!Settings.BS || Settings.BSXItself) // Not BS Dump
2506 {
2507 ROMCRC32 = caCRC32(ROM, CalculatedSize);
2508 sha256sum(ROM, CalculatedSize, ROMSHA256);
2509 }
2510 else // Convert to correct format before scan
2511 {
2512 int offset = HiROM ? 0xffc0 : 0x7fc0;
2513 // Backup
2514 uint8 BSMagic0 = ROM[offset + 22],
2515 BSMagic1 = ROM[offset + 23];
2516 // uCONSRT standard
2517 ROM[offset + 22] = 0x42;
2518 ROM[offset + 23] = 0x00;
2519 // Calc
2520 ROMCRC32 = caCRC32(ROM, CalculatedSize);
2521 sha256sum(ROM, CalculatedSize, ROMSHA256);
2522 // Convert back
2523 ROM[offset + 22] = BSMagic0;
2524 ROM[offset + 23] = BSMagic1;
2525 }
2526
2527 // NTSC/PAL
2528 if (Settings.ForceNTSC)
2529 Settings.PAL = FALSE;
2530 else
2531 if (Settings.ForcePAL)
2532 Settings.PAL = TRUE;
2533 else
2534 if (!Settings.BS && (ROMRegion >= 2) && (ROMRegion <= 12))
2535 Settings.PAL = TRUE;
2536 else
2537 Settings.PAL = FALSE;
2538
2539 if (Settings.PAL)
2540 {
2541 Settings.FrameTime = Settings.FrameTimePAL;
2542 ROMFramesPerSecond = 50;
2543 }
2544 else
2545 {
2546 Settings.FrameTime = Settings.FrameTimeNTSC;
2547 ROMFramesPerSecond = 60;
2548 }
2549
2550 // truncate cart name
2551 ROMName[ROM_NAME_LEN - 1] = 0;
2552 if (strlen(ROMName))
2553 {
2554 char *p = ROMName + strlen(ROMName);
2555 if (p > ROMName + 21 && ROMName[20] == ' ')
2556 p = ROMName + 21;
2557 while (p > ROMName && *(p - 1) == ' ')
2558 p--;
2559 *p = 0;
2560 }
2561
2562 // SRAM size
2563 SRAMMask = SRAMSize ? ((1 << (SRAMSize + 3)) * 128) - 1 : 0;
2564
2565 // checksum
2566 if (!isChecksumOK || ((uint32) CalculatedSize > (uint32) (((1 << (ROMSize - 7)) * 128) * 1024)))
2567 {
2568 Settings.DisplayColor = BUILD_PIXEL(31, 31, 0);
2569 SET_UI_COLOR(255, 255, 0);
2570 }
2571
2572 // Use slight blue tint to indicate ROM was patched.
2573 if (Settings.IsPatched)
2574 {
2575 Settings.DisplayColor = BUILD_PIXEL(26, 26, 31);
2576 SET_UI_COLOR(216, 216, 255);
2577 }
2578
2579 if (Multi.cartType == 4)
2580 {
2581 Settings.DisplayColor = BUILD_PIXEL(0, 16, 31);
2582 SET_UI_COLOR(0, 128, 255);
2583 }
2584
2585 //// Initialize emulation
2586
2587 Timings.H_Max_Master = SNES_CYCLES_PER_SCANLINE;
2588 Timings.H_Max = Timings.H_Max_Master;
2589 Timings.HBlankStart = SNES_HBLANK_START_HC;
2590 Timings.HBlankEnd = SNES_HBLANK_END_HC;
2591 Timings.HDMAInit = SNES_HDMA_INIT_HC;
2592 Timings.HDMAStart = SNES_HDMA_START_HC;
2593 Timings.RenderPos = SNES_RENDER_START_HC;
2594 Timings.V_Max_Master = Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER;
2595 Timings.V_Max = Timings.V_Max_Master;
2596 /* From byuu: The total delay time for both the initial (H)DMA sync (to the DMA clock),
2597 and the end (H)DMA sync (back to the last CPU cycle's mcycle rate (6, 8, or 12)) always takes between 12-24 mcycles.
2598 Possible delays: { 12, 14, 16, 18, 20, 22, 24 }
2599 XXX: Snes9x can't emulate this timing :( so let's use the average value... */
2600 Timings.DMACPUSync = 18;
2601 /* If the CPU is halted (i.e. for DMA) while /NMI goes low, the NMI will trigger
2602 after the DMA completes (even if /NMI goes high again before the DMA
2603 completes). In this case, there is a 24-30 cycle delay between the end of DMA
2604 and the NMI handler, time enough for an instruction or two. */
2605 // Wild Guns, Mighty Morphin Power Rangers - The Fighting Edition
2606 Timings.NMIDMADelay = 24;
2607 Timings.IRQTriggerCycles = 14;
2608 Timings.APUSpeedup = 0;
2609 S9xAPUTimingSetSpeedup(Timings.APUSpeedup);
2610
2611 IPPU.TotalEmulatedFrames = 0;
2612
2613 //// Hack games
2614
2615 ApplyROMFixes();
2616
2617 //// Show ROM information
2618 char displayName[ROM_NAME_LEN];
2619
2620 strcpy(RawROMName, ROMName);
2621 sprintf(displayName, "%s", SafeANK(ROMName));
2622 sprintf(ROMName, "%s", Safe(ROMName));
2623 sprintf(ROMId, "%s", Safe(ROMId));
2624
2625 sprintf(String, "\"%s\" [%s] %s, %s, %s, %s, SRAM:%s, ID:%s, CRC32:%08X",
2626 displayName, isChecksumOK ? "checksum ok" : ((Multi.cartType == 4) ? "no checksum" : "bad checksum"),
2627 MapType(), Size(), KartContents(), Settings.PAL ? "PAL" : "NTSC", StaticRAMSize(), ROMId, ROMCRC32);
2628 S9xMessage(S9X_INFO, S9X_ROM_INFO, String);
2629
2630 Settings.ForceLoROM = FALSE;
2631 Settings.ForceHiROM = FALSE;
2632 Settings.ForceHeader = FALSE;
2633 Settings.ForceNoHeader = FALSE;
2634 Settings.ForceInterleaved = FALSE;
2635 Settings.ForceInterleaved2 = FALSE;
2636 Settings.ForceInterleaveGD24 = FALSE;
2637 Settings.ForceNotInterleaved = FALSE;
2638 Settings.ForcePAL = FALSE;
2639 Settings.ForceNTSC = FALSE;
2640
2641 Settings.TakeScreenshot = FALSE;
2642
2643 if (stopMovie)
2644 S9xMovieStop(TRUE);
2645
2646 if (PostRomInitFunc)
2647 PostRomInitFunc();
2648
2649 S9xVerifyControllers();
2650}
2651
2652// memory map
2653
2654uint32 CMemory::map_mirror (uint32 size, uint32 pos)
2655{
2656 // from bsnes
2657 if (size == 0)
2658 return (0);
2659 if (pos < size)
2660 return (pos);
2661
2662 uint32 mask = 1 << 31;
2663 while (!(pos & mask))
2664 mask >>= 1;
2665
2666 if (size <= (pos & mask))
2667 return (map_mirror(size, pos - mask));
2668 else
2669 return (mask + map_mirror(size - mask, pos - mask));
2670}
2671
2672void CMemory::map_lorom (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size)
2673{
2674 uint32 c, i, p, addr;
2675
2676 for (c = bank_s; c <= bank_e; c++)
2677 {
2678 for (i = addr_s; i <= addr_e; i += 0x1000)
2679 {
2680 p = (c << 4) | (i >> 12);
2681 addr = (c & 0x7f) * 0x8000;
2682 Map[p] = ROM + map_mirror(size, addr) - (i & 0x8000);
2683 BlockIsROM[p] = TRUE;
2684 BlockIsRAM[p] = FALSE;
2685 }
2686 }
2687}
2688
2689void CMemory::map_hirom (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size)
2690{
2691 uint32 c, i, p, addr;
2692
2693 for (c = bank_s; c <= bank_e; c++)
2694 {
2695 for (i = addr_s; i <= addr_e; i += 0x1000)
2696 {
2697 p = (c << 4) | (i >> 12);
2698 addr = c << 16;
2699 Map[p] = ROM + map_mirror(size, addr);
2700 BlockIsROM[p] = TRUE;
2701 BlockIsRAM[p] = FALSE;
2702 }
2703 }
2704}
2705
2706void CMemory::map_lorom_offset (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size, uint32 offset)
2707{
2708 uint32 c, i, p, addr;
2709
2710 for (c = bank_s; c <= bank_e; c++)
2711 {
2712 for (i = addr_s; i <= addr_e; i += 0x1000)
2713 {
2714 p = (c << 4) | (i >> 12);
2715 addr = ((c - bank_s) & 0x7f) * 0x8000;
2716 Map[p] = ROM + offset + map_mirror(size, addr) - (i & 0x8000);
2717 BlockIsROM[p] = TRUE;
2718 BlockIsRAM[p] = FALSE;
2719 }
2720 }
2721}
2722
2723void CMemory::map_hirom_offset (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size, uint32 offset)
2724{
2725 uint32 c, i, p, addr;
2726
2727 for (c = bank_s; c <= bank_e; c++)
2728 {
2729 for (i = addr_s; i <= addr_e; i += 0x1000)
2730 {
2731 p = (c << 4) | (i >> 12);
2732 addr = (c - bank_s) << 16;
2733 Map[p] = ROM + offset + map_mirror(size, addr);
2734 BlockIsROM[p] = TRUE;
2735 BlockIsRAM[p] = FALSE;
2736 }
2737 }
2738}
2739
2740void CMemory::map_space (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint8 *data)
2741{
2742 uint32 c, i, p;
2743
2744 for (c = bank_s; c <= bank_e; c++)
2745 {
2746 for (i = addr_s; i <= addr_e; i += 0x1000)
2747 {
2748 p = (c << 4) | (i >> 12);
2749 Map[p] = data;
2750 BlockIsROM[p] = FALSE;
2751 BlockIsRAM[p] = TRUE;
2752 }
2753 }
2754}
2755
2756void CMemory::map_index (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, int index, int type)
2757{
2758 uint32 c, i, p;
2759 bool8 isROM, isRAM;
2760
2761 isROM = ((type == MAP_TYPE_I_O) || (type == MAP_TYPE_RAM)) ? FALSE : TRUE;
2762 isRAM = ((type == MAP_TYPE_I_O) || (type == MAP_TYPE_ROM)) ? FALSE : TRUE;
2763
2764 for (c = bank_s; c <= bank_e; c++)
2765 {
2766 for (i = addr_s; i <= addr_e; i += 0x1000)
2767 {
2768 p = (c << 4) | (i >> 12);
2769 Map[p] = (uint8 *) (pint) index;
2770 BlockIsROM[p] = isROM;
2771 BlockIsRAM[p] = isRAM;
2772 }
2773 }
2774}
2775
2776void CMemory::map_System (void)
2777{
2778 // will be overwritten
2779 map_space(0x00, 0x3f, 0x0000, 0x1fff, RAM);
2780 map_index(0x00, 0x3f, 0x2000, 0x3fff, MAP_PPU, MAP_TYPE_I_O);
2781 map_index(0x00, 0x3f, 0x4000, 0x5fff, MAP_CPU, MAP_TYPE_I_O);
2782 map_space(0x80, 0xbf, 0x0000, 0x1fff, RAM);
2783 map_index(0x80, 0xbf, 0x2000, 0x3fff, MAP_PPU, MAP_TYPE_I_O);
2784 map_index(0x80, 0xbf, 0x4000, 0x5fff, MAP_CPU, MAP_TYPE_I_O);
2785}
2786
2787void CMemory::map_WRAM (void)
2788{
2789 // will overwrite others
2790 map_space(0x7e, 0x7e, 0x0000, 0xffff, RAM);
2791 map_space(0x7f, 0x7f, 0x0000, 0xffff, RAM + 0x10000);
2792}
2793
2794void CMemory::map_LoROMSRAM (void)
2795{
2796 uint32 hi;
2797
2798 if (SRAMSize == 0)
2799 return;
2800
2801 if (ROMSize > 11 || SRAMSize > 5)
2802 hi = 0x7fff;
2803 else
2804 hi = 0xffff;
2805
2806 map_index(0x70, 0x7d, 0x0000, hi, MAP_LOROM_SRAM, MAP_TYPE_RAM);
2807 map_index(0xf0, 0xff, 0x0000, hi, MAP_LOROM_SRAM, MAP_TYPE_RAM);
2808}
2809
2810void CMemory::map_HiROMSRAM (void)
2811{
2812 map_index(0x20, 0x3f, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
2813 map_index(0xa0, 0xbf, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
2814}
2815
2816void CMemory::map_DSP (void)
2817{
2818 switch (DSP0.maptype)
2819 {
2820 case M_DSP1_LOROM_S:
2821 map_index(0x20, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
2822 map_index(0xa0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
2823 break;
2824
2825 case M_DSP1_LOROM_L:
2826 map_index(0x60, 0x6f, 0x0000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
2827 map_index(0xe0, 0xef, 0x0000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
2828 break;
2829
2830 case M_DSP1_HIROM:
2831 map_index(0x00, 0x1f, 0x6000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
2832 map_index(0x80, 0x9f, 0x6000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
2833 break;
2834
2835 case M_DSP2_LOROM:
2836 map_index(0x20, 0x3f, 0x6000, 0x6fff, MAP_DSP, MAP_TYPE_I_O);
2837 map_index(0x20, 0x3f, 0x8000, 0xbfff, MAP_DSP, MAP_TYPE_I_O);
2838 map_index(0xa0, 0xbf, 0x6000, 0x6fff, MAP_DSP, MAP_TYPE_I_O);
2839 map_index(0xa0, 0xbf, 0x8000, 0xbfff, MAP_DSP, MAP_TYPE_I_O);
2840 break;
2841
2842 case M_DSP3_LOROM:
2843 map_index(0x20, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
2844 map_index(0xa0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
2845 break;
2846
2847 case M_DSP4_LOROM:
2848 map_index(0x30, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
2849 map_index(0xb0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
2850 break;
2851 }
2852}
2853
2854void CMemory::map_C4 (void)
2855{
2856 map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_C4, MAP_TYPE_I_O);
2857 map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_C4, MAP_TYPE_I_O);
2858}
2859
2860void CMemory::map_OBC1 (void)
2861{
2862 map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_OBC_RAM, MAP_TYPE_I_O);
2863 map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_OBC_RAM, MAP_TYPE_I_O);
2864}
2865
2866void CMemory::map_SetaRISC (void)
2867{
2868 map_index(0x00, 0x3f, 0x3000, 0x3fff, MAP_SETA_RISC, MAP_TYPE_I_O);
2869 map_index(0x80, 0xbf, 0x3000, 0x3fff, MAP_SETA_RISC, MAP_TYPE_I_O);
2870}
2871
2872void CMemory::map_SetaDSP (void)
2873{
2874 // where does the SETA chip access, anyway?
2875 // please confirm this?
2876 map_index(0x68, 0x6f, 0x0000, 0x7fff, MAP_SETA_DSP, MAP_TYPE_RAM);
2877 // and this!
2878 map_index(0x60, 0x67, 0x0000, 0x3fff, MAP_SETA_DSP, MAP_TYPE_I_O);
2879
2880 // ST-0010:
2881 // map_index(0x68, 0x6f, 0x0000, 0x0fff, MAP_SETA_DSP, ?);
2882}
2883
2884void CMemory::map_WriteProtectROM (void)
2885{
2886 memmove((void *) WriteMap, (void *) Map, sizeof(Map));
2887
2888 for (int c = 0; c < 0x1000; c++)
2889 {
2890 if (BlockIsROM[c])
2891 WriteMap[c] = (uint8 *) MAP_NONE;
2892 }
2893}
2894
2895void CMemory::Map_Initialize (void)
2896{
2897 for (int c = 0; c < 0x1000; c++)
2898 {
2899 Map[c] = (uint8 *) MAP_NONE;
2900 WriteMap[c] = (uint8 *) MAP_NONE;
2901 BlockIsROM[c] = FALSE;
2902 BlockIsRAM[c] = FALSE;
2903 }
2904}
2905
2906void CMemory::Map_LoROMMap (void)
2907{
2908 printf("Map_LoROMMap\n");
2909 map_System();
2910
2911 map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
2912 map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize);
2913 map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
2914 map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize);
2915
2916 if (Settings.DSP)
2917 map_DSP();
2918 else
2919 if (Settings.C4)
2920 map_C4();
2921 else
2922 if (Settings.OBC1)
2923 map_OBC1();
2924 else
2925 if (Settings.SETA == ST_018)
2926 map_SetaRISC();
2927
2928 map_LoROMSRAM();
2929 map_WRAM();
2930
2931 map_WriteProtectROM();
2932}
2933
2934void CMemory::Map_NoMAD1LoROMMap (void)
2935{
2936 printf("Map_NoMAD1LoROMMap\n");
2937 map_System();
2938
2939 map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
2940 map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize);
2941 map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
2942 map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize);
2943
2944 map_index(0x70, 0x7f, 0x0000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
2945 map_index(0xf0, 0xff, 0x0000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
2946
2947 map_WRAM();
2948
2949 map_WriteProtectROM();
2950}
2951
2952void CMemory::Map_JumboLoROMMap (void)
2953{
2954 // XXX: Which game uses this?
2955 printf("Map_JumboLoROMMap\n");
2956 map_System();
2957
2958 map_lorom_offset(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize - 0x400000, 0x400000);
2959 map_lorom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize - 0x600000, 0x600000);
2960 map_lorom_offset(0x80, 0xbf, 0x8000, 0xffff, 0x400000, 0);
2961 map_lorom_offset(0xc0, 0xff, 0x0000, 0xffff, 0x400000, 0x200000);
2962
2963 map_LoROMSRAM();
2964 map_WRAM();
2965
2966 map_WriteProtectROM();
2967}
2968
2969void CMemory::Map_ROM24MBSLoROMMap (void)
2970{
2971 // PCB: BSC-1A5M-01, BSC-1A7M-10
2972 printf("Map_ROM24MBSLoROMMap\n");
2973 map_System();
2974
2975 map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x100000, 0);
2976 map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, 0x100000, 0x100000);
2977 map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x100000, 0x200000);
2978 map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, 0x100000, 0x100000);
2979
2980 map_LoROMSRAM();
2981 map_WRAM();
2982
2983 map_WriteProtectROM();
2984}
2985
2986void CMemory::Map_SRAM512KLoROMMap (void)
2987{
2988 printf("Map_SRAM512KLoROMMap\n");
2989 map_System();
2990
2991 map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
2992 map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize);
2993 map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
2994 map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize);
2995
2996 map_space(0x70, 0x70, 0x0000, 0xffff, SRAM);
2997 map_space(0x71, 0x71, 0x0000, 0xffff, SRAM + 0x8000);
2998 map_space(0x72, 0x72, 0x0000, 0xffff, SRAM + 0x10000);
2999 map_space(0x73, 0x73, 0x0000, 0xffff, SRAM + 0x18000);
3000
3001 map_WRAM();
3002
3003 map_WriteProtectROM();
3004}
3005
3006void CMemory::Map_SufamiTurboLoROMMap (void)
3007{
3008 printf("Map_SufamiTurboLoROMMap\n");
3009 map_System();
3010
3011 map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x40000, 0);
3012 map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3013 map_lorom_offset(0x40, 0x5f, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
3014 map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x40000, 0);
3015 map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3016 map_lorom_offset(0xc0, 0xdf, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
3017
3018 if (Multi.sramSizeA)
3019 {
3020 map_index(0x60, 0x63, 0x8000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
3021 map_index(0xe0, 0xe3, 0x8000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
3022 }
3023
3024 if (Multi.sramSizeB)
3025 {
3026 map_index(0x70, 0x73, 0x8000, 0xffff, MAP_LOROM_SRAM_B, MAP_TYPE_RAM);
3027 map_index(0xf0, 0xf3, 0x8000, 0xffff, MAP_LOROM_SRAM_B, MAP_TYPE_RAM);
3028 }
3029
3030 map_WRAM();
3031
3032 map_WriteProtectROM();
3033}
3034
3035void CMemory::Map_SufamiTurboPseudoLoROMMap (void)
3036{
3037 // for combined images
3038 printf("Map_SufamiTurboPseudoLoROMMap\n");
3039 map_System();
3040
3041 map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x40000, 0);
3042 map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, 0x100000, 0x100000);
3043 map_lorom_offset(0x40, 0x5f, 0x8000, 0xffff, 0x100000, 0x200000);
3044 map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x40000, 0);
3045 map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, 0x100000, 0x100000);
3046 map_lorom_offset(0xc0, 0xdf, 0x8000, 0xffff, 0x100000, 0x200000);
3047
3048 // I don't care :P
3049 map_space(0x60, 0x63, 0x8000, 0xffff, SRAM - 0x8000);
3050 map_space(0xe0, 0xe3, 0x8000, 0xffff, SRAM - 0x8000);
3051 map_space(0x70, 0x73, 0x8000, 0xffff, SRAM + 0x4000 - 0x8000);
3052 map_space(0xf0, 0xf3, 0x8000, 0xffff, SRAM + 0x4000 - 0x8000);
3053
3054 map_WRAM();
3055
3056 map_WriteProtectROM();
3057}
3058
3059void CMemory::Map_SuperFXLoROMMap (void)
3060{
3061 printf("Map_SuperFXLoROMMap\n");
3062 map_System();
3063
3064 // Replicate the first 2Mb of the ROM at ROM + 2MB such that each 32K
3065 // block is repeated twice in each 64K block.
3066 for (int c = 0; c < 64; c++)
3067 {
3068 memmove(&ROM[0x200000 + c * 0x10000], &ROM[c * 0x8000], 0x8000);
3069 memmove(&ROM[0x208000 + c * 0x10000], &ROM[c * 0x8000], 0x8000);
3070 }
3071
3072 map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
3073 map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
3074
3075 map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize, 0);
3076 map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0);
3077
3078 map_space(0x00, 0x3f, 0x6000, 0x7fff, SRAM - 0x6000);
3079 map_space(0x80, 0xbf, 0x6000, 0x7fff, SRAM - 0x6000);
3080 map_space(0x70, 0x70, 0x0000, 0xffff, SRAM);
3081 map_space(0x71, 0x71, 0x0000, 0xffff, SRAM + 0x10000);
3082
3083 map_WRAM();
3084
3085 map_WriteProtectROM();
3086}
3087
3088void CMemory::Map_SetaDSPLoROMMap (void)
3089{
3090 printf("Map_SetaDSPLoROMMap\n");
3091 map_System();
3092
3093 map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
3094 map_lorom(0x40, 0x7f, 0x8000, 0xffff, CalculatedSize);
3095 map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
3096 map_lorom(0xc0, 0xff, 0x8000, 0xffff, CalculatedSize);
3097
3098 map_SetaDSP();
3099
3100 map_LoROMSRAM();
3101 map_WRAM();
3102
3103 map_WriteProtectROM();
3104}
3105
3106void CMemory::Map_SDD1LoROMMap (void)
3107{
3108 printf("Map_SDD1LoROMMap\n");
3109 map_System();
3110
3111 map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
3112 map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
3113
3114 map_hirom_offset(0x60, 0x7f, 0x0000, 0xffff, CalculatedSize, 0);
3115 map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0); // will be overwritten dynamically
3116
3117 map_index(0x70, 0x7f, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
3118 map_index(0xa0, 0xbf, 0x6000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
3119
3120 map_WRAM();
3121
3122 map_WriteProtectROM();
3123}
3124
3125void CMemory::Map_SA1LoROMMap (void)
3126{
3127 printf("Map_SA1LoROMMap\n");
3128 map_System();
3129
3130 map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
3131 map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
3132
3133 map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0);
3134
3135 map_space(0x00, 0x3f, 0x3000, 0x37ff, FillRAM);
3136 map_space(0x80, 0xbf, 0x3000, 0x37ff, FillRAM);
3137 map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O);
3138 map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O);
3139
3140 for (int c = 0x40; c < 0x4f; c++)
3141 map_space(c, c, 0x0000, 0xffff, SRAM + (c & 3) * 0x10000);
3142
3143 map_WRAM();
3144
3145 map_WriteProtectROM();
3146
3147 // Now copy the map and correct it for the SA1 CPU.
3148 memmove((void *) SA1.Map, (void *) Map, sizeof(Map));
3149 memmove((void *) SA1.WriteMap, (void *) WriteMap, sizeof(WriteMap));
3150
3151 // SA-1 Banks 00->3f and 80->bf
3152 for (int c = 0x000; c < 0x400; c += 0x10)
3153 {
3154 SA1.Map[c + 0] = SA1.Map[c + 0x800] = FillRAM + 0x3000;
3155 SA1.Map[c + 1] = SA1.Map[c + 0x801] = (uint8 *) MAP_NONE;
3156 SA1.WriteMap[c + 0] = SA1.WriteMap[c + 0x800] = FillRAM + 0x3000;
3157 SA1.WriteMap[c + 1] = SA1.WriteMap[c + 0x801] = (uint8 *) MAP_NONE;
3158 }
3159
3160 // SA-1 Banks 40->4f
3161 for (int c = 0x400; c < 0x500; c++)
3162 SA1.Map[c] = SA1.WriteMap[c] = (uint8*)MAP_HIROM_SRAM;
3163
3164 // SA-1 Banks 60->6f
3165 for (int c = 0x600; c < 0x700; c++)
3166 SA1.Map[c] = SA1.WriteMap[c] = (uint8 *) MAP_BWRAM_BITMAP;
3167
3168 BWRAM = SRAM;
3169}
3170
3171void CMemory::Map_BSSA1LoROMMap(void)
3172{
3173 printf("Map_BSSA1LoROMMap\n");
3174 map_System();
3175
3176 map_lorom_offset(0x00, 0x3f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3177 map_lorom_offset(0x80, 0xbf, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3178
3179 map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3180
3181 map_space(0x00, 0x3f, 0x3000, 0x3fff, FillRAM);
3182 map_space(0x80, 0xbf, 0x3000, 0x3fff, FillRAM);
3183 map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O);
3184 map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O);
3185
3186 for (int c = 0x40; c < 0x80; c++)
3187 map_space(c, c, 0x0000, 0xffff, SRAM + (c & 1) * 0x10000);
3188
3189 map_WRAM();
3190
3191 map_WriteProtectROM();
3192
3193 // Now copy the map and correct it for the SA1 CPU.
3194 memmove((void *) SA1.Map, (void *) Map, sizeof(Map));
3195 memmove((void *) SA1.WriteMap, (void *) WriteMap, sizeof(WriteMap));
3196
3197 // SA-1 Banks 00->3f and 80->bf
3198 for (int c = 0x000; c < 0x400; c += 0x10)
3199 {
3200 SA1.Map[c + 0] = SA1.Map[c + 0x800] = FillRAM + 0x3000;
3201 SA1.Map[c + 1] = SA1.Map[c + 0x801] = (uint8 *) MAP_NONE;
3202 SA1.WriteMap[c + 0] = SA1.WriteMap[c + 0x800] = FillRAM + 0x3000;
3203 SA1.WriteMap[c + 1] = SA1.WriteMap[c + 0x801] = (uint8 *) MAP_NONE;
3204 }
3205
3206 // SA-1 Banks 60->6f
3207 for (int c = 0x600; c < 0x700; c++)
3208 SA1.Map[c] = SA1.WriteMap[c] = (uint8 *) MAP_BWRAM_BITMAP;
3209
3210 BWRAM = SRAM;
3211}
3212
3213void CMemory::Map_HiROMMap (void)
3214{
3215 printf("Map_HiROMMap\n");
3216 map_System();
3217
3218 map_hirom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
3219 map_hirom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize);
3220 map_hirom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
3221 map_hirom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize);
3222
3223 if (Settings.DSP)
3224 map_DSP();
3225
3226 map_HiROMSRAM();
3227 map_WRAM();
3228
3229 map_WriteProtectROM();
3230}
3231
3232void CMemory::Map_ExtendedHiROMMap (void)
3233{
3234 printf("Map_ExtendedHiROMMap\n");
3235 map_System();
3236
3237 map_hirom_offset(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize - 0x400000, 0x400000);
3238 map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize - 0x400000, 0x400000);
3239 map_hirom_offset(0x80, 0xbf, 0x8000, 0xffff, 0x400000, 0);
3240 map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, 0x400000, 0);
3241
3242 map_HiROMSRAM();
3243 map_WRAM();
3244
3245 map_WriteProtectROM();
3246}
3247
3248void CMemory::Map_SPC7110HiROMMap (void)
3249{
3250 printf("Map_SPC7110HiROMMap\n");
3251 map_System();
3252
3253 map_index(0x00, 0x00, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
3254 map_hirom(0x00, 0x0f, 0x8000, 0xffff, CalculatedSize);
3255 map_index(0x30, 0x30, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
3256 if(Memory.ROMSize >= 13)
3257 map_hirom_offset(0x40, 0x4f, 0x0000, 0xffff, CalculatedSize, 0x600000);
3258 map_index(0x50, 0x50, 0x0000, 0xffff, MAP_SPC7110_DRAM, MAP_TYPE_ROM);
3259 map_hirom(0x80, 0x8f, 0x8000, 0xffff, CalculatedSize);
3260 map_hirom_offset(0xc0, 0xcf, 0x0000, 0xffff, CalculatedSize, 0);
3261 map_index(0xd0, 0xff, 0x0000, 0xffff, MAP_SPC7110_ROM, MAP_TYPE_ROM);
3262
3263 map_WRAM();
3264
3265 map_WriteProtectROM();
3266}
3267
3268void CMemory::Map_BSCartLoROMMap(uint8 mapping)
3269{
3270 printf("Map_BSCartLoROMMap\n");
3271
3272 BSX.MMC[0x02] = 0x00;
3273 BSX.MMC[0x0C] = 0x80;
3274
3275 map_System();
3276
3277 if (mapping)
3278 {
3279 map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x100000, 0);
3280 map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, 0x100000, 0x100000);
3281 map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x100000, 0x200000);
3282 map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, 0x100000, 0x100000);
3283 }
3284 else
3285 {
3286 map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
3287 map_lorom(0x40, 0x7f, 0x0000, 0x7fff, CalculatedSize);
3288 map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
3289 map_lorom(0xc0, 0xff, 0x0000, 0x7fff, CalculatedSize);
3290 }
3291
3292 map_LoROMSRAM();
3293 map_index(0xc0, 0xef, 0x0000, 0xffff, MAP_BSX, MAP_TYPE_RAM);
3294 map_WRAM();
3295
3296 map_WriteProtectROM();
3297}
3298
3299void CMemory::Map_BSCartHiROMMap(void)
3300{
3301 printf("Map_BSCartHiROMMap\n");
3302
3303 BSX.MMC[0x02] = 0x80;
3304 BSX.MMC[0x0C] = 0x80;
3305
3306 map_System();
3307 map_hirom_offset(0x00, 0x1f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3308 map_hirom_offset(0x20, 0x3f, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
3309 map_hirom_offset(0x40, 0x5f, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3310 map_hirom_offset(0x60, 0x7f, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
3311 map_hirom_offset(0x80, 0x9f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3312 map_hirom_offset(0xa0, 0xbf, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
3313 map_hirom_offset(0xc0, 0xdf, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
3314
3315 if ((ROM[Multi.cartOffsetB + 0xFF00] == 0x4D)
3316 && (ROM[Multi.cartOffsetB + 0xFF02] == 0x50)
3317 && ((ROM[Multi.cartOffsetB + 0xFF06] & 0xF0) == 0x70))
3318 {
3319 //Type 7 Memory Pack detection - if detected, emulate it as Mask ROM
3320 map_hirom_offset(0xe0, 0xff, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
3321 }
3322 else
3323 {
3324 map_index(0xe0, 0xff, 0x0000, 0xffff, MAP_BSX, MAP_TYPE_RAM);
3325 }
3326
3327 map_HiROMSRAM();
3328 map_WRAM();
3329
3330 map_WriteProtectROM();
3331}
3332
3333// checksum
3334
3335uint16 CMemory::checksum_calc_sum (uint8 *data, uint32 length)
3336{
3337 uint16 sum = 0;
3338
3339 for (uint32 i = 0; i < length; i++)
3340 sum += data[i];
3341
3342 return (sum);
3343}
3344
3345uint16 CMemory::checksum_mirror_sum (uint8 *start, uint32 &length, uint32 mask)
3346{
3347 // from NSRT
3348 while (!(length & mask) && mask)
3349 mask >>= 1;
3350
3351 uint16 part1 = checksum_calc_sum(start, mask);
3352 uint16 part2 = 0;
3353
3354 uint32 next_length = length - mask;
3355 if (next_length)
3356 {
3357 part2 = checksum_mirror_sum(start + mask, next_length, mask >> 1);
3358
3359 while (next_length < mask)
3360 {
3361 next_length += next_length;
3362 part2 += part2;
3363 }
3364
3365 length = mask + mask;
3366 }
3367
3368 return (part1 + part2);
3369}
3370
3371void CMemory::Checksum_Calculate (void)
3372{
3373 // from NSRT
3374 uint16 sum = 0;
3375
3376 if (Settings.BS && !Settings.BSXItself)
3377 sum = checksum_calc_sum(ROM, CalculatedSize) - checksum_calc_sum(ROM + (HiROM ? 0xffb0 : 0x7fb0), 48);
3378 else
3379 if (Settings.SPC7110)
3380 {
3381 sum = checksum_calc_sum(ROM, CalculatedSize);
3382 if (CalculatedSize == 0x300000)
3383 sum += sum;
3384 }
3385 else
3386 {
3387 if (CalculatedSize & 0x7fff)
3388 sum = checksum_calc_sum(ROM, CalculatedSize);
3389 else
3390 {
3391 uint32 length = CalculatedSize;
3392 sum = checksum_mirror_sum(ROM, length);
3393 }
3394 }
3395
3396 CalculatedChecksum = sum;
3397}
3398
3399// information
3400
3401const char * CMemory::MapType (void)
3402{
3403 return (HiROM ? ((ExtendedFormat != NOPE) ? "ExHiROM": "HiROM") : "LoROM");
3404}
3405
3406const char * CMemory::StaticRAMSize (void)
3407{
3408 static char str[20];
3409
3410 if (SRAMSize > 16)
3411 strcpy(str, "Corrupt");
3412 else
3413 sprintf(str, "%dKbits", 8 * (SRAMMask + 1) / 1024);
3414
3415 return (str);
3416}
3417
3418const char * CMemory::Size (void)
3419{
3420 static char str[20];
3421
3422 if (Multi.cartType == 4)
3423 strcpy(str, "N/A");
3424 else
3425 if (ROMSize < 7 || ROMSize - 7 > 23)
3426 strcpy(str, "Corrupt");
3427 else
3428 sprintf(str, "%dMbits", 1 << (ROMSize - 7));
3429
3430 return (str);
3431}
3432
3433const char * CMemory::Revision (void)
3434{
3435 static char str[20];
3436
3437 sprintf(str, "1.%d", HiROM ? ((ExtendedFormat != NOPE) ? ROM[0x40ffdb] : ROM[0xffdb]) : ROM[0x7fdb]);
3438
3439 return (str);
3440}
3441
3442const char * CMemory::KartContents (void)
3443{
3444 static char str[64];
3445 static const char *contents[3] = { "ROM", "ROM+RAM", "ROM+RAM+BAT" };
3446
3447 char chip[20];
3448
3449 if (ROMType == 0 && !Settings.BS)
3450 return ("ROM");
3451
3452 if (Settings.BS)
3453 strcpy(chip, "+BS");
3454 else
3455 if (Settings.SuperFX)
3456 strcpy(chip, "+Super FX");
3457 else
3458 if (Settings.SDD1)
3459 strcpy(chip, "+S-DD1");
3460 else
3461 if (Settings.OBC1)
3462 strcpy(chip, "+OBC1");
3463 else
3464 if (Settings.SA1)
3465 strcpy(chip, "+SA-1");
3466 else
3467 if (Settings.SPC7110RTC)
3468 strcpy(chip, "+SPC7110+RTC");
3469 else
3470 if (Settings.SPC7110)
3471 strcpy(chip, "+SPC7110");
3472 else
3473 if (Settings.SRTC)
3474 strcpy(chip, "+S-RTC");
3475 else
3476 if (Settings.C4)
3477 strcpy(chip, "+C4");
3478 else
3479 if (Settings.SETA == ST_010)
3480 strcpy(chip, "+ST-010");
3481 else
3482 if (Settings.SETA == ST_011)
3483 strcpy(chip, "+ST-011");
3484 else
3485 if (Settings.SETA == ST_018)
3486 strcpy(chip, "+ST-018");
3487 else
3488 if (Settings.DSP)
3489 sprintf(chip, "+DSP-%d", Settings.DSP);
3490 else
3491 strcpy(chip, "");
3492
3493 if (Settings.MSU1)
3494 sprintf(chip + strlen(chip), "+MSU-1");
3495
3496 sprintf(str, "%s%s", contents[(ROMType & 0xf) % 3], chip);
3497
3498 return (str);
3499}
3500
3501const char * CMemory::Country (void)
3502{
3503 switch (ROMRegion)
3504 {
3505 case 0: return("Japan");
3506 case 1: return("USA and Canada");
3507 case 2: return("Oceania, Europe and Asia");
3508 case 3: return("Sweden");
3509 case 4: return("Finland");
3510 case 5: return("Denmark");
3511 case 6: return("France");
3512 case 7: return("Holland");
3513 case 8: return("Spain");
3514 case 9: return("Germany, Austria and Switzerland");
3515 case 10: return("Italy");
3516 case 11: return("Hong Kong and China");
3517 case 12: return("Indonesia");
3518 case 13: return("South Korea");
3519 default: return("Unknown");
3520 }
3521}
3522
3523const char * CMemory::PublishingCompany (void)
3524{
3525 if (CompanyId >= (int) (sizeof(nintendo_licensees) / sizeof(nintendo_licensees[0])) || CompanyId < 0)
3526 return ("Unknown");
3527
3528 if (nintendo_licensees[CompanyId] == NULL)
3529 return ("Unknown");
3530
3531 return (nintendo_licensees[CompanyId]);
3532}
3533
3534void CMemory::MakeRomInfoText (char *romtext)
3535{
3536 char temp[256];
3537
3538 romtext[0] = 0;
3539
3540 sprintf(temp, " Cart Name: %s", ROMName);
3541 strcat(romtext, temp);
3542 sprintf(temp, "\n Game Code: %s", ROMId);
3543 strcat(romtext, temp);
3544 sprintf(temp, "\n Contents: %s", KartContents());
3545 strcat(romtext, temp);
3546 sprintf(temp, "\n Map: %s", MapType());
3547 strcat(romtext, temp);
3548 sprintf(temp, "\n Speed: 0x%02X (%s)", ROMSpeed, (ROMSpeed & 0x10) ? "FastROM" : "SlowROM");
3549 strcat(romtext, temp);
3550 sprintf(temp, "\n Type: 0x%02X", ROMType);
3551 strcat(romtext, temp);
3552 sprintf(temp, "\n Size (calculated): %dMbits", CalculatedSize / 0x20000);
3553 strcat(romtext, temp);
3554 sprintf(temp, "\n Size (header): %s", Size());
3555 strcat(romtext, temp);
3556 sprintf(temp, "\n SRAM size: %s", StaticRAMSize());
3557 strcat(romtext, temp);
3558 sprintf(temp, "\nChecksum (calculated): 0x%04X", CalculatedChecksum);
3559 strcat(romtext, temp);
3560 sprintf(temp, "\n Checksum (header): 0x%04X", ROMChecksum);
3561 strcat(romtext, temp);
3562 sprintf(temp, "\n Complement (header): 0x%04X", ROMComplementChecksum);
3563 strcat(romtext, temp);
3564 sprintf(temp, "\n Video Output: %s", (ROMRegion > 12 || ROMRegion < 2) ? "NTSC 60Hz" : "PAL 50Hz");
3565 strcat(romtext, temp);
3566 sprintf(temp, "\n Revision: %s", Revision());
3567 strcat(romtext, temp);
3568 sprintf(temp, "\n Licensee: %s", PublishingCompany());
3569 strcat(romtext, temp);
3570 sprintf(temp, "\n Region: %s", Country());
3571 strcat(romtext, temp);
3572 sprintf(temp, "\n CRC32: 0x%08X", ROMCRC32);
3573 strcat(romtext, temp);
3574}
3575
3576// hack
3577
3578bool8 CMemory::match_na (const char *str)
3579{
3580 return (strcmp(ROMName, str) == 0);
3581}
3582
3583bool8 CMemory::match_nn (const char *str)
3584{
3585 return (strncmp(ROMName, str, strlen(str)) == 0);
3586}
3587
3588bool8 CMemory::match_nc (const char *str)
3589{
3590 return (strncasecmp(ROMName, str, strlen(str)) == 0);
3591}
3592
3593bool8 CMemory::match_id (const char *str)
3594{
3595 return (strncmp(ROMId, str, strlen(str)) == 0);
3596}
3597
3598void CMemory::ApplyROMFixes (void)
3599{
3600 Settings.BlockInvalidVRAMAccess = Settings.BlockInvalidVRAMAccessMaster;
3601
3602 if (Settings.DisableGameSpecificHacks)
3603 return;
3604
3605 // APU timing hacks
3606 if (match_na("CIRCUIT USA"))
3607 Timings.APUSpeedup = 3;
3608
3609 S9xAPUTimingSetSpeedup(Timings.APUSpeedup);
3610
3611 // Other timing hacks
3612 // The delay to sync CPU and DMA which Snes9x does not emulate.
3613 // Some games need really severe delay timing...
3614 if (match_na("BATTLE GRANDPRIX")) // Battle Grandprix
3615 Timings.DMACPUSync = 20;
3616 else if (match_na("KORYU NO MIMI ENG")) // Koryu no Mimi translation by rpgone)
3617 {
3618 // An infinite loop reads $4210 and checks NMI flag. This only works if LDA instruction executes before the NMI triggers,
3619 // which doesn't work very well with s9x's default DMA timing.
3620 Timings.DMACPUSync = 20;
3621 }
3622
3623 if (Timings.DMACPUSync != 18)
3624 printf("DMA sync: %d\n", Timings.DMACPUSync);
3625
3626 // SRAM initial value
3627 if (match_na("HITOMI3"))
3628 {
3629 SRAMSize = 1;
3630 SRAMMask = ((1 << (SRAMSize + 3)) * 128) - 1;
3631 }
3632
3633 // SRAM value fixes
3634 if (match_na("SUPER DRIFT OUT") || // Super Drift Out
3635 match_na("SATAN IS OUR FATHER!") ||
3636 match_na("goemon 4")) // Ganbare Goemon Kirakira Douchuu
3637 SNESGameFixes.SRAMInitialValue = 0x00;
3638
3639 // Additional game fixes by sanmaiwashi ...
3640 // XXX: unnecessary?
3641 if (match_na("SFX \xC5\xB2\xC4\xB6\xDE\xDD\xC0\xDE\xD1\xD3\xC9\xB6\xDE\xC0\xD8 1")) // SD Gundam Gaiden - Knight Gundam Monogatari
3642 SNESGameFixes.SRAMInitialValue = 0x6b;
3643
3644 // others: BS and ST-01x games are 0x00.
3645
3646 // OAM hacks :(
3647 // OAM hacks because we don't fully understand the behavior of the SNES.
3648 // Totally wacky display in 2P mode...
3649 // seems to need a disproven behavior, so we're definitely overlooking some other bug?
3650 if (match_nn("UNIRACERS")) // Uniracers
3651 {
3652 SNESGameFixes.Uniracers = TRUE;
3653 printf("Applied Uniracers hack.\n");
3654 }
3655
3656 // Render Position
3657 if (match_na("Sugoro Quest++"))
3658 Timings.RenderPos = 128;
3659 else if (match_na("FIREPOWER 2000"))
3660 Timings.RenderPos = 32;
3661 else if (match_na("DERBY STALLION 98"))
3662 Timings.RenderPos = 128;
3663 else if (match_na("AIR STRIKE PATROL") || match_na("DESERT FIGHTER"))
3664 Timings.RenderPos = 128; // Just hides shadow
3665 // From bsnes
3666 else if (match_na("NHL '94") || match_na("NHL PROHOCKEY'94"))
3667 Timings.RenderPos = 32;
3668 else if (match_na("ADVENTURES OF FRANKEN") && Settings.PAL)
3669 Timings.RenderPos = 32;
3670}
3671
3672// BPS % UPS % IPS
3673
3674// number decoding used for both BPS and UPS
3675static uint32 XPSdecode (const uint8 *data, unsigned &addr, unsigned size)
3676{
3677 uint32 offset = 0, shift = 1;
3678 while(addr < size) {
3679 uint8 x = data[addr++];
3680 offset += (x & 0x7f) * shift;
3681 if(x & 0x80) break;
3682 shift <<= 7;
3683 offset += shift;
3684 }
3685 return offset;
3686}
3687
3688//NOTE: UPS patches are *never* created against a headered ROM!
3689//this is per the UPS file specification. however, do note that it is
3690//technically possible for a non-compliant patcher to ignore this requirement.
3691//therefore, it is *imperative* that no emulator support such patches.
3692//thusly, we ignore the "long offset" parameter below. failure to do so would
3693//completely invalidate the purpose of UPS; which is to avoid header vs
3694//no-header patching errors that result in IPS patches having a 50/50 chance of
3695//being applied correctly.
3696
3697static bool8 ReadUPSPatch (Stream *r, long, int32 &rom_size)
3698{
3699 //Reader lacks size() and rewind(), so we need to read in the file to get its size
3700 uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ...
3701 uint32 size = 0;
3702 while(true) {
3703 int value = r->get_char();
3704 if(value == EOF) break;
3705 data[size++] = value;
3706 if(size >= 8 * 1024 * 1024) {
3707 //prevent buffer overflow: SNES-made UPS patches should never be this big anyway ...
3708 delete[] data;
3709 return false;
3710 }
3711 }
3712
3713 //4-byte header + 1-byte input size + 1-byte output size + 4-byte patch CRC32 + 4-byte unpatched CRC32 + 4-byte patched CRC32
3714 if(size < 18) { delete[] data; return false; } //patch is too small
3715
3716 uint32 addr = 0;
3717 if(data[addr++] != 'U') { delete[] data; return false; } //patch has an invalid header
3718 if(data[addr++] != 'P') { delete[] data; return false; } //...
3719 if(data[addr++] != 'S') { delete[] data; return false; } //...
3720 if(data[addr++] != '1') { delete[] data; return false; } //...
3721
3722 uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation
3723 uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size);
3724 uint32 px_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24);
3725 uint32 py_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24);
3726 uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24);
3727 if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted
3728 if(!Settings.IgnorePatchChecksum && (rom_crc32 != px_crc32) && (rom_crc32 != py_crc32)) { delete[] data; return false; } //patch is for a different ROM
3729
3730 uint32 px_size = XPSdecode(data, addr, size);
3731 uint32 py_size = XPSdecode(data, addr, size);
3732 uint32 out_size = ((uint32) rom_size == px_size) ? py_size : px_size;
3733 if(out_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer
3734
3735 //fill expanded area with 0x00s; so that XORing works as expected below.
3736 //note that this is needed (and works) whether output ROM is larger or smaller than pre-patched ROM
3737 for(unsigned i = min((uint32) rom_size, out_size); i < max((uint32) rom_size, out_size); i++) {
3738 Memory.ROM[i] = 0x00;
3739 }
3740
3741 uint32 relative = 0;
3742 while(addr < size - 12) {
3743 relative += XPSdecode(data, addr, size);
3744 while(addr < size - 12) {
3745 uint8 x = data[addr++];
3746 Memory.ROM[relative++] ^= x;
3747 if(!x) break;
3748 }
3749 }
3750
3751 rom_size = out_size;
3752 delete[] data;
3753
3754 uint32 out_crc32 = caCRC32(Memory.ROM, rom_size);
3755 if(Settings.IgnorePatchChecksum
3756 || ((rom_crc32 == px_crc32) && (out_crc32 == py_crc32))
3757 || ((rom_crc32 == py_crc32) && (out_crc32 == px_crc32))
3758 ) {
3759 Settings.IsPatched = 3;
3760 return true;
3761 } else {
3762 //technically, reaching here means that patching has failed.
3763 //we should return false, but unfortunately Memory.ROM has already
3764 //been modified above and cannot be undone. to do this properly, we
3765 //would need to make a copy of Memory.ROM, apply the patch, and then
3766 //copy that back to Memory.ROM.
3767 //
3768 //however, the only way for this case to happen is if the UPS patch file
3769 //itself is corrupted, which should be detected by the patch CRC32 check
3770 //above anyway. errors due to the wrong ROM or patch file being used are
3771 //already caught above.
3772 fprintf(stderr, "WARNING: UPS patching appears to have failed.\nGame may not be playable.\n");
3773 return true;
3774 }
3775}
3776
3777// header notes for UPS patches also apply to BPS
3778//
3779// logic taken from http://byuu.org/programming/bps and the accompanying source
3780//
3781static bool8 ReadBPSPatch (Stream *r, long, int32 &rom_size)
3782{
3783 uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ...
3784 uint32 size = 0;
3785 while(true) {
3786 int value = r->get_char();
3787 if(value == EOF) break;
3788 data[size++] = value;
3789 if(size >= 8 * 1024 * 1024) {
3790 //prevent buffer overflow: SNES-made BPS patches should never be this big anyway ...
3791 delete[] data;
3792 return false;
3793 }
3794 }
3795
3796 /* 4-byte header + 1-byte input size + 1-byte output size + 1-byte metadata size
3797 + 4-byte unpatched CRC32 + 4-byte patched CRC32 + 4-byte patch CRC32 */
3798 if(size < 19) { delete[] data; return false; } //patch is too small
3799
3800 uint32 addr = 0;
3801 if(data[addr++] != 'B') { delete[] data; return false; } //patch has an invalid header
3802 if(data[addr++] != 'P') { delete[] data; return false; } //...
3803 if(data[addr++] != 'S') { delete[] data; return false; } //...
3804 if(data[addr++] != '1') { delete[] data; return false; } //...
3805
3806 uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation
3807 uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size);
3808 uint32 source_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24);
3809 uint32 target_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24);
3810 uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24);
3811 if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted
3812 if(!Settings.IgnorePatchChecksum && rom_crc32 != source_crc32) { delete[] data; return false; } //patch is for a different ROM
3813
3814 XPSdecode(data, addr, size);
3815 uint32 target_size = XPSdecode(data, addr, size);
3816 uint32 metadata_size = XPSdecode(data, addr, size);
3817 addr += metadata_size;
3818
3819 if(target_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer
3820
3821 enum { SourceRead, TargetRead, SourceCopy, TargetCopy };
3822 uint32 outputOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0;
3823
3824 uint8 *patched_rom = new uint8[target_size];
3825 memset(patched_rom,0,target_size);
3826
3827 while(addr < size - 12) {
3828 uint32 length = XPSdecode(data, addr, size);
3829 uint32 mode = length & 3;
3830 length = (length >> 2) + 1;
3831
3832 switch((int)mode) {
3833 case SourceRead:
3834 while(length--) {
3835 patched_rom[outputOffset] = Memory.ROM[outputOffset];
3836 outputOffset++;
3837 }
3838 break;
3839 case TargetRead:
3840 while(length--) patched_rom[outputOffset++] = data[addr++];
3841 break;
3842 case SourceCopy:
3843 case TargetCopy:
3844 int32 offset = XPSdecode(data, addr, size);
3845 bool negative = offset & 1;
3846 offset >>= 1;
3847 if(negative) offset = -offset;
3848
3849 if(mode == SourceCopy) {
3850 sourceRelativeOffset += offset;
3851 while(length--) patched_rom[outputOffset++] = Memory.ROM[sourceRelativeOffset++];
3852 } else {
3853 targetRelativeOffset += offset;
3854 while(length--) patched_rom[outputOffset++] = patched_rom[targetRelativeOffset++];
3855 }
3856 break;
3857 }
3858 }
3859
3860 delete[] data;
3861
3862 uint32 out_crc32 = caCRC32(patched_rom, target_size);
3863 if(Settings.IgnorePatchChecksum || out_crc32 == target_crc32) {
3864 memcpy(Memory.ROM, patched_rom, target_size);
3865 rom_size = target_size;
3866 delete[] patched_rom;
3867 Settings.IsPatched = 2;
3868 return true;
3869 } else {
3870 delete[] patched_rom;
3871 fprintf(stderr, "WARNING: BPS patching failed.\nROM has not been altered.\n");
3872 return false;
3873 }
3874}
3875
3876static long ReadInt (Stream *r, unsigned nbytes)
3877{
3878 long v = 0;
3879
3880 while (nbytes--)
3881 {
3882 int c = r->get_char();
3883 if (c == EOF)
3884 return (-1);
3885 v = (v << 8) | (c & 0xFF);
3886 }
3887
3888 return (v);
3889}
3890
3891static bool8 ReadIPSPatch (Stream *r, long offset, int32 &rom_size)
3892{
3893 const int32 IPS_EOF = 0x00454F46l;
3894 int32 ofs;
3895 char fname[6];
3896
3897 fname[5] = 0;
3898 for (int i = 0; i < 5; i++)
3899 {
3900 int c = r->get_char();
3901 if (c == EOF)
3902 return (0);
3903 fname[i] = (char) c;
3904 }
3905
3906 if (strncmp(fname, "PATCH", 5))
3907 return (0);
3908
3909 for (;;)
3910 {
3911 long len, rlen;
3912 int rchar;
3913
3914 ofs = ReadInt(r, 3);
3915 if (ofs == -1)
3916 return (0);
3917
3918 if (ofs == IPS_EOF)
3919 break;
3920
3921 ofs -= offset;
3922
3923 len = ReadInt(r, 2);
3924 if (len == -1)
3925 return (0);
3926
3927 if (len)
3928 {
3929 if (ofs + len > CMemory::MAX_ROM_SIZE)
3930 return (0);
3931
3932 while (len--)
3933 {
3934 rchar = r->get_char();
3935 if (rchar == EOF)
3936 return (0);
3937 Memory.ROM[ofs++] = (uint8) rchar;
3938 }
3939
3940 if (ofs > rom_size)
3941 rom_size = ofs;
3942 }
3943 else
3944 {
3945 rlen = ReadInt(r, 2);
3946 if (rlen == -1)
3947 return (0);
3948
3949 rchar = r->get_char();
3950 if (rchar == EOF)
3951 return (0);
3952
3953 if (ofs + rlen > CMemory::MAX_ROM_SIZE)
3954 return (0);
3955
3956 while (rlen--)
3957 Memory.ROM[ofs++] = (uint8) rchar;
3958
3959 if (ofs > rom_size)
3960 rom_size = ofs;
3961 }
3962 }
3963
3964 ofs = ReadInt(r, 3);
3965 if (ofs != -1 && ofs - offset < rom_size)
3966 rom_size = ofs - offset;
3967
3968 Settings.IsPatched = 1;
3969 return (1);
3970}
3971
3972#ifdef UNZIP_SUPPORT
3973static int unzFindExtension (unzFile &file, const char *ext, bool restart, bool print, bool allowExact)
3974{
3975 unz_file_info info;
3976 int port, l = strlen(ext), e = allowExact ? 0 : 1;
3977
3978 if (restart)
3979 port = unzGoToFirstFile(file);
3980 else
3981 port = unzGoToNextFile(file);
3982
3983 while (port == UNZ_OK)
3984 {
3985 int len;
3986 char name[132];
3987
3988 unzGetCurrentFileInfo(file, &info, name, 128, NULL, 0, NULL, 0);
3989 len = strlen(name);
3990
3991 if (len >= l + e && name[len - l - 1] == '.' && strcasecmp(name + len - l, ext) == 0 && unzOpenCurrentFile(file) == UNZ_OK)
3992 {
3993 if (print)
3994 printf("Using patch %s", name);
3995
3996 return (port);
3997 }
3998
3999 port = unzGoToNextFile(file);
4000 }
4001
4002 return (port);
4003}
4004#endif
4005
4006void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &rom_size)
4007{
4008 Settings.IsPatched = false;
4009
4010 if (Settings.NoPatch)
4011 return;
4012
4013 FSTREAM patch_file = NULL;
4014 uint32 i;
4015 long offset = header ? 512 : 0;
4016 int ret;
4017 bool flag;
4018 char dir[_MAX_DIR + 1], drive[_MAX_DRIVE + 1], name[_MAX_FNAME + 1], ext[_MAX_EXT + 1], ips[_MAX_EXT + 3], fname[PATH_MAX + 1];
4019 const char *n;
4020
4021 _splitpath(rom_filename, drive, dir, name, ext);
4022
4023 // BPS
4024 _makepath(fname, drive, dir, name, "bps");
4025
4026 if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL)
4027 {
4028 printf("Using BPS patch %s", fname);
4029
4030 Stream *s = new fStream(patch_file);
4031 ret = ReadBPSPatch(s, 0, rom_size);
4032 s->closeStream();
4033
4034 if (ret)
4035 {
4036 printf("!\n");
4037 return;
4038 }
4039 else
4040 printf(" failed!\n");
4041 }
4042
4043#ifdef UNZIP_SUPPORT
4044 if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip"))
4045 {
4046 unzFile file = unzOpen(rom_filename);
4047 if (file)
4048 {
4049 int port = unzFindExtension(file, "bps");
4050 if (port == UNZ_OK)
4051 {
4052 printf(" in %s", rom_filename);
4053
4054 Stream *s = new unzStream(file);
4055 ret = ReadBPSPatch(s, offset, rom_size);
4056 delete s;
4057
4058 if (ret)
4059 printf("!\n");
4060 else
4061 printf(" failed!\n");
4062 }
4063 assert(unzClose(file) == UNZ_OK);
4064 }
4065 }
4066#endif
4067
4068 n = S9xGetFilename(".bps", PATCH_DIR);
4069
4070 if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL)
4071 {
4072 printf("Using BPS patch %s", n);
4073
4074 Stream *s = new fStream(patch_file);
4075 ret = ReadBPSPatch(s, 0, rom_size);
4076 s->closeStream();
4077
4078 if (ret)
4079 {
4080 printf("!\n");
4081 return;
4082 }
4083 else
4084 printf(" failed!\n");
4085 }
4086
4087 // UPS
4088
4089 _makepath(fname, drive, dir, name, "ups");
4090
4091 if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL)
4092 {
4093 printf("Using UPS patch %s", fname);
4094
4095 Stream *s = new fStream(patch_file);
4096 ret = ReadUPSPatch(s, 0, rom_size);
4097 s->closeStream();
4098
4099 if (ret)
4100 {
4101 printf("!\n");
4102 return;
4103 }
4104 else
4105 printf(" failed!\n");
4106 }
4107
4108#ifdef UNZIP_SUPPORT
4109 if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip"))
4110 {
4111 unzFile file = unzOpen(rom_filename);
4112 if (file)
4113 {
4114 int port = unzFindExtension(file, "ups");
4115 if (port == UNZ_OK)
4116 {
4117 printf(" in %s", rom_filename);
4118
4119 Stream *s = new unzStream(file);
4120 ret = ReadUPSPatch(s, offset, rom_size);
4121 delete s;
4122
4123 if (ret)
4124 printf("!\n");
4125 else
4126 printf(" failed!\n");
4127 }
4128 assert(unzClose(file) == UNZ_OK);
4129 }
4130 }
4131#endif
4132
4133 n = S9xGetFilename(".ups", PATCH_DIR);
4134
4135 if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL)
4136 {
4137 printf("Using UPS patch %s", n);
4138
4139 Stream *s = new fStream(patch_file);
4140 ret = ReadUPSPatch(s, 0, rom_size);
4141 s->closeStream();
4142
4143 if (ret)
4144 {
4145 printf("!\n");
4146 return;
4147 }
4148 else
4149 printf(" failed!\n");
4150 }
4151
4152 // IPS
4153
4154 _makepath(fname, drive, dir, name, "ips");
4155
4156 if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL)
4157 {
4158 printf("Using IPS patch %s", fname);
4159
4160 Stream *s = new fStream(patch_file);
4161 ret = ReadIPSPatch(s, offset, rom_size);
4162 s->closeStream();
4163
4164 if (ret)
4165 {
4166 printf("!\n");
4167 return;
4168 }
4169 else
4170 printf(" failed!\n");
4171 }
4172
4173 if (_MAX_EXT > 6)
4174 {
4175 i = 0;
4176 flag = false;
4177
4178 do
4179 {
4180 snprintf(ips, 8, "%03d.ips", i);
4181 _makepath(fname, drive, dir, name, ips);
4182
4183 if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
4184 break;
4185
4186 printf("Using IPS patch %s", fname);
4187
4188 Stream *s = new fStream(patch_file);
4189 ret = ReadIPSPatch(s, offset, rom_size);
4190 s->closeStream();
4191
4192 if (ret)
4193 {
4194 printf("!\n");
4195 flag = true;
4196 }
4197 else
4198 {
4199 printf(" failed!\n");
4200 break;
4201 }
4202 } while (++i < 1000);
4203
4204 if (flag)
4205 return;
4206 }
4207
4208 if (_MAX_EXT > 3)
4209 {
4210 i = 0;
4211 flag = false;
4212
4213 do
4214 {
4215 snprintf(ips, _MAX_EXT + 2, "ips%d", i);
4216 if (strlen(ips) > _MAX_EXT)
4217 break;
4218 _makepath(fname, drive, dir, name, ips);
4219
4220 if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
4221 break;
4222
4223 printf("Using IPS patch %s", fname);
4224
4225 Stream *s = new fStream(patch_file);
4226 ret = ReadIPSPatch(s, offset, rom_size);
4227 s->closeStream();
4228
4229 if (ret)
4230 {
4231 printf("!\n");
4232 flag = true;
4233 }
4234 else
4235 {
4236 printf(" failed!\n");
4237 break;
4238 }
4239 } while (++i != 0);
4240
4241 if (flag)
4242 return;
4243 }
4244
4245 if (_MAX_EXT > 2)
4246 {
4247 i = 0;
4248 flag = false;
4249
4250 do
4251 {
4252 snprintf(ips, 4, "ip%d", i);
4253 _makepath(fname, drive, dir, name, ips);
4254
4255 if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
4256 break;
4257
4258 printf("Using IPS patch %s", fname);
4259
4260 Stream *s = new fStream(patch_file);
4261 ret = ReadIPSPatch(s, offset, rom_size);
4262 s->closeStream();
4263
4264 if (ret)
4265 {
4266 printf("!\n");
4267 flag = true;
4268 }
4269 else
4270 {
4271 printf(" failed!\n");
4272 break;
4273 }
4274 } while (++i < 10);
4275
4276 if (flag)
4277 return;
4278 }
4279
4280#ifdef UNZIP_SUPPORT
4281 if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip"))
4282 {
4283 unzFile file = unzOpen(rom_filename);
4284 if (file)
4285 {
4286 int port = unzFindExtension(file, "ips");
4287 while (port == UNZ_OK)
4288 {
4289 printf(" in %s", rom_filename);
4290
4291 Stream *s = new unzStream(file);
4292 ret = ReadIPSPatch(s, offset, rom_size);
4293 delete s;
4294
4295 if (ret)
4296 {
4297 printf("!\n");
4298 flag = true;
4299 }
4300 else
4301 printf(" failed!\n");
4302
4303 port = unzFindExtension(file, "ips", false);
4304 }
4305
4306 if (!flag)
4307 {
4308 i = 0;
4309
4310 do
4311 {
4312 snprintf(ips, 8, "%03d.ips", i);
4313
4314 if (unzFindExtension(file, ips) != UNZ_OK)
4315 break;
4316
4317 printf(" in %s", rom_filename);
4318
4319 Stream *s = new unzStream(file);
4320 ret = ReadIPSPatch(s, offset, rom_size);
4321 delete s;
4322
4323 if (ret)
4324 {
4325 printf("!\n");
4326 flag = true;
4327 }
4328 else
4329 {
4330 printf(" failed!\n");
4331 break;
4332 }
4333
4334 if (unzFindExtension(file, ips, false, false) == UNZ_OK)
4335 printf("WARNING: Ignoring extra .%s files!\n", ips);
4336 } while (++i < 1000);
4337 }
4338
4339 if (!flag)
4340 {
4341 i = 0;
4342
4343 do
4344 {
4345 snprintf(ips, _MAX_EXT + 2, "ips%d", i);
4346 if (strlen(ips) > _MAX_EXT)
4347 break;
4348
4349 if (unzFindExtension(file, ips) != UNZ_OK)
4350 break;
4351
4352 printf(" in %s", rom_filename);
4353
4354 Stream *s = new unzStream(file);
4355 ret = ReadIPSPatch(s, offset, rom_size);
4356 delete s;
4357
4358 if (ret)
4359 {
4360 printf("!\n");
4361 flag = true;
4362 }
4363 else
4364 {
4365 printf(" failed!\n");
4366 break;
4367 }
4368
4369 if (unzFindExtension(file, ips, false, false) == UNZ_OK)
4370 printf("WARNING: Ignoring extra .%s files!\n", ips);
4371 } while (++i != 0);
4372 }
4373
4374 if (!flag)
4375 {
4376 i = 0;
4377
4378 do
4379 {
4380 snprintf(ips, 4, "ip%d", i);
4381
4382 if (unzFindExtension(file, ips) != UNZ_OK)
4383 break;
4384
4385 printf(" in %s", rom_filename);
4386
4387 Stream *s = new unzStream(file);
4388 ret = ReadIPSPatch(s, offset, rom_size);
4389 delete s;
4390
4391 if (ret)
4392 {
4393 printf("!\n");
4394 flag = true;
4395 }
4396 else
4397 {
4398 printf(" failed!\n");
4399 break;
4400 }
4401
4402 if (unzFindExtension(file, ips, false, false) == UNZ_OK)
4403 printf("WARNING: Ignoring extra .%s files!\n", ips);
4404 } while (++i < 10);
4405 }
4406
4407 assert(unzClose(file) == UNZ_OK);
4408
4409 if (flag)
4410 return;
4411 }
4412 }
4413#endif
4414
4415 n = S9xGetFilename(".ips", PATCH_DIR);
4416
4417 if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL)
4418 {
4419 printf("Using IPS patch %s", n);
4420
4421 Stream *s = new fStream(patch_file);
4422 ret = ReadIPSPatch(s, offset, rom_size);
4423 s->closeStream();
4424
4425 if (ret)
4426 {
4427 printf("!\n");
4428 return;
4429 }
4430 else
4431 printf(" failed!\n");
4432 }
4433
4434 if (_MAX_EXT > 6)
4435 {
4436 i = 0;
4437 flag = false;
4438
4439 do
4440 {
4441 snprintf(ips, 9, ".%03d.ips", i);
4442 n = S9xGetFilename(ips, PATCH_DIR);
4443
4444 if (!(patch_file = OPEN_FSTREAM(n, "rb")))
4445 break;
4446
4447 printf("Using IPS patch %s", n);
4448
4449 Stream *s = new fStream(patch_file);
4450 ret = ReadIPSPatch(s, offset, rom_size);
4451 s->closeStream();
4452
4453 if (ret)
4454 {
4455 printf("!\n");
4456 flag = true;
4457 }
4458 else
4459 {
4460 printf(" failed!\n");
4461 break;
4462 }
4463 } while (++i < 1000);
4464
4465 if (flag)
4466 return;
4467 }
4468
4469 if (_MAX_EXT > 3)
4470 {
4471 i = 0;
4472 flag = false;
4473
4474 do
4475 {
4476 snprintf(ips, _MAX_EXT + 3, ".ips%d", i);
4477 if (strlen(ips) > _MAX_EXT + 1)
4478 break;
4479 n = S9xGetFilename(ips, PATCH_DIR);
4480
4481 if (!(patch_file = OPEN_FSTREAM(n, "rb")))
4482 break;
4483
4484 printf("Using IPS patch %s", n);
4485
4486 Stream *s = new fStream(patch_file);
4487 ret = ReadIPSPatch(s, offset, rom_size);
4488 s->closeStream();
4489
4490 if (ret)
4491 {
4492 printf("!\n");
4493 flag = true;
4494 }
4495 else
4496 {
4497 printf(" failed!\n");
4498 break;
4499 }
4500 } while (++i != 0);
4501
4502 if (flag)
4503 return;
4504 }
4505
4506 if (_MAX_EXT > 2)
4507 {
4508 i = 0;
4509 flag = false;
4510
4511 do
4512 {
4513 snprintf(ips, 5, ".ip%d", i);
4514 n = S9xGetFilename(ips, PATCH_DIR);
4515
4516 if (!(patch_file = OPEN_FSTREAM(n, "rb")))
4517 break;
4518
4519 printf("Using IPS patch %s", n);
4520
4521 Stream *s = new fStream(patch_file);
4522 ret = ReadIPSPatch(s, offset, rom_size);
4523 s->closeStream();
4524
4525 if (ret)
4526 {
4527 printf("!\n");
4528 flag = true;
4529 }
4530 else
4531 {
4532 printf(" failed!\n");
4533 break;
4534 }
4535 } while (++i < 10);
4536
4537 if (flag)
4538 return;
4539 }
4540
4541#ifdef UNZIP_SUPPORT
4542 // Mercurial Magic (MSU-1 distribution pack)
4543 if (strcasecmp(ext, "msu1") && strcasecmp(ext, ".msu1")) // ROM was *NOT* loaded from a .msu1 pack
4544 {
4545 Stream *s = S9xMSU1OpenFile("patch.bps", TRUE);
4546 if (s)
4547 {
4548 printf("Using BPS patch %s.msu1", name);
4549 ret = ReadBPSPatch(s, offset, rom_size);
4550 s->closeStream();
4551
4552 if (ret)
4553 printf("!\n");
4554 else
4555 printf(" failed!\n");
4556 }
4557 }
4558#endif
4559}
4560