initial upstream import
[drnoksnes] / memmap.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
12  * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13  * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14  * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
21  * Permission to use, copy, modify and distribute Snes9x in both binary and
22  * source form, for non-commercial purposes, is hereby granted without fee,
23  * providing that this license information and copyright notice appear with
24  * all copies and any derived work.
25  *
26  * This software is provided 'as-is', without any express or implied
27  * warranty. In no event shall the authors be held liable for any damages
28  * arising from the use of this software.
29  *
30  * Snes9x is freeware for PERSONAL USE only. Commercial users should
31  * seek permission of the copyright holders first. Commercial use includes
32  * charging money for Snes9x or software derived from Snes9x.
33  *
34  * The copyright holders request that bug fixes and improvements to the code
35  * should be forwarded to them so everyone can benefit from the modifications
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41 #include <string.h>
42 #include <ctype.h>
43
44 #ifdef __linux
45 //#include <unistd.h>
46 #endif
47
48 #include "snes9x.h"
49 #include "memmap.h"
50 #include "cpuexec.h"
51 #include "ppu.h"
52 #include "display.h"
53 #include "cheats.h"
54 #include "apu.h"
55 #include "sa1.h"
56 #include "srtc.h"
57 #include "sdd1.h"
58
59 #ifndef ZSNES_FX
60 #include "fxemu.h"
61 extern struct FxInit_s SuperFX;
62 #else
63 START_EXTERN_C
64 extern uint8 *SFXPlotTable;
65 END_EXTERN_C
66 #endif
67
68 static uint8 bytes0x2000 [0x2000];
69
70 extern char *rom_filename;
71 extern bool8 LoadZip(const char* , int32 *, int32 *);
72
73 bool8_32 CMemory::AllASCII (uint8 *b, int size)
74 {
75     for (int i = 0; i < size; i++)
76     {
77         if (b[i] < 32 || b[i] > 126)
78             return (FALSE);
79     }
80     return (TRUE);
81 }
82
83 int CMemory::ScoreHiROM (bool8_32 skip_header)
84 {
85     int score = 0;
86     int o = skip_header ? 0xff00 + 0x200 : 0xff00;
87
88     if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) +
89          Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff)
90         score += 2;
91
92     if (Memory.ROM [o + 0xda] == 0x33)
93         score += 2;
94     if ((Memory.ROM [o + 0xd5] & 0xf) < 4)
95         score += 2;
96     if (!(Memory.ROM [o + 0xfd] & 0x80))
97         score -= 4;
98     if (CalculatedSize > 1024 * 1024 * 3)
99         score += 4;
100     if ((1 << (Memory.ROM [o + 0xd7] - 7)) > 48)
101         score -= 1;
102     if (!AllASCII (&Memory.ROM [o + 0xb0], 6))
103         score -= 1;
104     if (!AllASCII (&Memory.ROM [o + 0xc0], ROM_NAME_LEN - 1))
105         score -= 1;
106
107     return (score);
108 }
109
110 int CMemory::ScoreLoROM (bool8_32 skip_header)
111 {
112     int score = 0;
113     int o = skip_header ? 0x7f00 + 0x200 : 0x7f00;
114
115     if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) +
116          Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff)
117         score += 2;
118
119     if (Memory.ROM [o + 0xda] == 0x33)
120         score += 2;
121     if ((Memory.ROM [o + 0xd5] & 0xf) < 4)
122         score += 2;
123     if (CalculatedSize <= 1024 * 1024 * 16)
124         score += 2;
125     if (!(Memory.ROM [o + 0xfd] & 0x80))
126         score -= 4;
127     if ((1 << (Memory.ROM [o + 0xd7] - 7)) > 48)
128         score -= 1;
129     if (!AllASCII (&Memory.ROM [o + 0xb0], 6))
130         score -= 1;
131     if (!AllASCII (&Memory.ROM [o + 0xc0], ROM_NAME_LEN - 1))
132         score -= 1;
133
134     return (score);
135 }
136         
137 char *CMemory::Safe (const char *s)
138 {
139     static char *safe = NULL;
140     static int safe_len = 0;
141
142     int len = strlen (s);
143     if (!safe || len + 1 > safe_len)
144     {
145         if (safe)
146             free ((char *) safe);
147         safe = (char *) malloc (safe_len = len + 1);
148     }
149
150     for (int i = 0; i < len; i++)
151     {
152         if (s [i] >= 32 && s [i] < 127)
153             safe [i] = s[i];
154         else
155             safe [i] = '?';
156     }
157     safe [len] = 0;
158     return (safe);
159 }
160
161 /**********************************************************************************************/
162 /* Init()                                                                                     */
163 /* This function allocates all the memory needed by the emulator                              */
164 /**********************************************************************************************/
165 bool8_32 CMemory::Init ()
166 {
167     RAM     = (uint8 *) malloc (0x20000);
168     SRAM    = (uint8 *) malloc (0x20000);
169     VRAM    = (uint8 *) malloc (0x10000);
170     ROM     = (uint8 *) malloc (MAX_ROM_SIZE + 0x200 + 0x8000);
171     FillRAM = NULL;
172
173     IPPU.TileCache [TILE_2BIT] = (uint8 *) malloc (MAX_2BIT_TILES * 128);
174     IPPU.TileCache [TILE_4BIT] = (uint8 *) malloc (MAX_4BIT_TILES * 128);
175     IPPU.TileCache [TILE_8BIT] = (uint8 *) malloc (MAX_8BIT_TILES * 128);
176         
177     IPPU.TileCached [TILE_2BIT] = (uint8 *) malloc (MAX_2BIT_TILES);
178     IPPU.TileCached [TILE_4BIT] = (uint8 *) malloc (MAX_4BIT_TILES);
179     IPPU.TileCached [TILE_8BIT] = (uint8 *) malloc (MAX_8BIT_TILES);
180     
181     if (!RAM || !SRAM || !VRAM || !ROM ||
182         !IPPU.TileCache [TILE_2BIT] || !IPPU.TileCache [TILE_4BIT] ||
183         !IPPU.TileCache [TILE_8BIT] || !IPPU.TileCached [TILE_2BIT] ||
184         !IPPU.TileCached [TILE_4BIT] || !IPPU.TileCached [TILE_8BIT])
185     {
186         Deinit ();
187         return (FALSE);
188     }
189  
190     // FillRAM uses first 32K of ROM image area, otherwise space just
191     // wasted. Might be read by the SuperFX code.
192
193     FillRAM = ROM;
194
195     // Add 0x8000 to ROM image pointer to stop SuperFX code accessing
196     // unallocated memory (can cause crash on some ports).
197     ROM += 0x8000;
198
199     C4RAM    = ROM + 0x400000 + 8192 * 8;
200     ::ROM    = ROM;
201     ::SRAM   = SRAM;
202     ::RegRAM = FillRAM;
203
204 #ifdef ZSNES_FX
205     SFXPlotTable = ROM + 0x400000;
206 #else
207     SuperFX.pvRegisters = &Memory.FillRAM [0x3000];
208     SuperFX.nRamBanks = 1;
209     SuperFX.pvRam = ::SRAM;
210     SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024);
211     SuperFX.pvRom = (uint8 *) ROM;
212 #endif
213
214         ZeroMemory (IPPU.TileCached [TILE_2BIT], MAX_2BIT_TILES);
215     ZeroMemory (IPPU.TileCached [TILE_4BIT], MAX_4BIT_TILES);
216     ZeroMemory (IPPU.TileCached [TILE_8BIT], MAX_8BIT_TILES);
217         
218     SDD1Data = NULL;
219     SDD1Index = NULL;
220
221     return (TRUE);
222 }
223
224 void CMemory::Deinit ()
225 {
226     if (RAM)
227     {
228         free ((char *) RAM);
229         RAM = NULL;
230     }
231     if (SRAM)
232     {
233         free ((char *) SRAM);
234         SRAM = NULL;
235     }
236     if (VRAM)
237     {
238         free ((char *) VRAM);
239         VRAM = NULL;
240     }
241     if (ROM)
242     {
243         ROM -= 0x8000;
244         free ((char *) ROM);
245         ROM = NULL;
246     }
247
248     if (IPPU.TileCache [TILE_2BIT])
249     {
250         free ((char *) IPPU.TileCache [TILE_2BIT]);
251         IPPU.TileCache [TILE_2BIT] = NULL;
252     }
253     if (IPPU.TileCache [TILE_4BIT])
254     {
255         free ((char *) IPPU.TileCache [TILE_4BIT]);
256         IPPU.TileCache [TILE_4BIT] = NULL;
257     }
258     if (IPPU.TileCache [TILE_8BIT])
259     {
260         free ((char *) IPPU.TileCache [TILE_8BIT]);
261         IPPU.TileCache [TILE_8BIT] = NULL;
262     }
263         
264         if (IPPU.TileCached [TILE_2BIT])
265     {
266         free ((char *) IPPU.TileCached [TILE_2BIT]);
267         IPPU.TileCached [TILE_2BIT] = NULL;
268     }
269     if (IPPU.TileCached [TILE_4BIT])
270     {
271         free ((char *) IPPU.TileCached [TILE_4BIT]);
272         IPPU.TileCached [TILE_4BIT] = NULL;
273     }
274     if (IPPU.TileCached [TILE_8BIT])
275     {
276         free ((char *) IPPU.TileCached [TILE_8BIT]);
277         IPPU.TileCached [TILE_8BIT] = NULL;
278     }
279
280     FreeSDD1Data ();
281 }
282
283 void CMemory::FreeSDD1Data ()
284 {
285     if (SDD1Index)
286     {
287         free ((char *) SDD1Index);
288         SDD1Index = NULL;
289     }
290     if (SDD1Data)
291     {
292         free ((char *) SDD1Data);
293         SDD1Data = NULL;
294     }
295 }
296
297 /**********************************************************************************************/
298 /* checkext()                                                                                 */
299 /**********************************************************************************************/
300 int checkzip( char * fn  )
301 {
302     int cnt = strlen(fn);
303     if( ( (fn[cnt-1] == 'p') || (fn[cnt-1] == 'P') ) &&
304         ( (fn[cnt-2] == 'i') || (fn[cnt-2] == 'I') ) &&
305         ( (fn[cnt-3] == 'z') || (fn[cnt-3] == 'Z') )    ){
306         return true;
307         
308     }
309     return false;
310 }
311
312 /**********************************************************************************************/
313 /* LoadROM()                                                                                  */
314 /* This function loads a Snes-Backup image                                                    */
315 /**********************************************************************************************/
316 #ifdef _SNESPPC
317 #pragma warning(disable : 4101)
318 #pragma warning(disable : 4700)
319 #endif
320 bool8_32 CMemory::LoadROM (const char *filename)
321 {
322     unsigned long FileSize = 0;
323     int retry_count = 0;
324     STREAM ROMFile;
325     bool8_32 Interleaved = FALSE;
326     bool8_32 Tales = FALSE;
327     char dir [_MAX_DIR + 1];
328     char drive [_MAX_DRIVE + 1];
329     char name [_MAX_FNAME + 1];
330     char ext [_MAX_EXT + 1];
331     char fname [_MAX_PATH + 1];
332     int i;
333
334     memset (&SNESGameFixes, 0, sizeof(SNESGameFixes));
335     SNESGameFixes.SRAMInitialValue = 0x60;
336
337     memset (bytes0x2000, 0, 0x2000);
338     CPU.TriedInterleavedMode2 = FALSE;
339
340     CalculatedSize = 0;
341 again:
342 #ifndef _SNESPPC
343     _splitpath (filename, drive, dir, name, ext);
344     _makepath (fname, drive, dir, name, ext);
345 #else
346         strcpy(fname, filename);
347 //      strupr(fname);
348 #endif
349
350 #ifdef __WIN32__
351     memmove (&ext [0], &ext[1], 4);
352 #endif
353
354     int32 TotalFileSize = 0;
355
356 #ifdef UNZIP_SUPPORT
357     if( checkzip( fname ) )
358     {
359                 if (!LoadZip (fname, &TotalFileSize, &HeaderCount))
360             return (FALSE);
361
362         strcpy (ROMFilename, fname);
363     }
364     else
365 #endif
366     {
367         if ((ROMFile = OPEN_STREAM (fname, "rb")) == NULL)
368             return (FALSE);
369
370         strcpy (ROMFilename, fname);
371
372         HeaderCount = 0;
373         uint8 *ptr = ROM;
374         bool8_32 more = FALSE;
375
376         do
377         {
378             FileSize = READ_STREAM (ptr, MAX_ROM_SIZE + 0x200 - (ptr - ROM), ROMFile);
379             CLOSE_STREAM (ROMFile);
380             int calc_size = (FileSize / 0x2000) * 0x2000;
381
382             if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) ||
383                 Settings.ForceHeader)
384             {
385                 memmove (ptr, ptr + 512, calc_size);
386                 HeaderCount++;
387                 FileSize -= 512;
388             }
389             ptr += FileSize;
390             TotalFileSize += FileSize;
391
392             int len;
393             if (ptr - ROM < MAX_ROM_SIZE + 0x200 &&
394                 (isdigit (ext [0]) && ext [1] == 0 && ext [0] < '9'))
395             {
396                 more = TRUE;
397                 ext [0]++;
398 #ifdef __WIN32__
399                 memmove (&ext [1], &ext [0], 4);
400                 ext [0] = '.';
401 #endif
402 #ifndef _SNESPPC
403                 _makepath (fname, drive, dir, name, ext);
404 #endif
405                 }
406             else
407             if (ptr - ROM < MAX_ROM_SIZE + 0x200 &&
408                 (((len = strlen (name)) == 7 || len == 8) &&
409                  strncasecmp (name, "sf", 2) == 0 &&
410                  isdigit (name [2]) && isdigit (name [3]) && isdigit (name [4]) &&
411                  isdigit (name [5]) && isalpha (name [len - 1])))
412             {
413                 more = TRUE;
414                 name [len - 1]++;
415 #ifdef __WIN32__
416                 memmove (&ext [1], &ext [0], 4);
417                 ext [0] = '.';
418 #endif
419 #ifndef _SNESPPC
420                 _makepath (fname, drive, dir, name, ext);
421 #endif
422                 }
423             else
424                 more = FALSE;
425         } while (more && (ROMFile = OPEN_STREAM (fname, "rb")) != NULL);
426     }
427
428     if (HeaderCount == 0)
429         S9xMessage (S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found.");
430     else
431     {
432         if (HeaderCount == 1)
433             S9xMessage (S9X_INFO, S9X_HEADERS_INFO,
434                         "Found ROM file header (and ignored it).");
435         else
436             S9xMessage (S9X_INFO, S9X_HEADERS_INFO,
437                         "Found multiple ROM file headers (and ignored them).");
438     }
439
440     CheckForIPSPatch (filename, HeaderCount != 0, TotalFileSize);
441     int orig_hi_score, orig_lo_score;
442     int hi_score, lo_score;
443
444     orig_hi_score = hi_score = ScoreHiROM (FALSE);
445     orig_lo_score = lo_score = ScoreLoROM (FALSE);
446     
447     if (HeaderCount == 0 && !Settings.ForceNoHeader &&
448         ((hi_score > lo_score && ScoreHiROM (TRUE) > hi_score) ||
449          (hi_score <= lo_score && ScoreLoROM (TRUE) > lo_score)))
450     {
451         memmove (Memory.ROM, Memory.ROM + 512, TotalFileSize - 512);
452         TotalFileSize -= 512;
453         S9xMessage (S9X_INFO, S9X_HEADER_WARNING, 
454                     "Try specifying the -nhd command line option if the game doesn't work\n");
455     }
456
457     CalculatedSize = (TotalFileSize / 0x2000) * 0x2000;
458     ZeroMemory (ROM + CalculatedSize, MAX_ROM_SIZE - CalculatedSize);
459
460     // Check for cherryroms.com DAIKAIJYUMONOGATARI2
461
462     if (CalculatedSize == 0x500000 && 
463         strncmp ((const char *)&ROM [0x40ffc0], "DAIKAIJYUMONOGATARI2", 20) == 0 &&
464         strncmp ((const char *)&ROM [0x40ffb0], "18AE6J", 6) == 0 &&
465         memcmp (&ROM[0x40ffb0], &ROM [0xffb0], 0x30))
466     {
467         memmove (&ROM[0x100000], ROM, 0x500000);
468         memmove (ROM, &ROM[0x500000], 0x100000);
469     }
470
471     Interleaved = Settings.ForceInterleaved || Settings.ForceInterleaved2;
472     if (Settings.ForceLoROM || (!Settings.ForceHiROM && lo_score >= hi_score))
473     {
474         LoROM = TRUE;
475         HiROM = FALSE;
476
477         // Ignore map type byte if not 0x2x or 0x3x
478         if ((ROM [0x7fd5] & 0xf0) == 0x20 || (ROM [0x7fd5] & 0xf0) == 0x30)
479         {
480             switch (ROM [0x7fd5] & 0xf)
481             {
482             case 1:
483                 if (strncmp ((char *) &ROM [0x7fc0], "TREASURE HUNTER G", 17) != 0)
484                     Interleaved = TRUE;
485                 break;
486             case 2:
487 #if 0
488                 if (!Settings.ForceLoROM &&
489                     strncmp ((char *) &ROM [0x7fc0], "SUPER FORMATION SOCCE", 21) != 0 &&
490                     strncmp ((char *) &ROM [0x7fc0], "Star Ocean", 10) != 0)
491                 {
492                     LoROM = FALSE;
493                     HiROM = TRUE;
494                 }
495 #endif
496                 break;
497             case 5:
498                 Interleaved = TRUE;
499                 Tales = TRUE;
500                 break;
501             }
502         }
503     }
504     else
505     {
506         if ((ROM [0xffd5] & 0xf0) == 0x20 || (ROM [0xffd5] & 0xf0) == 0x30)
507         {
508             switch (ROM [0xffd5] & 0xf)
509             {
510             case 0:
511             case 3:
512                 Interleaved = TRUE;
513                 break;
514             }
515         }
516         LoROM = FALSE;
517         HiROM = TRUE;
518     }
519
520     // More 
521     if (!Settings.ForceHiROM && !Settings.ForceLoROM &&
522         !Settings.ForceInterleaved && !Settings.ForceInterleaved2 &&
523         !Settings.ForceNotInterleaved && !Settings.ForcePAL &&
524         !Settings.ForceSuperFX && !Settings.ForceDSP1 &&
525         !Settings.ForceSA1 && !Settings.ForceC4 &&
526         !Settings.ForceSDD1)
527     {
528         if (strncmp ((char *) &ROM [0x7fc0], "YUYU NO QUIZ DE GO!GO!", 22) == 0)
529         {
530             LoROM = TRUE;
531             HiROM = FALSE;
532             Interleaved = FALSE;
533         }
534         else 
535         if (strncmp ((char *) &ROM [0x7fc0], "SP MOMOTAROU DENTETSU2", 22) == 0)
536         {
537             LoROM = TRUE;
538             HiROM = FALSE;
539             Interleaved = FALSE;
540         }
541         else 
542         if (CalculatedSize == 0x100000 && 
543             strncmp ((char *) &ROM [0xffc0], "WWF SUPER WRESTLEMANIA", 22) == 0)
544         {
545             int cvcount;
546
547             memmove (&ROM[0x100000] , ROM, 0x100000);
548             for (cvcount = 0; cvcount < 16; cvcount++)
549             {
550                 memmove (&ROM[0x8000 * cvcount], &ROM[0x10000 * cvcount + 0x100000 + 0x8000], 0x8000);
551                 memmove (&ROM[0x8000 * cvcount + 0x80000], &ROM[0x10000 * cvcount + 0x100000], 0x8000);
552             }
553             LoROM = TRUE;
554             HiROM = FALSE;
555             ZeroMemory (ROM + CalculatedSize, MAX_ROM_SIZE - CalculatedSize);
556         }
557     }
558
559     if (!Settings.ForceNotInterleaved && Interleaved)
560     {
561         CPU.TriedInterleavedMode2 = TRUE;
562         S9xMessage (S9X_INFO, S9X_ROM_INTERLEAVED_INFO,
563                     "ROM image is in interleaved format - converting...");
564
565         int nblocks = CalculatedSize >> 16;
566 #if 0
567         int step = 64;
568
569         while (nblocks <= step)
570             step >>= 1;
571             
572         nblocks = step;
573 #endif
574         uint8 blocks [256];
575
576         if (Tales)
577         {
578             nblocks = 0x60;
579             for (i = 0; i < 0x40; i += 2)
580             {
581                 blocks [i + 0] = (i >> 1) + 0x20;
582                 blocks [i + 1] = (i >> 1) + 0x00;
583             }
584             for (i = 0; i < 0x80; i += 2)
585             {
586                 blocks [i + 0x40] = (i >> 1) + 0x80;
587                 blocks [i + 0x41] = (i >> 1) + 0x40;
588             }
589             LoROM = FALSE;
590             HiROM = TRUE;
591         }
592         else
593         if (Settings.ForceInterleaved2)
594         {
595             for (i = 0; i < nblocks * 2; i++)
596             {
597                 blocks [i] = (i & ~0x1e) | ((i & 2) << 2) | ((i & 4) << 2) |
598                              ((i & 8) >> 2) | ((i & 16) >> 2);
599             }
600         }
601         else
602         {
603             bool8_32 t = LoROM;
604
605             LoROM = HiROM;
606             HiROM = t;
607
608             for (i = 0; i < nblocks; i++)
609             {
610                 blocks [i * 2] = i + nblocks;
611                 blocks [i * 2 + 1] = i;
612             }
613         }
614
615         uint8 *tmp = (uint8 *) malloc (0x8000);
616         if (tmp)
617         {
618             for (i = 0; i < nblocks * 2; i++)
619             {
620                 for (int j = i; j < nblocks * 2; j++)
621                 {
622                     if (blocks [j] == i)
623                     {
624                         memmove (tmp, &ROM [blocks [j] * 0x8000], 0x8000);
625                         memmove (&ROM [blocks [j] * 0x8000], 
626                                  &ROM [blocks [i] * 0x8000], 0x8000);
627                         memmove (&ROM [blocks [i] * 0x8000], tmp, 0x8000);
628                         uint8 b = blocks [j];
629                         blocks [j] = blocks [i];
630                         blocks [i] = b;
631                         break;
632                     }
633                 }
634             }
635             free ((char *) tmp);
636         }
637
638         hi_score = ScoreHiROM (FALSE);
639         lo_score = ScoreLoROM (FALSE);
640
641         if ((HiROM &&
642              (lo_score >= hi_score || hi_score < 0)) ||
643             (LoROM && 
644              (hi_score > lo_score || lo_score < 0)))
645         {
646             if (retry_count == 0)
647             {
648                 S9xMessage (S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO,
649                             "ROM lied about its type! Trying again.");
650                 Settings.ForceNotInterleaved = TRUE;
651                 Settings.ForceInterleaved = FALSE;
652                 retry_count++;
653                 goto again;
654             }
655         }
656     }
657     FreeSDD1Data ();
658     InitROM (Tales);
659         
660     S9xLoadCheatFile (S9xGetFilename(".cht"));
661     S9xInitCheatData ();
662     S9xApplyCheats ();
663
664     S9xReset ();
665
666     return (TRUE);
667 }
668
669 void S9xDeinterleaveMode2 ()
670 {
671     S9xMessage (S9X_INFO, S9X_ROM_INTERLEAVED_INFO,
672                 "ROM image is in interleaved format - converting...");
673
674     int nblocks = Memory.CalculatedSize >> 15;
675     int step = 64;
676
677     while (nblocks <= step)
678         step >>= 1;
679         
680     nblocks = step;
681     uint8 blocks [256];
682     int i;
683
684     for (i = 0; i < nblocks * 2; i++)
685     {
686         blocks [i] = (i & ~0x1e) | ((i & 2) << 2) | ((i & 4) << 2) |
687                     ((i & 8) >> 2) | ((i & 16) >> 2);
688     }
689
690     uint8 *tmp = (uint8 *) malloc (0x8000);
691
692     if (tmp)
693     {
694         for (i = 0; i < nblocks * 2; i++)
695         {
696             for (int j = i; j < nblocks * 2; j++)
697             {
698                 if (blocks [j] == i)
699                 {
700                     memmove (tmp, &Memory.ROM [blocks [j] * 0x8000], 0x8000);
701                     memmove (&Memory.ROM [blocks [j] * 0x8000], 
702                              &Memory.ROM [blocks [i] * 0x8000], 0x8000);
703                     memmove (&Memory.ROM [blocks [i] * 0x8000], tmp, 0x8000);
704                     uint8 b = blocks [j];
705                     blocks [j] = blocks [i];
706                     blocks [i] = b;
707                     break;
708                 }
709             }
710         }
711         free ((char *) tmp);
712     }
713     Memory.InitROM (FALSE);
714     S9xReset ();
715 }
716
717 void CMemory::InitROM (bool8_32 Interleaved)
718 {
719 #ifndef ZSNES_FX
720     SuperFX.nRomBanks = CalculatedSize >> 15;
721 #endif
722     Settings.MultiPlayer5Master = Settings.MultiPlayer5;
723     Settings.MouseMaster = Settings.Mouse;
724     Settings.SuperScopeMaster = Settings.SuperScope;
725     Settings.DSP1Master = Settings.ForceDSP1;
726     Settings.SuperFX = FALSE;
727     Settings.SA1 = FALSE;
728     Settings.C4 = FALSE;
729     Settings.SDD1 = FALSE;
730     Settings.SRTC = FALSE;
731
732     ZeroMemory (BlockIsRAM, MEMMAP_NUM_BLOCKS);
733     ZeroMemory (BlockIsROM, MEMMAP_NUM_BLOCKS);
734
735     ::SRAM = SRAM;
736     memset (ROMId, 0, 5);
737     memset (CompanyId, 0, 3);
738
739     if (Memory.HiROM)
740     {
741         Memory.SRAMSize = ROM [0xffd8];
742         strncpy (ROMName, (char *) &ROM[0xffc0], ROM_NAME_LEN - 1);
743         ROMSpeed = ROM [0xffd5];
744         ROMType = ROM [0xffd6];
745         ROMSize = ROM [0xffd7];
746         ROMChecksum = ROM [0xffde] + (ROM [0xffdf] << 8);
747         ROMComplementChecksum = ROM [0xffdc] + (ROM [0xffdd] << 8);
748         
749         memmove (ROMId, &ROM [0xffb2], 4);
750         memmove (CompanyId, &ROM [0xffb0], 2);
751
752         // Try to auto-detect the DSP1 chip
753         if (!Settings.ForceNoDSP1 &&
754             (ROMType & 0xf) >= 3 && (ROMType & 0xf0) == 0)
755             Settings.DSP1Master = TRUE;
756
757         Settings.SDD1 = Settings.ForceSDD1;
758         if ((ROMType & 0xf0) == 0x40)
759             Settings.SDD1 = !Settings.ForceNoSDD1;
760
761         if (Settings.BS)
762             BSHiROMMap ();
763         else
764         if ((ROMSpeed & ~0x10) == 0x25)
765             TalesROMMap (Interleaved);
766         else 
767         if ((ROMSpeed & ~0x10) == 0x22 &&
768             strncmp (ROMName, "Super Street Fighter", 20) != 0)
769         {
770             AlphaROMMap ();
771         }
772         else
773             HiROMMap ();
774     }
775     else
776     {
777         Memory.HiROM = FALSE;
778         Memory.SRAMSize = ROM [0x7fd8];
779         ROMSpeed = ROM [0x7fd5];
780         ROMType = ROM [0x7fd6];
781         ROMSize = ROM [0x7fd7];
782         ROMChecksum = ROM [0x7fde] + (ROM [0x7fdf] << 8);
783         ROMComplementChecksum = ROM [0x7fdc] + (ROM [0x7fdd] << 8);
784         memmove (ROMId, &ROM [0x7fb2], 4);
785         memmove (CompanyId, &ROM [0x7fb0], 2);
786
787         strncpy (ROMName, (char *) &ROM[0x7fc0], ROM_NAME_LEN - 1);
788         Settings.SuperFX = Settings.ForceSuperFX;
789
790         if ((ROMType & 0xf0) == 0x10)
791             Settings.SuperFX = !Settings.ForceNoSuperFX;
792
793         // Try to auto-detect the DSP1 chip
794         if (!Settings.ForceNoDSP1 &&
795             (ROMType & 0xf) >= 3 && (ROMType & 0xf0) == 0)
796             Settings.DSP1Master = TRUE;
797
798         Settings.SDD1 = Settings.ForceSDD1;
799         if ((ROMType & 0xf0) == 0x40)
800             Settings.SDD1 = !Settings.ForceNoSDD1;
801
802         if (Settings.SDD1)
803             S9xLoadSDD1Data ();
804
805         Settings.C4 = Settings.ForceC4;
806         if ((ROMType & 0xf0) == 0xf0 &&
807             (strncmp (ROMName, "MEGAMAN X", 9) == 0 ||
808              strncmp (ROMName, "ROCKMAN X", 9) == 0))
809         {
810             Settings.C4 = !Settings.ForceNoC4;
811         }
812
813         if (Settings.SuperFX)
814         {
815             //::SRAM = ROM + 1024 * 1024 * 4;
816             SuperFXROMMap ();
817             Settings.MultiPlayer5Master = FALSE;
818             //Settings.MouseMaster = FALSE;
819             //Settings.SuperScopeMaster = FALSE;
820             Settings.DSP1Master = FALSE;
821             Settings.SA1 = FALSE;
822             Settings.C4 = FALSE;
823             Settings.SDD1 = FALSE;
824         }
825         else
826         if (Settings.ForceSA1 ||
827             (!Settings.ForceNoSA1 && (ROMSpeed & ~0x10) == 0x23 && 
828              (ROMType & 0xf) > 3 && (ROMType & 0xf0) == 0x30))
829         {
830             Settings.SA1 = TRUE;
831             Settings.MultiPlayer5Master = FALSE;
832             //Settings.MouseMaster = FALSE;
833             //Settings.SuperScopeMaster = FALSE;
834             Settings.DSP1Master = FALSE;
835             Settings.C4 = FALSE;
836             Settings.SDD1 = FALSE;
837             SA1ROMMap ();
838         }
839         else
840         if ((ROMSpeed & ~0x10) == 0x25)
841             TalesROMMap (Interleaved);
842         else
843         if (strncmp ((char *) &Memory.ROM [0x7fc0], "SOUND NOVEL-TCOOL", 17) == 0 ||
844             strncmp ((char *) &Memory.ROM [0x7fc0], "DERBY STALLION 96", 17) == 0)
845         {
846             LoROM24MBSMap ();
847             Settings.DSP1Master = FALSE;
848         }
849         else
850         if (strncmp ((char *) &Memory.ROM [0x7fc0], "THOROUGHBRED BREEDER3", 21) == 0 ||
851             strncmp ((char *) &Memory.ROM [0x7fc0], "RPG-TCOOL 2", 11) == 0)
852         {
853             SRAM512KLoROMMap ();
854             Settings.DSP1Master = FALSE;
855         }
856         else
857         if (strncmp ((char *) &Memory.ROM [0x7fc0], "DEZAEMON  ", 10) == 0)
858         {
859             Settings.DSP1Master = FALSE;
860             SRAM1024KLoROMMap ();
861         }
862         else
863         if (strncmp ((char *) &Memory.ROM [0x7fc0], "ADD-ON BASE CASSETE", 19) == 0)
864         {
865             Settings.MultiPlayer5Master = FALSE;
866             Settings.MouseMaster = FALSE;
867             Settings.SuperScopeMaster = FALSE;
868             Settings.DSP1Master = FALSE;
869             SufamiTurboLoROMMap(); 
870             Memory.SRAMSize = 3;
871         }
872         else
873         if ((ROMSpeed & ~0x10) == 0x22 &&
874             strncmp (ROMName, "Super Street Fighter", 20) != 0)
875         {
876             AlphaROMMap ();
877         }
878         else
879             LoROMMap ();
880     }
881
882     int power2 = 0;
883     int size = CalculatedSize;
884
885     while (size >>= 1)
886         power2++;
887
888     size = 1 << power2;
889     uint32 remainder = CalculatedSize - size;
890
891     uint32 sum1 = 0;
892     uint32 sum2 = 0;
893
894     int i;
895
896     for (i = 0; i < size; i++)
897         sum1 += ROM [i];
898
899     for (i = 0; i < (int) remainder; i++)
900         sum2 += ROM [size + i];
901
902     if (remainder)
903     {
904         //for Tengai makyou
905         if (CalculatedSize == 0x500000 && Memory.HiROM && 
906             strncmp ((const char *)&ROM[0xffb0], "18AZ", 4) == 0 &&
907             !memcmp(&ROM[0xffd5], "\x3a\xf9\x0d\x03\x00\x33\x00", 7))
908             sum1 += sum2;
909         else
910             sum1 += sum2 * (size / remainder);
911     }
912
913     sum1 &= 0xffff;
914
915     if (Settings.ForceNTSC)
916         Settings.PAL = FALSE;
917     else
918     if (Settings.ForcePAL)
919         Settings.PAL = TRUE;
920     else
921     if (Memory.HiROM)
922         // Country code
923         Settings.PAL = ROM [0xffd9] >= 2;
924     else
925         Settings.PAL = ROM [0x7fd9] >= 2;
926     
927     if (Settings.PAL)
928     {
929         Settings.FrameTime = Settings.FrameTimePAL;
930         Memory.ROMFramesPerSecond = 50;
931     }
932     else
933     {
934         Settings.FrameTime = Settings.FrameTimeNTSC;
935         Memory.ROMFramesPerSecond = 60;
936     }
937         
938     ROMName[ROM_NAME_LEN - 1] = 0;
939     if (strlen (ROMName))
940     {
941         char *p = ROMName + strlen (ROMName) - 1;
942
943         while (p > ROMName && *(p - 1) == ' ')
944             p--;
945         *p = 0;
946     }
947
948     if (Settings.SuperFX)
949     {
950         CPU.Memory_SRAMMask = 0xffff;
951         Memory.SRAMSize = 16;
952     }
953     else
954     {
955         CPU.Memory_SRAMMask = Memory.SRAMSize ?
956                     ((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0;
957     }
958
959     IAPU.OneCycle = ONE_APU_CYCLE;
960     Settings.Shutdown = Settings.ShutdownMaster;
961
962         SetDSP = &DSP1SetByte;
963         GetDSP = &DSP1GetByte;
964
965     ApplyROMFixes ();
966     sprintf (ROMName, "%s", Safe (ROMName));
967     sprintf (ROMId, "%s", Safe (ROMId));
968     sprintf (CompanyId, "%s", Safe (CompanyId));
969
970     sprintf (String, "\"%s\" [%s] %s, %s, Type: %s, Mode: %s, TV: %s, S-RAM: %s, ROMId: %s Company: %2.2s",
971              ROMName,
972              (ROMChecksum + ROMComplementChecksum != 0xffff ||
973               ROMChecksum != sum1) ? "bad checksum" : "checksum ok",
974              MapType (),
975              Size (),
976              KartContents (),
977              MapMode (),
978              TVStandard (),
979              StaticRAMSize (),
980              ROMId,
981              CompanyId);
982
983     S9xMessage (S9X_INFO, S9X_ROM_INFO, String);
984 }
985
986 bool8_32 CMemory::LoadSRAM (const char *filename)
987 {
988     int size = Memory.SRAMSize ?
989                (1 << (Memory.SRAMSize + 3)) * 128 : 0;
990
991     memset (SRAM, SNESGameFixes.SRAMInitialValue, 0x20000);
992
993     if (size > 0x20000)
994         size = 0x20000;
995     
996     if (size)
997     {
998         FILE *file;
999         if ((file = fopen(filename, "rb")))
1000         {
1001             int len = fread ((char*) ::SRAM, 1, 0x20000, file);
1002             fclose (file);
1003             if (len - size == 512)
1004             {
1005                 // S-RAM file has a header - remove it
1006                 memmove (::SRAM, ::SRAM + 512, size);
1007             }
1008             if (len == size + SRTC_SRAM_PAD)
1009             {
1010                 S9xSRTCPostLoadState ();
1011                 S9xResetSRTC ();
1012                 rtc.index = -1;
1013                 rtc.mode = MODE_READ;
1014             }
1015             else
1016                 S9xHardResetSRTC ();
1017
1018             return (TRUE);
1019         }
1020         S9xHardResetSRTC ();
1021         return (FALSE);
1022     }
1023     if (Settings.SDD1)
1024         S9xSDD1LoadLoggedData ();
1025
1026     return (TRUE);
1027 }
1028
1029 bool8_32 CMemory::SaveSRAM (const char *filename)
1030 {
1031     int size = Memory.SRAMSize ?
1032                (1 << (Memory.SRAMSize + 3)) * 128 : 0;
1033     if (Settings.SRTC)
1034     {
1035         size += SRTC_SRAM_PAD;
1036         S9xSRTCPreSaveState ();
1037     }
1038
1039     if (Settings.SDD1)
1040         S9xSDD1SaveLoggedData ();
1041
1042     if (size > 0x20000)
1043         size = 0x20000;
1044
1045     if (size && *Memory.ROMFilename)
1046     {
1047         FILE *file;
1048         if ((file = fopen (filename, "wb")))
1049         {
1050             fwrite ((char *) ::SRAM, size, 1, file);
1051             fclose (file);
1052 #if defined(__linux)
1053             chown (filename, getuid (), getgid ());
1054 #endif
1055             return (TRUE);
1056         }
1057     }
1058     return (FALSE);
1059 }
1060
1061 void CMemory::FixROMSpeed ()
1062 {
1063     int c;
1064
1065     for (c = 0x800; c < 0x1000; c++)
1066     {
1067         if (BlockIsROM [c])
1068             MemorySpeed [c] = (uint8) CPU.FastROMSpeed;
1069     }
1070 }
1071
1072 void CMemory::WriteProtectROM ()
1073 {
1074     memmove ((void *) WriteMap, (void *) Map, sizeof (Map));
1075     for (int c = 0; c < 0x1000; c++)
1076     {
1077         if (BlockIsROM [c])
1078             WriteMap [c] = (uint8 *) MAP_NONE;
1079     }
1080 }
1081
1082 void CMemory::MapRAM ()
1083 {
1084     int c;
1085
1086     // Banks 7e->7f, RAM
1087     for (c = 0; c < 16; c++)
1088     {
1089         Map [c + 0x7e0] = RAM;
1090         Map [c + 0x7f0] = RAM + 0x10000;
1091         BlockIsRAM [c + 0x7e0] = TRUE;
1092         BlockIsRAM [c + 0x7f0] = TRUE;
1093         BlockIsROM [c + 0x7e0] = FALSE;
1094         BlockIsROM [c + 0x7f0] = FALSE;
1095     }
1096
1097     // Banks 70->77, S-RAM
1098     for (c = 0; c < 0x80; c++)
1099     {
1100         Map [c + 0x700] = (uint8 *) MAP_LOROM_SRAM;
1101         BlockIsRAM [c + 0x700] = TRUE;
1102         BlockIsROM [c + 0x700] = FALSE;
1103     }
1104 }
1105
1106 void CMemory::MapExtraRAM ()
1107 {
1108     int c;
1109
1110     // Banks 7e->7f, RAM
1111     for (c = 0; c < 16; c++)
1112     {
1113         Map [c + 0x7e0] = RAM;
1114         Map [c + 0x7f0] = RAM + 0x10000;
1115         BlockIsRAM [c + 0x7e0] = TRUE;
1116         BlockIsRAM [c + 0x7f0] = TRUE;
1117         BlockIsROM [c + 0x7e0] = FALSE;
1118         BlockIsROM [c + 0x7f0] = FALSE;
1119     }
1120
1121     // Banks 70->73, S-RAM
1122     for (c = 0; c < 16; c++)
1123     {
1124         Map [c + 0x700] = ::SRAM;
1125         Map [c + 0x710] = ::SRAM + 0x8000;
1126         Map [c + 0x720] = ::SRAM + 0x10000;
1127         Map [c + 0x730] = ::SRAM + 0x18000;
1128
1129         BlockIsRAM [c + 0x700] = TRUE;
1130         BlockIsROM [c + 0x700] = FALSE;
1131         BlockIsRAM [c + 0x710] = TRUE;
1132         BlockIsROM [c + 0x710] = FALSE;
1133         BlockIsRAM [c + 0x720] = TRUE;
1134         BlockIsROM [c + 0x720] = FALSE;
1135         BlockIsRAM [c + 0x730] = TRUE;
1136         BlockIsROM [c + 0x730] = FALSE;
1137     }
1138 }
1139
1140 void CMemory::LoROMMap ()
1141 {
1142     int c;
1143     int i;
1144
1145     // Banks 00->3f and 80->bf
1146     for (c = 0; c < 0x400; c += 16)
1147     {
1148         Map [c + 0] = Map [c + 0x800] = RAM;
1149         Map [c + 1] = Map [c + 0x801] = RAM;
1150         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1151         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1152
1153         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1154         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1155         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1156         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1157         if (Settings.DSP1Master)
1158         {
1159             Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP;
1160             Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP;
1161         }
1162         else
1163         if (Settings.C4)
1164         {
1165             Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_C4;
1166             Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_C4;
1167         }
1168         else
1169         {
1170             Map [c + 6] = Map [c + 0x806] = (uint8 *) bytes0x2000 - 0x6000;
1171             Map [c + 7] = Map [c + 0x807] = (uint8 *) bytes0x2000 - 0x6000;
1172         }
1173
1174         for (i = c + 8; i < c + 16; i++)
1175         {
1176             Map [i] = Map [i + 0x800] = &ROM [(c << 11) % CalculatedSize] - 0x8000;
1177             BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
1178         }
1179
1180         for (i = c; i < c + 16; i++)
1181         {
1182             int ppu = i & 15;
1183             
1184             MemorySpeed [i] = 
1185                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1186         }
1187     }
1188
1189     if (Settings.DSP1Master)
1190     {
1191         // Banks 30->3f and b0->bf
1192         for (c = 0x300; c < 0x400; c += 16)
1193         {
1194             for (i = c + 8; i < c + 16; i++)
1195             {
1196                 Map [i] = Map [i + 0x800] = (uint8 *) MAP_DSP;
1197                 BlockIsROM [i] = BlockIsROM [i + 0x800] = FALSE;
1198             }
1199         }
1200     }
1201
1202     // Banks 40->7f and c0->ff
1203     for (c = 0; c < 0x400; c += 16)
1204     {
1205         for (i = c; i < c + 8; i++)
1206             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) % CalculatedSize];
1207
1208         for (i = c + 8; i < c + 16; i++)
1209             Map [i + 0x400] = Map [i + 0xc00] = &ROM [((c << 11) + 0x200000) % CalculatedSize - 0x8000];
1210
1211         for (i = c; i < c + 16; i++)    
1212         {
1213             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1214             BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1215         }
1216     }
1217
1218     if (Settings.DSP1Master)
1219     {
1220         for (c = 0; c < 0x100; c++)
1221         {
1222             Map [c + 0xe00] = (uint8 *) MAP_DSP;
1223             MemorySpeed [c + 0xe00] = SLOW_ONE_CYCLE;
1224             BlockIsROM [c + 0xe00] = FALSE;
1225         }
1226     }
1227     MapRAM ();
1228     WriteProtectROM ();
1229 }
1230
1231 void CMemory::HiROMMap ()
1232 {
1233     int c;
1234     int i;
1235
1236     // Banks 00->3f and 80->bf
1237     for (c = 0; c < 0x400; c += 16)
1238     {
1239         Map [c + 0] = Map [c + 0x800] = RAM;
1240         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1241         Map [c + 1] = Map [c + 0x801] = RAM;
1242         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1243
1244         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1245         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1246         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1247         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1248         if (Settings.DSP1Master)
1249         {
1250             Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP;
1251             Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP;
1252         }
1253         else
1254         {
1255             Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
1256             Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
1257         }
1258             
1259         for (i = c + 8; i < c + 16; i++)
1260         {
1261             Map [i] = Map [i + 0x800] = &ROM [(c << 12) % CalculatedSize];
1262             BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
1263         }
1264
1265         for (i = c; i < c + 16; i++)
1266         {
1267             int ppu = i & 15;
1268             
1269             MemorySpeed [i] = 
1270                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1271         }
1272     }
1273
1274     // Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM.
1275     for (c = 0; c < 16; c++)
1276     {
1277         Map [0x306 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
1278         Map [0x307 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
1279         Map [0xb06 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
1280         Map [0xb07 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
1281         BlockIsRAM [0x306 + (c << 4)] = TRUE;
1282         BlockIsRAM [0x307 + (c << 4)] = TRUE;
1283         BlockIsRAM [0xb06 + (c << 4)] = TRUE;
1284         BlockIsRAM [0xb07 + (c << 4)] = TRUE;
1285     }
1286
1287     // Banks 40->7f and c0->ff
1288     for (c = 0; c < 0x400; c += 16)
1289     {
1290         for (i = c; i < c + 16; i++)
1291         {
1292             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
1293             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1294             BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1295         }
1296     }
1297
1298     MapRAM ();
1299     WriteProtectROM ();
1300 }
1301
1302 void CMemory::TalesROMMap (bool8_32 Interleaved)
1303 {
1304     int c;
1305     int i;
1306
1307     uint32 OFFSET0 = 0x400000;
1308     uint32 OFFSET1 = 0x400000;
1309     uint32 OFFSET2 = 0x000000;
1310
1311     if (Interleaved)
1312     {
1313         OFFSET0 = 0x000000;
1314         OFFSET1 = 0x000000;
1315         OFFSET2 = 0x200000;
1316     }
1317
1318     // Banks 00->3f and 80->bf
1319     for (c = 0; c < 0x400; c += 16)
1320     {
1321         Map [c + 0] = Map [c + 0x800] = RAM;
1322         Map [c + 1] = Map [c + 0x801] = RAM;
1323         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1324         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1325
1326         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1327         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1328         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1329         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1330         Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
1331         Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
1332         for (i = c + 8; i < c + 16; i++)
1333         {
1334             Map [i] = &ROM [((c << 12) + OFFSET0) % CalculatedSize];
1335             Map [i + 0x800] = &ROM [((c << 12) + OFFSET0) % CalculatedSize];
1336             BlockIsROM [i] = TRUE;
1337             BlockIsROM [i + 0x800] = TRUE;
1338         }
1339
1340         for (i = c; i < c + 16; i++)
1341         {
1342             int ppu = i & 15;
1343             
1344             MemorySpeed [i] = 
1345                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1346         }
1347     }
1348     
1349     // Banks 30->3f and b0->bf, address ranges 6000->7ffff is S-RAM.
1350     for (c = 0; c < 16; c++)
1351     {
1352         Map [0x306 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
1353         Map [0x307 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
1354         Map [0xb06 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
1355         Map [0xb07 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
1356         BlockIsRAM [0x306 + (c << 4)] = TRUE;
1357         BlockIsRAM [0x307 + (c << 4)] = TRUE;
1358         BlockIsRAM [0xb06 + (c << 4)] = TRUE;
1359         BlockIsRAM [0xb07 + (c << 4)] = TRUE;
1360     }
1361
1362     // Banks 40->7f and c0->ff
1363     for (c = 0; c < 0x400; c += 16)
1364     {
1365         for (i = c; i < c + 8; i++)
1366         {
1367             Map [i + 0x400] = &ROM [((c << 12) + OFFSET1) % CalculatedSize];
1368             Map [i + 0x408] = &ROM [((c << 12) + OFFSET1) % CalculatedSize];
1369             Map [i + 0xc00] = &ROM [((c << 12) + OFFSET2) % CalculatedSize];
1370             Map [i + 0xc08] = &ROM [((c << 12) + OFFSET2) % CalculatedSize];
1371             BlockIsROM [i + 0x400] = TRUE;
1372             BlockIsROM [i + 0x408] = TRUE;
1373             BlockIsROM [i + 0xc00] = TRUE;
1374             BlockIsROM [i + 0xc08] = TRUE;
1375             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1376             MemorySpeed [i + 0x408] = MemorySpeed [i + 0xc08] = SLOW_ONE_CYCLE;
1377         }
1378     }
1379     MapRAM ();
1380     WriteProtectROM ();
1381 }
1382
1383 void CMemory::AlphaROMMap ()
1384 {
1385     int c;
1386     int i;
1387
1388     // Banks 00->3f and 80->bf
1389     for (c = 0; c < 0x400; c += 16)
1390     {
1391         Map [c + 0] = Map [c + 0x800] = RAM;
1392         Map [c + 1] = Map [c + 0x801] = RAM;
1393         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1394         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1395
1396         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1397         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1398         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1399         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1400         Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP;
1401         Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP;
1402
1403         for (i = c + 8; i < c + 16; i++)
1404         {
1405             Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
1406             BlockIsROM [i] = TRUE;
1407         }
1408
1409         for (i = c; i < c + 16; i++)
1410         {
1411             int ppu = i & 15;
1412             
1413             MemorySpeed [i] = 
1414                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1415         }
1416     }
1417
1418     // Banks 40->7f and c0->ff
1419
1420     for (c = 0; c < 0x400; c += 16)
1421     {
1422         for (i = c; i < c + 16; i++)
1423         {
1424             Map [i + 0x400] = &ROM [(c << 12) % CalculatedSize];
1425             Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
1426             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1427             BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1428         }
1429     }
1430
1431     MapRAM ();
1432     WriteProtectROM ();
1433 }
1434
1435 void CMemory::SuperFXROMMap ()
1436 {
1437     int c;
1438     int i;
1439     
1440     // Banks 00->3f and 80->bf
1441     for (c = 0; c < 0x400; c += 16)
1442     {
1443         Map [c + 0] = Map [c + 0x800] = RAM;
1444         Map [c + 1] = Map [c + 0x801] = RAM;
1445         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1446         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1447
1448         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1449         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1450         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1451         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1452         Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP;
1453         Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP;
1454         for (i = c + 8; i < c + 16; i++)
1455         {
1456             Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
1457             BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
1458         }
1459
1460         for (i = c; i < c + 8; i++)
1461         {
1462             int ppu = i & 15;
1463             
1464             MemorySpeed [i] = 
1465                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1466         }
1467     }
1468     
1469     // Banks 40->7f and c0->ff
1470     for (c = 0; c < 0x400; c += 16)
1471     {
1472         for (i = c; i < c + 16; i++)
1473         {
1474             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
1475             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1476             BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1477         }
1478     }
1479
1480     // Banks 7e->7f, RAM
1481     for (c = 0; c < 16; c++)
1482     {
1483         Map [c + 0x7e0] = RAM;
1484         Map [c + 0x7f0] = RAM + 0x10000;
1485         BlockIsRAM [c + 0x7e0] = TRUE;
1486         BlockIsRAM [c + 0x7f0] = TRUE;
1487         BlockIsROM [c + 0x7e0] = FALSE;
1488         BlockIsROM [c + 0x7f0] = FALSE;
1489     }
1490
1491     // Banks 70->71, S-RAM
1492     for (c = 0; c < 32; c++)
1493     {
1494         Map [c + 0x700] = ::SRAM + (((c >> 4) & 1) << 16);
1495         BlockIsRAM [c + 0x700] = TRUE;
1496         BlockIsROM [c + 0x700] = FALSE;
1497     }
1498
1499     // Banks 00->3f and 80->bf address ranges 6000->7fff is RAM.
1500     for (c = 0; c < 0x40; c++)
1501     {
1502         Map [0x006 + (c << 4)] = (uint8 *) ::SRAM - 0x6000;
1503         Map [0x007 + (c << 4)] = (uint8 *) ::SRAM - 0x6000;
1504         Map [0x806 + (c << 4)] = (uint8 *) ::SRAM - 0x6000;
1505         Map [0x807 + (c << 4)] = (uint8 *) ::SRAM - 0x6000;
1506         BlockIsRAM [0x006 + (c << 4)] = TRUE;
1507         BlockIsRAM [0x007 + (c << 4)] = TRUE;
1508         BlockIsRAM [0x806 + (c << 4)] = TRUE;
1509         BlockIsRAM [0x807 + (c << 4)] = TRUE;
1510     }
1511     // Replicate the first 2Mb of the ROM at ROM + 2MB such that each 32K
1512     // block is repeated twice in each 64K block.
1513     for (c = 0; c < 64; c++)
1514     {
1515         memmove (&ROM [0x200000 + c * 0x10000], &ROM [c * 0x8000], 0x8000);
1516         memmove (&ROM [0x208000 + c * 0x10000], &ROM [c * 0x8000], 0x8000);
1517     }
1518
1519     WriteProtectROM ();
1520 }
1521
1522 void CMemory::SA1ROMMap ()
1523 {
1524     int c;
1525     int i;
1526
1527     // Banks 00->3f and 80->bf
1528     for (c = 0; c < 0x400; c += 16)
1529     {
1530         Map [c + 0] = Map [c + 0x800] = RAM;
1531         Map [c + 1] = Map [c + 0x801] = RAM;
1532         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1533         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1534
1535         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1536         Map [c + 3] = Map [c + 0x803] = (uint8 *) &Memory.FillRAM [0x3000] - 0x3000;
1537         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1538         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1539         Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_BWRAM;
1540         Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_BWRAM;
1541         for (i = c + 8; i < c + 16; i++)
1542         {
1543             Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
1544             BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
1545         }
1546
1547         for (i = c; i < c + 16; i++)
1548         {
1549             int ppu = i & 15;
1550             
1551             MemorySpeed [i] = 
1552                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1553         }
1554     }
1555
1556     // Banks 40->7f
1557     for (c = 0; c < 0x400; c += 16)
1558     {
1559         for (i = c; i < c + 16; i++)
1560             Map [i + 0x400] = (uint8 *) &SRAM [(c << 12) & 0x1ffff];
1561
1562         for (i = c; i < c + 16; i++)
1563         {
1564             MemorySpeed [i + 0x400] = SLOW_ONE_CYCLE;
1565             BlockIsROM [i + 0x400] = FALSE;
1566         }
1567     }
1568
1569     // c0->ff
1570     for (c = 0; c < 0x400; c += 16)
1571     {
1572         for (i = c;  i < c + 16; i++)
1573         {
1574             Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
1575             MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1576             BlockIsROM [i + 0xc00] = TRUE;
1577         }
1578     }
1579
1580     for (c = 0; c < 16; c++)
1581     {
1582         Map [c + 0x7e0] = RAM;
1583         Map [c + 0x7f0] = RAM + 0x10000;
1584         BlockIsRAM [c + 0x7e0] = TRUE;
1585         BlockIsRAM [c + 0x7f0] = TRUE;
1586         BlockIsROM [c + 0x7e0] = FALSE;
1587         BlockIsROM [c + 0x7f0] = FALSE;
1588     }
1589     WriteProtectROM ();
1590
1591     // Now copy the map and correct it for the SA1 CPU.
1592     memmove ((void *) SA1.WriteMap, (void *) WriteMap, sizeof (WriteMap));
1593     memmove ((void *) SA1.Map, (void *) Map, sizeof (Map));
1594
1595     // Banks 00->3f and 80->bf
1596     for (c = 0; c < 0x400; c += 16)
1597     {
1598         SA1.Map [c + 0] = SA1.Map [c + 0x800] = &Memory.FillRAM [0x3000];
1599         SA1.Map [c + 1] = SA1.Map [c + 0x801] = (uint8 *) MAP_NONE;
1600         SA1.WriteMap [c + 0] = SA1.WriteMap [c + 0x800] = &Memory.FillRAM [0x3000];
1601         SA1.WriteMap [c + 1] = SA1.WriteMap [c + 0x801] = (uint8 *) MAP_NONE;
1602     }
1603
1604     // Banks 60->6f
1605     for (c = 0; c < 0x100; c++)
1606         SA1.Map [c + 0x600] = SA1.WriteMap [c + 0x600] = (uint8 *) MAP_BWRAM_BITMAP;
1607     
1608     BWRAM = SRAM;
1609 }
1610
1611 void CMemory::LoROM24MBSMap ()
1612 {
1613     int c;
1614     int i;
1615
1616     // Banks 00->3f and 80->bf
1617     for (c = 0; c < 0x400; c += 16)
1618     {
1619         Map [c + 0] = Map [c + 0x800] = RAM;
1620         Map [c + 1] = Map [c + 0x801] = RAM;
1621         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1622         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1623
1624         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1625         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1626         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1627         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1628         Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
1629         Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
1630
1631         for (i = c + 8; i < c + 16; i++)
1632         {
1633             Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
1634             BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
1635         }
1636
1637         for (i = c; i < c + 16; i++)
1638         {
1639             int ppu = i & 15;
1640             
1641             MemorySpeed [i] = 
1642                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1643         }
1644     }
1645
1646     // Banks 00->3f and 80->bf
1647     for (c = 0; c < 0x200; c += 16)
1648     {
1649         Map [c + 0x800] = RAM;
1650         Map [c + 0x801] = RAM;
1651         BlockIsRAM [c + 0x800] = TRUE;
1652         BlockIsRAM [c + 0x801] = TRUE;
1653
1654         Map [c + 0x802] = (uint8 *) MAP_PPU;
1655         Map [c + 0x803] = (uint8 *) MAP_PPU;
1656         Map [c + 0x804] = (uint8 *) MAP_CPU;
1657         Map [c + 0x805] = (uint8 *) MAP_CPU;
1658         Map [c + 0x806] = (uint8 *) MAP_NONE;
1659         Map [c + 0x807] = (uint8 *) MAP_NONE;
1660
1661         for (i = c + 8; i < c + 16; i++)
1662         {
1663             Map [i + 0x800] = &ROM [c << 11] - 0x8000 + 0x200000;
1664             BlockIsROM [i + 0x800] = TRUE;
1665         }
1666
1667         for (i = c; i < c + 16; i++)
1668         {
1669             int ppu = i & 15;
1670             
1671             MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1672         }
1673     }
1674
1675     // Banks 40->7f and c0->ff
1676     for (c = 0; c < 0x400; c += 16)
1677     {
1678         for (i = c; i < c + 8; i++)
1679             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000];
1680
1681         for (i = c + 8; i < c + 16; i++)
1682             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000];
1683
1684         for (i = c; i < c + 16; i++)
1685         {
1686             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1687             BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1688         }
1689     }
1690
1691     MapExtraRAM ();
1692     WriteProtectROM ();
1693 }
1694
1695 void CMemory::SufamiTurboLoROMMap ()
1696 {
1697     int c;
1698     int i;
1699
1700     // Banks 00->3f and 80->bf
1701     for (c = 0; c < 0x400; c += 16)
1702     {
1703         Map [c + 0] = Map [c + 0x800] = RAM;
1704         Map [c + 1] = Map [c + 0x801] = RAM;
1705         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1706         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1707
1708         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1709         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1710         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1711         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1712         if (Settings.DSP1Master)
1713         {
1714             Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP;
1715             Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP;
1716         }
1717         else
1718         {
1719             Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
1720             Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
1721         }
1722         for (i = c + 8; i < c + 16; i++)
1723         {
1724             Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
1725             BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
1726         }
1727
1728         for (i = c; i < c + 16; i++)
1729         {
1730             int ppu = i & 15;
1731             
1732             MemorySpeed [i] = 
1733                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1734         }
1735     }
1736
1737     if (Settings.DSP1Master)
1738     {
1739         // Banks 30->3f and b0->bf
1740         for (c = 0x300; c < 0x400; c += 16)
1741         {
1742             for (i = c + 8; i < c + 16; i++)
1743             {
1744                 Map [i] = Map [i + 0x800] = (uint8 *) MAP_DSP;
1745                 BlockIsROM [i] = BlockIsROM [i + 0x800] = FALSE;
1746             }
1747         }
1748     }
1749
1750     // Banks 40->7f and c0->ff
1751     for (c = 0; c < 0x400; c += 16)
1752     {
1753         for (i = c; i < c + 8; i++)
1754             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000];
1755
1756         for (i = c + 8; i < c + 16; i++)
1757             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000];
1758
1759         for (i = c; i < c + 16; i++)
1760         {
1761             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1762             BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1763         }
1764     }
1765
1766     if (Settings.DSP1Master)
1767     {
1768         for (c = 0; c < 0x100; c++)
1769         {
1770             Map [c + 0xe00] = (uint8 *) MAP_DSP;
1771             MemorySpeed [c + 0xe00] = SLOW_ONE_CYCLE;
1772             BlockIsROM [c + 0xe00] = FALSE;
1773         }
1774     }
1775
1776     // Banks 7e->7f, RAM
1777     for (c = 0; c < 16; c++)
1778     {
1779         Map [c + 0x7e0] = RAM;
1780         Map [c + 0x7f0] = RAM + 0x10000;
1781         BlockIsRAM [c + 0x7e0] = TRUE;
1782         BlockIsRAM [c + 0x7f0] = TRUE;
1783         BlockIsROM [c + 0x7e0] = FALSE;
1784         BlockIsROM [c + 0x7f0] = FALSE;
1785     }
1786
1787     // Banks 60->67, S-RAM
1788     for (c = 0; c < 0x80; c++)
1789     {
1790         Map [c + 0x600] = (uint8 *) MAP_LOROM_SRAM;
1791         BlockIsRAM [c + 0x600] = TRUE;
1792         BlockIsROM [c + 0x600] = FALSE;
1793     }
1794
1795     WriteProtectROM ();
1796 }
1797
1798 void CMemory::SRAM512KLoROMMap ()
1799 {
1800     int c;
1801     int i;
1802
1803     // Banks 00->3f and 80->bf
1804     for (c = 0; c < 0x400; c += 16)
1805     {
1806         Map [c + 0] = Map [c + 0x800] = RAM;
1807         Map [c + 1] = Map [c + 0x801] = RAM;
1808         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1809         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1810
1811         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1812         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1813         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1814         Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
1815         Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
1816         Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
1817
1818         for (i = c + 8; i < c + 16; i++)
1819         {
1820             Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
1821             BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
1822         }
1823
1824         for (i = c; i < c + 16; i++)
1825         {
1826             int ppu = i & 15;
1827             
1828             MemorySpeed [i] = 
1829                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1830         }
1831     }
1832
1833     // Banks 40->7f and c0->ff
1834     for (c = 0; c < 0x400; c += 16)
1835     {
1836         for (i = c; i < c + 8; i++)
1837             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000];
1838
1839         for (i = c + 8; i < c + 16; i++)
1840             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000];
1841
1842         for (i = c; i < c + 16; i++)
1843         {
1844             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1845             BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1846         }
1847     }
1848
1849     MapExtraRAM ();
1850     WriteProtectROM ();
1851 }
1852
1853 void CMemory::SRAM1024KLoROMMap ()
1854 {
1855     int c;
1856     int i;
1857
1858     // Banks 00->3f and 80->bf
1859     for (c = 0; c < 0x400; c += 16)
1860     {
1861         Map [c + 0] = Map [c + 0x800] = Map [c + 0x400] = Map [c + 0xc00] = RAM;
1862         Map [c + 1] = Map [c + 0x801] = Map [c + 0x401] = Map [c + 0xc01] = RAM;
1863         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = BlockIsRAM [c + 0x400] = BlockIsRAM [c + 0xc00] = TRUE;
1864         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = BlockIsRAM [c + 0x401] = BlockIsRAM [c + 0xc01] = TRUE;
1865
1866         Map [c + 2] = Map [c + 0x802] = Map [c + 0x402] = Map [c + 0xc02] = (uint8 *) MAP_PPU;
1867         Map [c + 3] = Map [c + 0x803] = Map [c + 0x403] = Map [c + 0xc03] = (uint8 *) MAP_PPU;
1868         Map [c + 4] = Map [c + 0x804] = Map [c + 0x404] = Map [c + 0xc04] = (uint8 *) MAP_CPU;
1869         Map [c + 5] = Map [c + 0x805] = Map [c + 0x405] = Map [c + 0xc05] = (uint8 *) MAP_CPU;
1870         Map [c + 6] = Map [c + 0x806] = Map [c + 0x406] = Map [c + 0xc06] = (uint8 *) MAP_NONE;
1871         Map [c + 7] = Map [c + 0x807] = Map [c + 0x407] = Map [c + 0xc07] = (uint8 *) MAP_NONE;
1872         for (i = c + 8; i < c + 16; i++)
1873         {
1874             Map [i] = Map [i + 0x800] = Map [i + 0x400] = Map [i + 0xc00] = &ROM [c << 11] - 0x8000;
1875             BlockIsROM [i] = BlockIsROM [i + 0x800] = BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1876         }
1877
1878         for (i = c; i < c + 16; i++)
1879         {
1880             int ppu = i & 15;
1881             
1882             MemorySpeed [i] = MemorySpeed [i + 0x800] = 
1883                 MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1884         }
1885     }
1886
1887     MapExtraRAM ();
1888     WriteProtectROM ();
1889 }
1890
1891 void CMemory::BSHiROMMap ()
1892 {
1893     int c;
1894     int i;
1895
1896     // Banks 00->3f and 80->bf
1897     for (c = 0; c < 0x400; c += 16)
1898     {
1899         Map [c + 0] = Map [c + 0x800] = RAM;
1900         BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
1901         Map [c + 1] = Map [c + 0x801] = RAM;
1902         BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
1903
1904         Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
1905         Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
1906         Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
1907         // XXX: How large is SRAM??
1908         Map [c + 5] = Map [c + 0x805] = (uint8 *) SRAM;
1909         BlockIsRAM [c + 5] = BlockIsRAM [c + 0x805] = TRUE;
1910         Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
1911         Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
1912             
1913         for (i = c + 8; i < c + 16; i++)
1914         {
1915             Map [i] = Map [i + 0x800] = &ROM [(c << 12) % CalculatedSize];
1916             BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
1917         }
1918
1919         for (i = c; i < c + 16; i++)
1920         {
1921             int ppu = i & 15;
1922             
1923             MemorySpeed [i] = 
1924                 MemorySpeed [i + 0x800] = ppu >= 2 && ppu <= 3 ? ONE_CYCLE : SLOW_ONE_CYCLE;
1925         }
1926     }
1927
1928     // Banks 60->7d offset 0000->7fff & 60->7f offset 8000->ffff PSRAM
1929     // XXX: How large is PSRAM?
1930     for (c = 0x600; c < 0x7e0; c += 16)
1931     {
1932         for (i = c; i < c + 8; i++)
1933         {
1934             Map [i] = &ROM [0x400000 + (c << 11)];
1935             BlockIsRAM [i] = TRUE;
1936         }
1937         for (i = c + 8; i < c + 16; i++)
1938         {
1939             Map [i] = &ROM [0x400000 + (c << 11) - 0x8000];
1940             BlockIsRAM [i] = TRUE;
1941         }
1942     }
1943
1944     // Banks 40->7f and c0->ff
1945     for (c = 0; c < 0x400; c += 16)
1946     {
1947         for (i = c; i < c + 16; i++)
1948         {
1949             Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
1950             MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = SLOW_ONE_CYCLE;
1951             BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
1952         }
1953     }
1954
1955     MapRAM ();
1956     WriteProtectROM ();
1957 }
1958
1959 const char *CMemory::TVStandard ()
1960 {
1961     return (Settings.PAL ? "PAL" : "NTSC");
1962 }
1963
1964 const char *CMemory::Speed ()
1965 {
1966     return (ROMSpeed & 0x10 ? "120ns" : "200ns");
1967 }
1968
1969 const char *CMemory::MapType ()
1970 {
1971     return (HiROM ? "HiROM" : "LoROM");
1972 }
1973
1974 const char *CMemory::StaticRAMSize ()
1975 {
1976     static char tmp [20];
1977
1978     if (Memory.SRAMSize > 16)
1979         return ("Corrupt");
1980     sprintf (tmp, "%dKb", (CPU.Memory_SRAMMask + 1) / 1024);
1981     return (tmp);
1982 }
1983
1984 const char *CMemory::Size ()
1985 {
1986     static char tmp [20];
1987
1988     if (ROMSize < 7 || ROMSize - 7 > 23)
1989         return ("Corrupt");
1990     sprintf (tmp, "%dMbits", 1 << (ROMSize - 7));
1991     return (tmp);
1992 }
1993
1994 const char *CMemory::KartContents ()
1995 {
1996     static char tmp [30];
1997     static const char *CoPro [16] = {
1998         "DSP1", "SuperFX", "OBC1", "SA-1", "S-DD1", "S-RTC", "CoPro#6",
1999         "CoPro#7", "CoPro#8", "CoPro#9", "CoPro#10", "CoPro#11", "CoPro#12",
2000         "CoPro#13", "CoPro#14", "CoPro-Custom"
2001     };
2002     static const char *Contents [3] = {
2003         "ROM", "ROM+RAM", "ROM+RAM+BAT"
2004     };
2005     if (ROMType == 0)
2006         return ("ROM only");
2007
2008     sprintf (tmp, "%s", Contents [(ROMType & 0xf) % 3]);
2009
2010     if ((ROMType & 0xf) >= 3)
2011         sprintf (tmp, "%s+%s", tmp, CoPro [(ROMType & 0xf0) >> 4]);
2012
2013     return (tmp);
2014 }
2015
2016 const char *CMemory::MapMode ()
2017 {
2018     static char tmp [4];
2019     sprintf (tmp, "%02x", ROMSpeed & ~0x10);
2020     return (tmp);
2021 }
2022
2023 const char *CMemory::ROMID ()
2024 {
2025     return (ROMId);
2026 }
2027
2028 void CMemory::ApplyROMFixes ()
2029 {
2030         DSP1.version = 0;
2031         if (strncmp(ROMName, "DUNGEON MASTER", 14) == 0)
2032         {
2033                 DSP1.version = 1;
2034                 SetDSP=&DSP2SetByte;
2035                 GetDSP=&DSP2GetByte;
2036         }
2037
2038     // Enable S-RTC (Real Time Clock) emulation for Dai Kaijyu Monogatari 2
2039     Settings.SRTC = ((ROMType & 0xf0) >> 4) == 5;
2040
2041     Settings.StrikeGunnerOffsetHack = strcmp (ROMName, "STRIKE GUNNER") == 0 ? 7 : 0;
2042
2043     CPU.NMITriggerPoint = 4;
2044     if (strcmp (ROMName, "CACOMA KNIGHT") == 0)
2045         CPU.NMITriggerPoint = 25;
2046
2047     // These games complain if the multi-player adaptor is 'connected'
2048     if (strcmp (ROMName, "TETRIS&Dr.MARIO") == 0 || 
2049         strcmp (ROMName, "JIGSAW PARTY") == 0 || 
2050         strcmp (ROMName, "SUPER PICROSS") == 0 || 
2051         strcmp (ROMName, "KIRBY NO KIRA KIZZU") == 0 || 
2052         strcmp (ROMName, "BLOCK") == 0 || 
2053         strncmp (ROMName, "SUPER BOMBLISS", 14) == 0 ||
2054         strcmp (ROMId, "ABOJ") == 0) 
2055     {
2056         Settings.MultiPlayer5Master = FALSE;
2057         Settings.MouseMaster = FALSE;
2058         Settings.SuperScopeMaster = FALSE;
2059     }
2060
2061     // Games which spool sound samples between the SNES and sound CPU using
2062     // H-DMA as the sample is playing.
2063     if (strcmp (ROMName, "EARTHWORM JIM 2") == 0 ||
2064         strcmp (ROMName, "PRIMAL RAGE") == 0 ||
2065         strcmp (ROMName, "CLAY FIGHTER") == 0 ||
2066         strcmp (ROMName, "ClayFighter 2") == 0 ||
2067         strncasecmp (ROMName, "MADDEN", 6) == 0 ||
2068         strncmp (ROMName, "NHL", 3) == 0 ||
2069         strcmp (ROMName, "WeaponLord") == 0)
2070     {
2071         Settings.Shutdown = FALSE;
2072     }
2073
2074
2075     // Stunt Racer FX
2076     if (strcmp (ROMId, "CQ  ") == 0 ||
2077     // Illusion of Gaia
2078         strncmp (ROMId, "JG", 2) == 0 ||
2079         strcmp (ROMName, "GAIA GENSOUKI 1 JPN") == 0)
2080     {
2081         IAPU.OneCycle = 13;
2082                 Settings.APUEnabled  |= 2;
2083                 CPU.APU_APUExecuting |= 2;
2084     }
2085
2086     // RENDERING RANGER R2
2087     if (strcmp (ROMId, "AVCJ") == 0 ||
2088     // Star Ocean
2089         strncmp (ROMId, "ARF", 3) == 0 ||
2090     // Tales of Phantasia
2091         strncmp (ROMId, "ATV", 3) == 0 ||
2092     // Act Raiser 1 & 2
2093         strncasecmp (ROMName, "ActRaiser", 9) == 0 ||
2094     // Soulblazer
2095         strcmp (ROMName, "SOULBLAZER - 1 USA") == 0 ||
2096         strcmp (ROMName, "SOULBLADER - 1") == 0 ||
2097         strncmp (ROMName, "SOULBLAZER 1",12) == 0 ||
2098     // Terranigma
2099         strncmp (ROMId, "AQT", 3) == 0 ||
2100     // Robotrek
2101         strncmp (ROMId, "E9 ", 3) == 0 ||
2102         strcmp (ROMName, "SLAP STICK 1 JPN") == 0 ||
2103     // ZENNIHON PURORESU2
2104         strncmp (ROMId, "APR", 3) == 0 ||
2105     // Bomberman 4
2106         strncmp (ROMId, "A4B", 3) == 0 ||
2107     // UFO KAMEN YAKISOBAN
2108         strncmp (ROMId, "Y7 ", 3) == 0 ||
2109         strncmp (ROMId, "Y9 ", 3) == 0 ||
2110     // Panic Bomber World
2111         strncmp (ROMId, "APB", 3) == 0 ||
2112         ((strncmp (ROMName, "Parlor", 6) == 0 || 
2113           strcmp (ROMName, "HEIWA Parlor!Mini8") == 0 ||
2114           strncmp (ROMName, "SANKYO Fever! Ì¨°ÊÞ°!", 21) == 0) &&
2115          strcmp (CompanyId, "A0") == 0) ||
2116         strcmp (ROMName, "DARK KINGDOM") == 0 ||
2117         strcmp (ROMName, "ZAN3 SFC") == 0 ||
2118         strcmp (ROMName, "HIOUDEN") == 0 ||
2119         strcmp (ROMName, "ÃݼɳÀ") == 0 ||
2120         strcmp (ROMName, "FORTUNE QUEST") == 0 ||
2121         strcmp (ROMName, "FISHING TO BASSING") == 0 ||
2122         strncmp (ROMName, "TokyoDome '95Battle 7", 21) == 0 ||
2123         strcmp (ROMName, "OHMONO BLACKBASS") == 0)
2124     {
2125         IAPU.OneCycle = 15;
2126                 // notaz: strangely enough, these games work properly with my hack enabled
2127                 Settings.APUEnabled  |= 2;
2128                 CPU.APU_APUExecuting |= 2;
2129     }
2130     
2131     if (strcmp (ROMName, "BATMAN--REVENGE JOKER") == 0)
2132     {
2133         Memory.HiROM = FALSE;
2134         Memory.LoROM = TRUE;
2135         LoROMMap ();
2136     }
2137     Settings.StarfoxHack = strcmp (ROMName, "STAR FOX") == 0 ||
2138                            strcmp (ROMName, "STAR WING") == 0;
2139     Settings.WinterGold = strcmp (ROMName, "FX SKIING NINTENDO 96") == 0 ||
2140                           strcmp (ROMName, "DIRT RACER") == 0 ||
2141                           strcmp (ROMName, "Stunt Race FX") == 0 ||
2142                           Settings.StarfoxHack;
2143     Settings.ChuckRock = strcmp (ROMName, "CHUCK ROCK") == 0;
2144     Settings.Dezaemon = strcmp (ROMName, "DEZAEMON") == 0;
2145     
2146     if (strcmp (ROMName, "RADICAL DREAMERS") == 0 ||
2147         strcmp (ROMName, "TREASURE CONFLIX") == 0)
2148     {
2149         int c;
2150
2151         for (c = 0; c < 0x80; c++)
2152         {
2153             Map [c + 0x700] = ROM + 0x200000 + 0x1000 * (c & 0xf0);
2154             BlockIsRAM [c + 0x700] = TRUE;
2155             BlockIsROM [c + 0x700] = FALSE;
2156         }
2157         for (c = 0; c < 0x400; c += 16)
2158         {
2159             Map [c + 5] = Map [c + 0x805] = ROM + 0x300000;
2160             BlockIsRAM [c + 5] = BlockIsRAM [c + 0x805] = TRUE;
2161         }
2162         WriteProtectROM ();
2163     }
2164
2165     Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 
2166                       Settings.CyclesPercentage) / 100;
2167
2168     if (strcmp (ROMId, "ASRJ") == 0 && Settings.CyclesPercentage == 100)
2169         // Street Racer
2170         Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 95) / 100;
2171
2172         // Power Rangers Fight
2173     if (strncmp (ROMId, "A3R", 3) == 0 ||
2174         // Clock Tower
2175         strncmp (ROMId, "AJE", 3) == 0)
2176         Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 103) / 100;
2177     
2178     if (strcmp (ROMId, "AWVP") == 0 || strcmp (ROMId, "AWVE") == 0 ||
2179         strcmp (ROMId, "AWVJ") == 0)
2180     {
2181         // Wrestlemania Arcade
2182 #if 0
2183         if (Settings.CyclesPercentage == 100)
2184             Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 140) / 100; // Fixes sound
2185 #endif
2186         Settings.WrestlemaniaArcade = TRUE;
2187     }
2188     // Theme Park - disable offset-per-tile mode.
2189     if (strcmp (ROMId, "ATQP") == 0)
2190         Settings.WrestlemaniaArcade = TRUE;
2191
2192     if (strncmp (ROMId, "A3M", 3) == 0 && Settings.CyclesPercentage == 100)
2193         // Mortal Kombat 3. Fixes cut off speech sample
2194         Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 110) / 100;
2195
2196     if (strcmp (ROMName, "\x0bd\x0da\x0b2\x0d4\x0b0\x0bd\x0de") == 0 &&
2197         Settings.CyclesPercentage == 100)
2198         Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 101) / 100;
2199
2200     if (strcmp (ROMName, "WILD TRAX") == 0 || 
2201         strcmp (ROMName, "YOSSY'S ISLAND") == 0 || 
2202         strcmp (ROMName, "YOSHI'S ISLAND") == 0)
2203         CPU.TriedInterleavedMode2 = TRUE;
2204
2205     // Start Trek: Deep Sleep 9
2206     if (strncmp (ROMId, "A9D", 3) == 0 && Settings.CyclesPercentage == 100)
2207         Settings.H_Max = (SNES_CYCLES_PER_SCANLINE * 110) / 100;
2208     
2209     Settings.APURAMInitialValue = 0xff;
2210
2211     if (strcmp (ROMName, "·­³Ô¸¥Ò¶ÞÐÃݾ²") == 0 ||
2212         strcmp (ROMName, "KENTOUOU WORLDCHAMPIO") == 0 ||
2213         strcmp (ROMName, "TKO SUPERCHAMPIONSHIP") == 0 ||
2214         strcmp (ROMName, "TKO SUPER CHAMPIONSHI") == 0 ||
2215         strcmp (ROMName, "IHATOVO STORY") == 0 ||
2216         strcmp (ROMName, "WANDERERS FROM YS") == 0 ||
2217         strcmp (ROMName, "SUPER GENTYOUHISHI") == 0 ||
2218     // Panic Bomber World
2219         strncmp (ROMId, "APB", 3) == 0)
2220     {
2221         Settings.APURAMInitialValue = 0;
2222     }
2223
2224     Settings.DaffyDuck = strcmp (ROMName, "DAFFY DUCK: MARV MISS") == 0;
2225     Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX;
2226
2227     SA1.WaitAddress = NULL;
2228     SA1.WaitByteAddress1 = NULL;
2229     SA1.WaitByteAddress2 = NULL;
2230
2231     /* Bass Fishing */
2232     if (strcmp (ROMId, "ZBPJ") == 0)
2233     {
2234         SA1.WaitAddress = SA1.Map [0x0093f1 >> MEMMAP_SHIFT] + 0x93f1;
2235         SA1.WaitByteAddress1 = FillRAM + 0x304a;
2236     }
2237     /* DAISENRYAKU EXPERTWW2 */
2238     if (strcmp (ROMId, "AEVJ") == 0)
2239     {
2240         SA1.WaitAddress = SA1.Map [0x0ed18d >> MEMMAP_SHIFT] + 0xd18d;
2241         SA1.WaitByteAddress1 = FillRAM + 0x3000;
2242     }
2243     /* debjk2 */
2244     if (strcmp (ROMId, "A2DJ") == 0)
2245     {
2246         SA1.WaitAddress = SA1.Map [0x008b62 >> MEMMAP_SHIFT] + 0x8b62;
2247     }
2248     /* Dragon Ballz HD */
2249     if (strcmp (ROMId, "AZIJ") == 0)
2250     {
2251         SA1.WaitAddress = SA1.Map [0x008083 >> MEMMAP_SHIFT] + 0x8083;
2252         SA1.WaitByteAddress1 = FillRAM + 0x3020;
2253     }
2254     /* SFC SDGUNDAMGNEXT */
2255     if (strcmp (ROMId, "ZX3J") == 0)
2256     {
2257         SA1.WaitAddress = SA1.Map [0x0087f2 >> MEMMAP_SHIFT] + 0x87f2;
2258         SA1.WaitByteAddress1 = FillRAM + 0x30c4;
2259     }
2260     /* ShougiNoHanamichi */
2261     if (strcmp (ROMId, "AARJ") == 0)
2262     {
2263         SA1.WaitAddress = SA1.Map [0xc1f85a >> MEMMAP_SHIFT] + 0xf85a;
2264         SA1.WaitByteAddress1 = SRAM + 0x0c64;
2265         SA1.WaitByteAddress2 = SRAM + 0x0c66;
2266     }
2267     /* KATO HIFUMI9DAN SYOGI */
2268     if (strcmp (ROMId, "A23J") == 0)
2269     {
2270         SA1.WaitAddress = SA1.Map [0xc25037 >> MEMMAP_SHIFT] + 0x5037;
2271         SA1.WaitByteAddress1 = SRAM + 0x0c06;
2272         SA1.WaitByteAddress2 = SRAM + 0x0c08;
2273     }
2274     /* idaten */
2275     if (strcmp (ROMId, "AIIJ") == 0)
2276     {
2277         SA1.WaitAddress = SA1.Map [0xc100be >> MEMMAP_SHIFT] + 0x00be;
2278         SA1.WaitByteAddress1 = SRAM + 0x1002;
2279         SA1.WaitByteAddress2 = SRAM + 0x1004;
2280     }
2281     /* igotais */
2282     if (strcmp (ROMId, "AITJ") == 0)
2283     {
2284         SA1.WaitAddress = SA1.Map [0x0080b7 >> MEMMAP_SHIFT] + 0x80b7;
2285     }
2286     /* J96 DREAM STADIUM */
2287     if (strcmp (ROMId, "AJ6J") == 0)
2288     {
2289         SA1.WaitAddress = SA1.Map [0xc0f74a >> MEMMAP_SHIFT] + 0xf74a;
2290     }
2291     /* JumpinDerby */
2292     if (strcmp (ROMId, "AJUJ") == 0)
2293     {
2294         SA1.WaitAddress = SA1.Map [0x00d926 >> MEMMAP_SHIFT] + 0xd926;
2295     }
2296     /* JKAKINOKI SHOUGI */
2297     if (strcmp (ROMId, "AKAJ") == 0)
2298     {
2299         SA1.WaitAddress = SA1.Map [0x00f070 >> MEMMAP_SHIFT] + 0xf070;
2300     }
2301     /* HOSHI NO KIRBY 3 & KIRBY'S DREAM LAND 3 JAP & US */
2302     if (strcmp (ROMId, "AFJJ") == 0 || strcmp (ROMId, "AFJE") == 0)
2303     {
2304         SA1.WaitAddress = SA1.Map [0x0082d4 >> MEMMAP_SHIFT] + 0x82d4;
2305         SA1.WaitByteAddress1 = SRAM + 0x72a4;
2306     }
2307     /* KIRBY SUPER DELUXE JAP */
2308     if (strcmp (ROMId, "AKFJ") == 0)
2309     {
2310         SA1.WaitAddress = SA1.Map [0x008c93 >> MEMMAP_SHIFT] + 0x8c93;
2311         SA1.WaitByteAddress1 = FillRAM + 0x300a;
2312         SA1.WaitByteAddress2 = FillRAM + 0x300e;
2313     }
2314     /* KIRBY SUPER DELUXE US */
2315     if (strcmp (ROMId, "AKFE") == 0)
2316     {
2317         SA1.WaitAddress = SA1.Map [0x008cb8 >> MEMMAP_SHIFT] + 0x8cb8;
2318         SA1.WaitByteAddress1 = FillRAM + 0x300a;
2319         SA1.WaitByteAddress2 = FillRAM + 0x300e;
2320     }
2321     /* SUPER MARIO RPG JAP & US */
2322     if (strcmp (ROMId, "ARWJ") == 0 || strcmp (ROMId, "ARWE") == 0)
2323     {
2324         SA1.WaitAddress = SA1.Map [0xc0816f >> MEMMAP_SHIFT] + 0x816f;
2325         SA1.WaitByteAddress1 = FillRAM + 0x3000;
2326     }
2327     /* marvelous.zip */
2328     if (strcmp (ROMId, "AVRJ") == 0)
2329     {
2330         SA1.WaitAddress = SA1.Map [0x0085f2 >> MEMMAP_SHIFT] + 0x85f2;
2331         SA1.WaitByteAddress1 = FillRAM + 0x3024;
2332     }
2333     /* AUGUSTA3 MASTERS NEW */
2334     if (strcmp (ROMId, "AO3J") == 0)
2335     {
2336         SA1.WaitAddress = SA1.Map [0x00dddb >> MEMMAP_SHIFT] + 0xdddb;
2337         SA1.WaitByteAddress1 = FillRAM + 0x37b4;
2338     }
2339     /* OSHABERI PARODIUS */
2340     if (strcmp (ROMId, "AJOJ") == 0)
2341     {
2342         SA1.WaitAddress = SA1.Map [0x8084e5 >> MEMMAP_SHIFT] + 0x84e5;
2343     }
2344     /* PANIC BOMBER WORLD */
2345     if (strcmp (ROMId, "APBJ") == 0)
2346     {
2347         SA1.WaitAddress = SA1.Map [0x00857a >> MEMMAP_SHIFT] + 0x857a;
2348     }
2349     /* PEBBLE BEACH NEW */
2350     if (strcmp (ROMId, "AONJ") == 0)
2351     {
2352         SA1.WaitAddress = SA1.Map [0x00df33 >> MEMMAP_SHIFT] + 0xdf33;
2353         SA1.WaitByteAddress1 = FillRAM + 0x37b4;
2354     }
2355     /* PGA EUROPEAN TOUR */
2356     if (strcmp (ROMId, "AEPE") == 0)
2357     {
2358         SA1.WaitAddress = SA1.Map [0x003700 >> MEMMAP_SHIFT] + 0x3700;
2359         SA1.WaitByteAddress1 = FillRAM + 0x3102;
2360     }
2361     /* PGA TOUR 96 */
2362     if (strcmp (ROMId, "A3GE") == 0)
2363     {
2364         SA1.WaitAddress = SA1.Map [0x003700 >> MEMMAP_SHIFT] + 0x3700;
2365         SA1.WaitByteAddress1 = FillRAM + 0x3102;
2366     }
2367     /* POWER RANGERS 4 */
2368     if (strcmp (ROMId, "A4RE") == 0)
2369     {
2370         SA1.WaitAddress = SA1.Map [0x009899 >> MEMMAP_SHIFT] + 0x9899;
2371         SA1.WaitByteAddress1 = FillRAM + 0x3000;
2372     }
2373     /* PACHISURO PALUSUPE */
2374     if (strcmp (ROMId, "AGFJ") == 0)
2375     {
2376         // Never seems to turn on the SA-1!
2377     }
2378     /* SD F1 GRAND PRIX */
2379     if (strcmp (ROMId, "AGFJ") == 0)
2380     {
2381         SA1.WaitAddress = SA1.Map [0x0181bc >> MEMMAP_SHIFT] + 0x81bc;
2382     }
2383     /* SHOUGI MARJONG */
2384     if (strcmp (ROMId, "ASYJ") == 0)
2385     {
2386         SA1.WaitAddress = SA1.Map [0x00f2cc >> MEMMAP_SHIFT] + 0xf2cc;
2387         SA1.WaitByteAddress1 = SRAM + 0x7ffe;
2388         SA1.WaitByteAddress2 = SRAM + 0x7ffc;
2389     }
2390     /* shogisai2 */
2391     if (strcmp (ROMId, "AX2J") == 0)
2392     {
2393         SA1.WaitAddress = SA1.Map [0x00d675 >> MEMMAP_SHIFT] + 0xd675;
2394     }
2395
2396     /* SHINING SCORPION */
2397     if (strcmp (ROMId, "A4WJ") == 0)
2398     {
2399         SA1.WaitAddress = SA1.Map [0xc048be >> MEMMAP_SHIFT] + 0x48be;
2400     }
2401     /* SHIN SHOUGI CLUB */
2402     if (strcmp (ROMId, "AHJJ") == 0)
2403     {
2404         SA1.WaitAddress = SA1.Map [0xc1002a >> MEMMAP_SHIFT] + 0x002a;
2405         SA1.WaitByteAddress1 = SRAM + 0x0806;
2406         SA1.WaitByteAddress2 = SRAM + 0x0808;
2407     }
2408
2409     // Additional game fixes by sanmaiwashi ...
2410     if (strcmp (ROMName, "SFX Å²Ä¶ÞÝÀÞÑÓɶÞÀØ 1") == 0) 
2411     {
2412         bytes0x2000 [0xb18] = 0x4c;
2413         bytes0x2000 [0xb19] = 0x4b;
2414         bytes0x2000 [0xb1a] = 0xea;
2415     }
2416
2417     if (strcmp (ROMName, "GOGO ACKMAN3") == 0 || 
2418         strcmp (ROMName, "HOME ALONE") == 0)
2419     {
2420         // Banks 00->3f and 80->bf
2421         for (int c = 0; c < 0x400; c += 16)
2422         {
2423             Map [c + 6] = Map [c + 0x806] = SRAM;
2424             Map [c + 7] = Map [c + 0x807] = SRAM;
2425             BlockIsROM [c + 6] = BlockIsROM [c + 0x806] = FALSE;
2426             BlockIsROM [c + 7] = BlockIsROM [c + 0x807] = FALSE;
2427             BlockIsRAM [c + 6] = BlockIsRAM [c + 0x806] = TRUE;
2428             BlockIsRAM [c + 7] = BlockIsRAM [c + 0x807] = TRUE;
2429         }
2430         WriteProtectROM ();
2431     }
2432
2433     if (strncmp (ROMName, "SWORD WORLD SFC", 15) == 0 ||
2434         strcmp (ROMName, "SFC ¶ÒÝײÀÞ°") == 0)
2435     {
2436         IAPU.OneCycle = 15;
2437         SNESGameFixes.NeedInit0x2137 = TRUE;
2438         Settings.APUEnabled  |= 2;
2439         CPU.APU_APUExecuting |= 2;
2440     }
2441
2442     if (strncmp (ROMName, "SHIEN THE BLADE CHASE", 21) == 0)
2443         SNESGameFixes.Old_Read0x4200 = TRUE;
2444
2445     if (strcmp (ROMName, "ºÞ¼Þ× ¶²¼Þ­³ÀÞ²¹¯¾Ý") == 0)
2446         SNESGameFixes.NeedInit0x2137 = TRUE;
2447
2448     if (strcmp (ROMName, "UMIHARAKAWASE") == 0)
2449         SNESGameFixes.umiharakawaseFix = TRUE;
2450
2451     if (strcmp (ROMName, "ALIENS vs. PREDATOR") == 0)
2452         SNESGameFixes.alienVSpredetorFix = TRUE;
2453
2454     if (strcmp (ROMName, "demon's blazon") == 0 ||
2455         strcmp (ROMName, "demon's crest") == 0 ||
2456         strcmp (ROMName, "ROCKMAN X") == 0 ||
2457         strcmp (ROMName, "MEGAMAN X") == 0)
2458     {
2459
2460         // CAPCOM's protect
2461         // Banks 0x808000, 0x408000 are mirroring.
2462         for (int c = 0; c < 8; c++)
2463             Map [0x408 + c] = ROM - 0x8000;
2464     }
2465
2466     if (strcmp (ROMName, "½°Ȩ̂߰нÀ") == 0 || 
2467         strcmp (ROMName, "½°Ȩ̂߰нÀ 2") == 0 ||
2468         strcmp (ROMName, "ZENKI TENCHIMEIDOU") == 0 ||
2469         strcmp (ROMName, "GANBA LEAGUE") == 0)
2470     {
2471         SNESGameFixes.APU_OutPorts_ReturnValueFix = TRUE;
2472     }
2473
2474     // HITOMI3
2475     if (strcmp (ROMName, "HITOMI3") == 0)
2476     {
2477         Memory.SRAMSize = 1;
2478         CPU.Memory_SRAMMask = Memory.SRAMSize ?
2479                         ((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0;
2480     }
2481
2482     if (strcmp (ROMName, "goemon 4") == 0)
2483         SNESGameFixes.SRAMInitialValue = 0x00;
2484
2485     if (strcmp (ROMName, "PACHISLO ¹Ý·­³") == 0)
2486         SNESGameFixes._0x213E_ReturnValue = 1;
2487
2488     if (strcmp (ROMName, "»Þ Ï°¼Þ¬Ý Ä³Ê²ÃÞÝ") == 0)
2489         SNESGameFixes.TouhaidenControllerFix = TRUE;
2490
2491     if (strcmp (ROMName, "DRAGON KNIGHT 4") == 0)
2492     {
2493         // Banks 70->7e, S-RAM
2494         for (int c = 0; c < 0xe0; c++)
2495         {
2496             Map [c + 0x700] = (uint8 *) MAP_LOROM_SRAM;
2497             BlockIsRAM [c + 0x700] = TRUE;
2498             BlockIsROM [c + 0x700] = FALSE;
2499         }
2500         WriteProtectROM ();
2501     }
2502
2503     if (strncmp (ROMName, "LETs PACHINKO(", 14) == 0)
2504     {
2505         IAPU.OneCycle = 15;
2506         Settings.APUEnabled  |= 2;
2507         CPU.APU_APUExecuting |= 2;
2508         if (!Settings.ForceNTSC && !Settings.ForcePAL)
2509         {
2510             Settings.PAL = FALSE;
2511             Settings.FrameTime = Settings.FrameTimeNTSC;
2512             Memory.ROMFramesPerSecond = 60;
2513         }
2514     }
2515
2516     if (strcmp (ROMName, "FURAI NO SIREN") == 0)
2517         SNESGameFixes.SoundEnvelopeHeightReading2 = TRUE;
2518 #if 0
2519     if(strcmp (ROMName, "XBAND JAPANESE MODEM") == 0)
2520     {
2521         for (c = 0x200; c < 0x400; c += 16)
2522         {
2523             for (int i = c; i < c + 16; i++)
2524             {
2525                 Map [i + 0x400] = Map [i + 0xc00] = &ROM[c * 0x1000];
2526                 MemorySpeed [i + 0x400] = MemorySpeed [i + 0xc00] = 8;
2527                 BlockIsRAM [i + 0x400] = BlockIsRAM [i + 0xc00] = TRUE;
2528                 BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = FALSE;
2529             }
2530         }
2531         WriteProtectROM ();
2532     }
2533 #endif
2534
2535 #define RomPatch(adr,ov,nv) \
2536 if (ROM [adr] == ov) \
2537     ROM [adr] = nv
2538
2539     // Love Quest
2540     if (strcmp (ROMName, "LOVE QUEST") == 0)
2541     {
2542         RomPatch (0x1385ec, 0xd0, 0xea);
2543         RomPatch (0x1385ed, 0xb2, 0xea);
2544     }
2545
2546     // Nangoku Syonen Papuwa Kun
2547     if (strcmp (ROMName, "NANGOKUSYONEN PAPUWA") == 0)
2548         RomPatch (0x1f0d1, 0xa0, 0x6b);
2549
2550     // Tetsuwan Atom
2551     if (strcmp (ROMName, "Tetsuwan Atom") == 0)
2552     {
2553         RomPatch (0xe24c5, 0x90, 0xea);
2554         RomPatch (0xe24c6, 0xf3, 0xea);
2555     }
2556
2557     // Oda Nobunaga
2558     if (strcmp (ROMName, "SFC ODA NOBUNAGA") == 0)
2559     {
2560         RomPatch (0x7497, 0x80, 0xea);
2561         RomPatch (0x7498, 0xd5, 0xea);
2562     }
2563
2564     // Super Batter Up
2565     if (strcmp (ROMName, "Super Batter Up") == 0)
2566     {
2567         RomPatch (0x27ae0, 0xd0, 0xea);
2568         RomPatch (0x27ae1, 0xfa, 0xea);
2569     }
2570
2571     // Super Professional Baseball 2
2572     if (strcmp (ROMName, "SUPER PRO. BASE BALL2") == 0)
2573     {
2574         RomPatch (0x1e4, 0x50, 0xea);
2575         RomPatch (0x1e5, 0xfb, 0xea);
2576     }
2577 }
2578
2579 // Read variable size MSB int from a file
2580 static long ReadInt (FILE *f, unsigned nbytes)
2581 {
2582     long v = 0;
2583     while (nbytes--)
2584     {
2585         int c = fgetc(f);
2586         if (c == EOF) 
2587             return -1;
2588         v = (v << 8) | (c & 0xFF);
2589     }
2590     return (v);
2591 }
2592
2593 #define IPS_EOF 0x00454F46l
2594
2595 void CMemory::CheckForIPSPatch (const char *rom_filename, bool8_32 header,
2596                                 int32 &rom_size)
2597 {
2598     char  dir [_MAX_DIR + 1];
2599     char  drive [_MAX_DRIVE + 1];
2600     char  name [_MAX_FNAME + 1];
2601     char  ext [_MAX_EXT + 1];
2602     char  fname [_MAX_PATH + 1];
2603     FILE  *patch_file  = NULL;
2604     long  offset = header ? 512 : 0;
2605
2606     if (!(patch_file = fopen(S9xGetFilename (".ips"), "rb"))) return;
2607
2608     if (fread (fname, 1, 5, patch_file) != 5 || strncmp (fname, "PATCH", 5) != 0)
2609     {
2610             fclose (patch_file);
2611             return;
2612     }
2613
2614     int32 ofs;
2615
2616     for (;;)
2617     {
2618         long len;
2619         long rlen;
2620         int  rchar;
2621
2622         ofs = ReadInt (patch_file, 3);
2623         if (ofs == -1)
2624             goto err_eof;
2625
2626         if (ofs == IPS_EOF) 
2627             break;
2628
2629         ofs -= offset;
2630
2631         len = ReadInt (patch_file, 2);
2632         if (len == -1)
2633             goto err_eof;
2634
2635         /* Apply patch block */
2636         if (len)
2637         {
2638             if (ofs + len > MAX_ROM_SIZE)
2639                 goto err_eof;
2640
2641             while (len--)
2642             {
2643                 rchar = fgetc (patch_file);
2644                 if (rchar == EOF) 
2645                     goto err_eof;
2646                 ROM [ofs++] = (uint8) rchar;
2647             }
2648             if (ofs > rom_size)
2649                 rom_size = ofs;
2650         }
2651         else
2652         {
2653             rlen = ReadInt (patch_file, 2);
2654             if (rlen == -1) 
2655                 goto err_eof;
2656
2657             rchar = fgetc (patch_file);
2658             if (rchar == EOF) 
2659                 goto err_eof;
2660
2661             if (ofs + rlen > MAX_ROM_SIZE)
2662                 goto err_eof;
2663
2664             while (rlen--) 
2665                 ROM [ofs++] = (uint8) rchar;
2666
2667             if (ofs > rom_size)
2668                 rom_size = ofs;
2669         }
2670     }
2671
2672     // Check if ROM image needs to be truncated
2673     ofs = ReadInt (patch_file, 3);
2674     if (ofs != -1 && ofs - offset < rom_size)
2675     {
2676         // Need to truncate ROM image
2677         rom_size = ofs - offset;
2678     }
2679     fclose (patch_file);
2680     return;
2681
2682 err_eof:
2683     if (patch_file) 
2684         fclose (patch_file);
2685 }
2686
2687 #undef INLINE
2688 #define INLINE
2689 #include "getset.h"