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 | |
50 | static bool8 stopMovie = TRUE; |
51 | static char LastRomFilename[PATH_MAX + 1] = "" ; |
52 | |
53 | // from NSRT |
54 | static 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 | |
724 | static 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 | |
771 | static void S9xDeinterleaveType1 (int, uint8 *); |
772 | static void S9xDeinterleaveType2 (int, uint8 *); |
773 | static void S9xDeinterleaveGD24 (int, uint8 *); |
774 | static bool8 allASCII (uint8 *, int); |
775 | static bool8 is_SufamiTurbo_BIOS (const uint8 *, uint32); |
776 | static bool8 is_SufamiTurbo_Cart (const uint8 *, uint32); |
777 | static bool8 is_BSCart_BIOS (const uint8 *, uint32); |
778 | static bool8 is_BSCartSA1_BIOS(const uint8 *, uint32); |
779 | static bool8 is_GNEXT_Add_On (const uint8 *, uint32); |
780 | static uint32 caCRC32 (uint8 *, uint32, uint32 crc32 = 0xffffffff); |
781 | static bool8 ReadUPSPatch (Stream *, long, int32 &); |
782 | static long ReadInt (Stream *, unsigned); |
783 | static bool8 ReadIPSPatch (Stream *, long, int32 &); |
784 | #ifdef UNZIP_SUPPORT |
785 | static int unzFindExtension (unzFile &, const char *, bool restart = TRUE, bool print = TRUE, bool allowExact = FALSE); |
786 | #endif |
787 | |
788 | // deinterleave |
789 | |
790 | static 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 | |
828 | static 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 | |
869 | static 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 | |
894 | bool8 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 | |
984 | void 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 | |
1032 | static 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 | |
1043 | static 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 | |
1052 | static 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 | |
1061 | static 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 | |
1081 | static 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 | |
1094 | static 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 | |
1102 | int CMemory::ScoreHiROM (bool8 , 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 | |
1151 | int CMemory::ScoreLoROM (bool8 , 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 | |
1197 | int 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 | |
1211 | uint32 CMemory:: (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 | |
1239 | uint32 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 | |
1370 | bool8 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 | |
1388 | bool8 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 | |
1411 | bool8 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 ; |
1421 | int ; |
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 = ((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 = 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 * = 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 | |
1631 | bool8 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 | |
1666 | bool8 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 | |
1698 | bool8 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 | |
1795 | bool8 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 | |
1825 | bool8 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 | |
1853 | bool8 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 | |
1876 | bool8 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 | |
1891 | bool8 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 | |
1908 | void 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 | |
1917 | bool8 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 | |
2002 | bool8 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 | |
2060 | bool8 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 | |
2088 | static 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 | |
2096 | char * 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 | |
2135 | char * 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 | |
2177 | void CMemory:: (uint8 *) |
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 | |
2224 | void 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 * = 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 | |
2654 | uint32 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 | |
2672 | void 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 | |
2689 | void 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 | |
2706 | void 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 | |
2723 | void 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 | |
2740 | void 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 | |
2756 | void 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 | |
2776 | void 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 | |
2787 | void 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 | |
2794 | void 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 | |
2810 | void 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 | |
2816 | void 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 | |
2854 | void 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 | |
2860 | void 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 | |
2866 | void 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 | |
2872 | void 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 | |
2884 | void 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 | |
2895 | void 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 | |
2906 | void 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 | |
2934 | void 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 | |
2952 | void 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 | |
2969 | void 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 | |
2986 | void 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 | |
3006 | void 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 | |
3035 | void 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 | |
3059 | void 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 | |
3088 | void 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 | |
3106 | void 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 | |
3125 | void 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 | |
3171 | void 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 | |
3213 | void 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 | |
3232 | void 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 | |
3248 | void 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 | |
3268 | void 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 | |
3299 | void 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 | |
3335 | uint16 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 | |
3345 | uint16 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 | |
3371 | void 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 | |
3401 | const char * CMemory::MapType (void) |
3402 | { |
3403 | return (HiROM ? ((ExtendedFormat != NOPE) ? "ExHiROM" : "HiROM" ) : "LoROM" ); |
3404 | } |
3405 | |
3406 | const 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 | |
3418 | const 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 | |
3433 | const 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 | |
3442 | const 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 | |
3501 | const 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 | |
3523 | const 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 | |
3534 | void 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 | |
3578 | bool8 CMemory::match_na (const char *str) |
3579 | { |
3580 | return (strcmp(ROMName, str) == 0); |
3581 | } |
3582 | |
3583 | bool8 CMemory::match_nn (const char *str) |
3584 | { |
3585 | return (strncmp(ROMName, str, strlen(str)) == 0); |
3586 | } |
3587 | |
3588 | bool8 CMemory::match_nc (const char *str) |
3589 | { |
3590 | return (strncasecmp(ROMName, str, strlen(str)) == 0); |
3591 | } |
3592 | |
3593 | bool8 CMemory::match_id (const char *str) |
3594 | { |
3595 | return (strncmp(ROMId, str, strlen(str)) == 0); |
3596 | } |
3597 | |
3598 | void 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 |
3675 | static 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 | |
3697 | static 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 | // |
3781 | static 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 | |
3876 | static 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 | |
3891 | static 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 |
3973 | static 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 | |
4006 | void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 , 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 | |