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