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