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