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