mirror of
https://github.com/dborth/snes9xgx.git
synced 2024-12-27 03:31:50 +01:00
4557 lines
111 KiB
C++
4557 lines
111 KiB
C++
/**********************************************************************************
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and
|
|
Jerremy Koot (jkoot@snes9x.com)
|
|
|
|
(c) Copyright 2002 - 2004 Matthew Kendora
|
|
|
|
(c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
|
|
|
|
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
|
|
|
|
(c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
|
|
|
|
(c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net),
|
|
funkyass (funkyass@spam.shaw.ca),
|
|
Kris Bleakley (codeviolation@hotmail.com),
|
|
Nach (n-a-c-h@users.sourceforge.net), and
|
|
zones (kasumitokoduck@yahoo.com)
|
|
|
|
BS-X C emulator code
|
|
(c) Copyright 2005 - 2006 Dreamer Nom,
|
|
zones
|
|
|
|
C4 x86 assembler and some C emulation code
|
|
(c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
|
|
Nach,
|
|
zsKnight (zsknight@zsnes.com)
|
|
|
|
C4 C++ code
|
|
(c) Copyright 2003 - 2006 Brad Jorsch,
|
|
Nach
|
|
|
|
DSP-1 emulator code
|
|
(c) Copyright 1998 - 2006 _Demo_,
|
|
Andreas Naive (andreasnaive@gmail.com)
|
|
Gary Henderson,
|
|
Ivar (ivar@snes9x.com),
|
|
John Weidman,
|
|
Kris Bleakley,
|
|
Matthew Kendora,
|
|
Nach,
|
|
neviksti (neviksti@hotmail.com)
|
|
|
|
DSP-2 emulator code
|
|
(c) Copyright 2003 John Weidman,
|
|
Kris Bleakley,
|
|
Lord Nightmare (lord_nightmare@users.sourceforge.net),
|
|
Matthew Kendora,
|
|
neviksti
|
|
|
|
|
|
DSP-3 emulator code
|
|
(c) Copyright 2003 - 2006 John Weidman,
|
|
Kris Bleakley,
|
|
Lancer,
|
|
z80 gaiden
|
|
|
|
DSP-4 emulator code
|
|
(c) Copyright 2004 - 2006 Dreamer Nom,
|
|
John Weidman,
|
|
Kris Bleakley,
|
|
Nach,
|
|
z80 gaiden
|
|
|
|
OBC1 emulator code
|
|
(c) Copyright 2001 - 2004 zsKnight,
|
|
pagefault (pagefault@zsnes.com),
|
|
Kris Bleakley,
|
|
Ported from x86 assembler to C by sanmaiwashi
|
|
|
|
SPC7110 and RTC C++ emulator code
|
|
(c) Copyright 2002 Matthew Kendora with research by
|
|
zsKnight,
|
|
John Weidman,
|
|
Dark Force
|
|
|
|
S-DD1 C emulator code
|
|
(c) Copyright 2003 Brad Jorsch with research by
|
|
Andreas Naive,
|
|
John Weidman
|
|
|
|
S-RTC C emulator code
|
|
(c) Copyright 2001-2006 byuu,
|
|
John Weidman
|
|
|
|
ST010 C++ emulator code
|
|
(c) Copyright 2003 Feather,
|
|
John Weidman,
|
|
Kris Bleakley,
|
|
Matthew Kendora
|
|
|
|
Super FX x86 assembler emulator code
|
|
(c) Copyright 1998 - 2003 _Demo_,
|
|
pagefault,
|
|
zsKnight,
|
|
|
|
Super FX C emulator code
|
|
(c) Copyright 1997 - 1999 Ivar,
|
|
Gary Henderson,
|
|
John Weidman
|
|
|
|
Sound DSP emulator code is derived from SNEeSe and OpenSPC:
|
|
(c) Copyright 1998 - 2003 Brad Martin
|
|
(c) Copyright 1998 - 2006 Charles Bilyue'
|
|
|
|
SH assembler code partly based on x86 assembler code
|
|
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
|
|
|
|
2xSaI filter
|
|
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
|
|
|
|
HQ2x filter
|
|
(c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
|
|
|
|
Specific ports contains the works of other authors. See headers in
|
|
individual files.
|
|
|
|
Snes9x homepage: http://www.snes9x.com
|
|
|
|
Permission to use, copy, modify and/or distribute Snes9x in both binary
|
|
and source form, for non-commercial purposes, is hereby granted without
|
|
fee, providing that this license information and copyright notice appear
|
|
with all copies and any derived work.
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event shall the authors be held liable for any damages
|
|
arising from the use of this software or it's derivatives.
|
|
|
|
Snes9x is freeware for PERSONAL USE only. Commercial users should
|
|
seek permission of the copyright holders first. Commercial use includes,
|
|
but is not limited to, charging money for Snes9x or software derived from
|
|
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
|
|
using Snes9x as a promotion for your commercial product.
|
|
|
|
The copyright holders request that bug fixes and improvements to the code
|
|
should be forwarded to them so everyone can benefit from the modifications
|
|
in future versions.
|
|
|
|
Super NES and Super Nintendo Entertainment System are trademarks of
|
|
Nintendo Co., Limited and its subsidiary companies.
|
|
**********************************************************************************/
|
|
|
|
|
|
#include <string.h>
|
|
#ifdef HAVE_STRINGS_H
|
|
#include <strings.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
|
|
#ifdef __linux
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef JMA_SUPPORT
|
|
#include "jma/s9x-jma.h"
|
|
#endif
|
|
|
|
#include "snes9x.h"
|
|
#include "memmap.h"
|
|
#include "cpuexec.h"
|
|
#include "ppu.h"
|
|
#include "display.h"
|
|
|
|
#include "cheats.h"
|
|
|
|
#include "apu.h"
|
|
#include "sa1.h"
|
|
#include "dsp1.h"
|
|
#include "srtc.h"
|
|
#include "sdd1.h"
|
|
#include "spc7110.h"
|
|
#include "seta.h"
|
|
#include "bsx.h"
|
|
|
|
#ifndef NGC
|
|
#include "reader.h"
|
|
#else
|
|
#include <gccore.h>
|
|
#include "aram.h" /*** Nintendo GameCube ARAM loader.
|
|
FileLoader requires that the ROM is preloaded in ARAM first
|
|
***/
|
|
extern unsigned long ARAM_ROMSIZE;
|
|
extern int hasloaded;
|
|
#endif
|
|
|
|
#include "controls.h"
|
|
|
|
#ifdef UNZIP_SUPPORT
|
|
#include "unzip.h"
|
|
#endif
|
|
|
|
#ifdef __W32_HEAP
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
#ifndef ZSNES_FX
|
|
#include "fxemu.h"
|
|
extern struct FxInit_s SuperFX;
|
|
#else
|
|
START_EXTERN_C
|
|
extern uint8 *SFXPlotTable;
|
|
END_EXTERN_C
|
|
#endif
|
|
|
|
#ifndef SET_UI_COLOR
|
|
#define SET_UI_COLOR(r,g,b) ;
|
|
#endif
|
|
|
|
//you would think everyone would have these
|
|
//since they're so useful.
|
|
#ifndef max
|
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#ifndef min
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
static int retry_count=0;
|
|
void S9xDeinterleaveType2 (bool8 reset=TRUE);
|
|
inline uint32 caCRC32(uint8 *array, uint32 size, register uint32 crc32 = 0xFFFFFFFF);
|
|
|
|
extern char *rom_filename;
|
|
|
|
const uint32 crc32Table[256] = {
|
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
|
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
|
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
|
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
|
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
|
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
|
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
|
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
|
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
|
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
|
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
|
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
|
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
|
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
|
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
|
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
|
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
|
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
|
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
|
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
|
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
|
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
|
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
|
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
|
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
|
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
|
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
|
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
|
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
|
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
|
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
|
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
|
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
|
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
|
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
|
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
|
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
|
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
|
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
|
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
|
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
|
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
|
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
|
};
|
|
|
|
|
|
|
|
void S9xDeinterleaveType1(int TotalFileSize, uint8 * base)
|
|
{
|
|
if(Settings.DisplayColor==0xffff)
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(0,31,0);
|
|
SET_UI_COLOR(0,255,0);
|
|
}
|
|
|
|
int i;
|
|
int nblocks = TotalFileSize >> 16;
|
|
uint8 blocks [256];
|
|
for (i = 0; i < nblocks; i++)
|
|
{
|
|
blocks [i * 2] = i + nblocks;
|
|
blocks [i * 2 + 1] = i;
|
|
}
|
|
uint8 *tmp = (uint8 *) malloc (0x8000);
|
|
if (tmp)
|
|
{
|
|
for (i = 0; i < nblocks * 2; i++)
|
|
{
|
|
for (int j = i; j < nblocks * 2; j++)
|
|
{
|
|
if (blocks [j] == i)
|
|
{
|
|
memmove (tmp, &base [blocks [j] * 0x8000], 0x8000);
|
|
memmove (&base [blocks [j] * 0x8000],
|
|
&base [blocks [i] * 0x8000], 0x8000);
|
|
memmove (&base [blocks [i] * 0x8000], tmp, 0x8000);
|
|
uint8 b = blocks [j];
|
|
blocks [j] = blocks [i];
|
|
blocks [i] = b;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
free ((char *) tmp);
|
|
}
|
|
}
|
|
|
|
void S9xDeinterleaveGD24(int TotalFileSize, uint8 * base)
|
|
{
|
|
|
|
if(TotalFileSize!=0x300000)
|
|
return;
|
|
|
|
if(Settings.DisplayColor==0xffff)
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(0,31,31);
|
|
SET_UI_COLOR(0,255,255);
|
|
}
|
|
|
|
uint8 *tmp = (uint8 *) malloc (0x80000);
|
|
if (tmp)
|
|
{
|
|
memmove(tmp, &base[0x180000], 0x80000);
|
|
memmove(&base[0x180000], &base[0x200000], 0x80000);
|
|
memmove(&base[0x200000], &base[0x280000], 0x80000);
|
|
memmove(&base[0x280000], tmp, 0x80000);
|
|
free ((char *) tmp);
|
|
|
|
S9xDeinterleaveType1(TotalFileSize, base);
|
|
}
|
|
}
|
|
|
|
bool8 CMemory::AllASCII (uint8 *b, int size)
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
if (b[i] < 32 || b[i] > 126)
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
int CMemory::ScoreHiROM (bool8 skip_header, int32 romoff)
|
|
{
|
|
int score = 0;
|
|
int o = skip_header ? 0xff00 + 0x200 : 0xff00;
|
|
|
|
o+=romoff;
|
|
|
|
if(Memory.ROM [o + 0xd5] & 0x1)
|
|
score+=2;
|
|
|
|
//Mode23 is SA-1
|
|
if(Memory.ROM [o + 0xd5] == 0x23)
|
|
score-=2;
|
|
|
|
if(Memory.ROM [o+0xd4] == 0x20)
|
|
score +=2;
|
|
|
|
if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) +
|
|
Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff)
|
|
{
|
|
score += 2;
|
|
if(0!=(Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)))
|
|
score++;
|
|
}
|
|
|
|
if (Memory.ROM [o + 0xda] == 0x33)
|
|
score += 2;
|
|
if ((Memory.ROM [o + 0xd5] & 0xf) < 4)
|
|
score += 2;
|
|
if (!(Memory.ROM [o + 0xfd] & 0x80))
|
|
score -= 6;
|
|
if ((Memory.ROM [o + 0xfc]|(Memory.ROM [o + 0xfd]<<8))>0xFFB0)
|
|
score -= 2; //reduced after looking at a scan by Cowering
|
|
if (CalculatedSize > 1024 * 1024 * 3)
|
|
score += 4;
|
|
if ((1 << (Memory.ROM [o + 0xd7] - 7)) > 48)
|
|
score -= 1;
|
|
if (!AllASCII (&Memory.ROM [o + 0xb0], 6))
|
|
score -= 1;
|
|
if (!AllASCII (&Memory.ROM [o + 0xc0], ROM_NAME_LEN - 1))
|
|
score -= 1;
|
|
|
|
return (score);
|
|
}
|
|
|
|
int CMemory::ScoreLoROM (bool8 skip_header, int32 romoff)
|
|
{
|
|
int score = 0;
|
|
int o = skip_header ? 0x7f00 + 0x200 : 0x7f00;
|
|
|
|
o+=romoff;
|
|
|
|
if(!(Memory.ROM [o + 0xd5] & 0x1))
|
|
score+=3;
|
|
|
|
//Mode23 is SA-1
|
|
if(Memory.ROM [o + 0xd5] == 0x23)
|
|
score+=2;
|
|
|
|
if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) +
|
|
Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff)
|
|
{
|
|
score += 2;
|
|
if(0!=(Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)))
|
|
score++;
|
|
}
|
|
|
|
if (Memory.ROM [o + 0xda] == 0x33)
|
|
score += 2;
|
|
if ((Memory.ROM [o + 0xd5] & 0xf) < 4)
|
|
score += 2;
|
|
if (CalculatedSize <= 1024 * 1024 * 16)
|
|
score += 2;
|
|
if (!(Memory.ROM [o + 0xfd] & 0x80))
|
|
score -= 6;
|
|
if ((Memory.ROM [o + 0xfc]|(Memory.ROM [o + 0xfd]<<8))>0xFFB0)
|
|
score -= 2;//reduced per Cowering suggestion
|
|
if ((1 << (Memory.ROM [o + 0xd7] - 7)) > 48)
|
|
score -= 1;
|
|
if (!AllASCII (&Memory.ROM [o + 0xb0], 6))
|
|
score -= 1;
|
|
if (!AllASCII (&Memory.ROM [o + 0xc0], ROM_NAME_LEN - 1))
|
|
score -= 1;
|
|
|
|
return (score);
|
|
}
|
|
|
|
char *CMemory::Safe (const char *s)
|
|
{
|
|
static char *safe;
|
|
static int safe_len = 0;
|
|
|
|
if(s==NULL)
|
|
{
|
|
if(safe!=NULL)
|
|
{
|
|
free((char*)safe);
|
|
safe = NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
int len = strlen (s);
|
|
if (!safe || len + 1 > safe_len)
|
|
{
|
|
if (safe)
|
|
free ((char *) safe);
|
|
safe = (char *) malloc (safe_len = len + 1);
|
|
}
|
|
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
if (s [i] >= 32 && s [i] < 127)
|
|
safe [i] = s[i];
|
|
else
|
|
safe [i] = '?';
|
|
}
|
|
safe [len] = 0;
|
|
return (safe);
|
|
}
|
|
|
|
char *CMemory::SafeANK (const char *s)
|
|
{
|
|
static char *safe;
|
|
static int safe_len = 0;
|
|
|
|
if(s==NULL)
|
|
{
|
|
if(safe!=NULL)
|
|
{
|
|
free((char*)safe);
|
|
safe = NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
int len = strlen (s);
|
|
if (!safe || len + 1 > safe_len)
|
|
{
|
|
if (safe)
|
|
free ((char *) safe);
|
|
safe = (char *) malloc (safe_len = len + 1);
|
|
}
|
|
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
if (s [i] >= 32 && s [i] < 127) // ASCII
|
|
safe [i] = s[i];
|
|
else
|
|
if (Memory.ROMRegion == 0 && ((unsigned char) s[i] >= 0xa0 && (unsigned char) s[i] < 0xe0)) // JIS X 201
|
|
safe [i] = s[i];
|
|
else
|
|
safe [i] = '?';
|
|
|
|
}
|
|
safe [len] = 0;
|
|
return (safe);
|
|
}
|
|
|
|
/**********************************************************************************************/
|
|
/* Init() */
|
|
/* This function allocates all the memory needed by the emulator */
|
|
/**********************************************************************************************/
|
|
bool8 CMemory::Init ()
|
|
{
|
|
RAM = (uint8 *) malloc (0x20000);
|
|
SRAM = (uint8 *) malloc (0x20000);
|
|
VRAM = (uint8 *) malloc (0x10000);
|
|
ROM = (uint8 *) malloc (MAX_ROM_SIZE + 0x200 + 0x8000);
|
|
|
|
memset (RAM, 0, 0x20000);
|
|
memset (SRAM, 0, 0x20000);
|
|
memset (VRAM, 0, 0x10000);
|
|
memset (ROM, 0, MAX_ROM_SIZE + 0x200 + 0x8000);
|
|
|
|
FillRAM = NULL;
|
|
|
|
IPPU.TileCache [TILE_2BIT] = (uint8 *) malloc (MAX_2BIT_TILES * 64);
|
|
IPPU.TileCache [TILE_4BIT] = (uint8 *) malloc (MAX_4BIT_TILES * 64);
|
|
IPPU.TileCache [TILE_8BIT] = (uint8 *) malloc (MAX_8BIT_TILES * 64);
|
|
IPPU.TileCache [TILE_2BIT_EVEN] = (uint8 *) malloc (MAX_2BIT_TILES * 64);
|
|
IPPU.TileCache [TILE_2BIT_ODD] = (uint8 *) malloc (MAX_2BIT_TILES * 64);
|
|
IPPU.TileCache [TILE_4BIT_EVEN] = (uint8 *) malloc (MAX_4BIT_TILES * 64);
|
|
IPPU.TileCache [TILE_4BIT_ODD] = (uint8 *) malloc (MAX_4BIT_TILES * 64);
|
|
|
|
IPPU.TileCached [TILE_2BIT] = (uint8 *) malloc (MAX_2BIT_TILES);
|
|
IPPU.TileCached [TILE_4BIT] = (uint8 *) malloc (MAX_4BIT_TILES);
|
|
IPPU.TileCached [TILE_8BIT] = (uint8 *) malloc (MAX_8BIT_TILES);
|
|
IPPU.TileCached [TILE_2BIT_EVEN] = (uint8 *) malloc (MAX_2BIT_TILES);
|
|
IPPU.TileCached [TILE_2BIT_ODD] = (uint8 *) malloc (MAX_2BIT_TILES);
|
|
IPPU.TileCached [TILE_4BIT_EVEN] = (uint8 *) malloc (MAX_4BIT_TILES);
|
|
IPPU.TileCached [TILE_4BIT_ODD] = (uint8 *) malloc (MAX_4BIT_TILES);
|
|
|
|
if (!RAM || !SRAM || !VRAM || !ROM ||
|
|
!IPPU.TileCache [TILE_2BIT] || !IPPU.TileCache [TILE_4BIT] ||
|
|
!IPPU.TileCache [TILE_8BIT] || !IPPU.TileCached [TILE_2BIT] ||
|
|
!IPPU.TileCached [TILE_4BIT] || !IPPU.TileCached [TILE_8BIT] ||
|
|
!IPPU.TileCache [TILE_2BIT_EVEN] || !IPPU.TileCache [TILE_2BIT_ODD] ||
|
|
!IPPU.TileCache [TILE_4BIT_EVEN] || !IPPU.TileCache [TILE_4BIT_ODD] ||
|
|
!IPPU.TileCached [TILE_2BIT_EVEN] || !IPPU.TileCached [TILE_2BIT_ODD] ||
|
|
!IPPU.TileCached [TILE_4BIT_EVEN] || !IPPU.TileCached [TILE_4BIT_ODD])
|
|
{
|
|
Deinit ();
|
|
return (FALSE);
|
|
}
|
|
|
|
// FillRAM uses first 32K of ROM image area, otherwise space just
|
|
// wasted. Might be read by the SuperFX code.
|
|
|
|
FillRAM = ROM;
|
|
|
|
// Add 0x8000 to ROM image pointer to stop SuperFX code accessing
|
|
// unallocated memory (can cause crash on some ports).
|
|
ROM += 0x8000;
|
|
|
|
C4RAM = ROM + 0x400000 + 8192 * 8;
|
|
::ROM = ROM;
|
|
::SRAM = SRAM;
|
|
::RegRAM = FillRAM;
|
|
|
|
// BS
|
|
BIOSROM = ROM + 0x300000;
|
|
BSRAM = ROM + 0x400000;
|
|
|
|
#ifdef ZSNES_FX
|
|
SFXPlotTable = ROM + 0x400000;
|
|
#else
|
|
SuperFX.pvRegisters = &Memory.FillRAM [0x3000];
|
|
SuperFX.nRamBanks = 2; // Most only use 1. 1=64KB, 2=128KB=1024Mb
|
|
SuperFX.pvRam = ::SRAM;
|
|
SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024);
|
|
SuperFX.pvRom = (uint8 *) ROM;
|
|
#endif
|
|
|
|
ZeroMemory (IPPU.TileCache [TILE_2BIT], MAX_2BIT_TILES * 64);
|
|
ZeroMemory (IPPU.TileCache [TILE_4BIT], MAX_4BIT_TILES * 64);
|
|
ZeroMemory (IPPU.TileCache [TILE_8BIT], MAX_8BIT_TILES * 64);
|
|
ZeroMemory (IPPU.TileCache [TILE_2BIT_EVEN], MAX_2BIT_TILES * 64);
|
|
ZeroMemory (IPPU.TileCache [TILE_2BIT_ODD], MAX_2BIT_TILES * 64);
|
|
ZeroMemory (IPPU.TileCache [TILE_4BIT_EVEN], MAX_4BIT_TILES * 64);
|
|
ZeroMemory (IPPU.TileCache [TILE_4BIT_ODD], MAX_4BIT_TILES * 64);
|
|
|
|
ZeroMemory (IPPU.TileCached [TILE_2BIT], MAX_2BIT_TILES);
|
|
ZeroMemory (IPPU.TileCached [TILE_4BIT], MAX_4BIT_TILES);
|
|
ZeroMemory (IPPU.TileCached [TILE_8BIT], MAX_8BIT_TILES);
|
|
ZeroMemory (IPPU.TileCached [TILE_2BIT_EVEN], MAX_2BIT_TILES);
|
|
ZeroMemory (IPPU.TileCached [TILE_2BIT_ODD], MAX_2BIT_TILES);
|
|
ZeroMemory (IPPU.TileCached [TILE_4BIT_EVEN], MAX_4BIT_TILES);
|
|
ZeroMemory (IPPU.TileCached [TILE_4BIT_ODD], MAX_4BIT_TILES);
|
|
|
|
SDD1Data = NULL;
|
|
SDD1Index = NULL;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
void CMemory::Deinit ()
|
|
{
|
|
#ifdef __W32_HEAP
|
|
if(_HEAPOK!=_heapchk())
|
|
MessageBox(GUI.hWnd, "CMemory::Deinit", "Heap Corrupt", MB_OK);
|
|
#endif
|
|
|
|
if (RAM)
|
|
{
|
|
free ((char *) RAM);
|
|
RAM = NULL;
|
|
}
|
|
if (SRAM)
|
|
{
|
|
free ((char *) SRAM);
|
|
SRAM = NULL;
|
|
}
|
|
if (VRAM)
|
|
{
|
|
free ((char *) VRAM);
|
|
VRAM = NULL;
|
|
}
|
|
if (ROM)
|
|
{
|
|
ROM -= 0x8000;
|
|
free ((char *) ROM);
|
|
ROM = NULL;
|
|
}
|
|
|
|
for(int t=0; t<7; t++){
|
|
if(IPPU.TileCache[t]) {
|
|
free ((char *) IPPU.TileCache[t]);
|
|
IPPU.TileCache[t] = NULL;
|
|
}
|
|
if(IPPU.TileCached[t]) {
|
|
free ((char *) IPPU.TileCached[t]);
|
|
IPPU.TileCached[t] = NULL;
|
|
}
|
|
}
|
|
|
|
FreeSDD1Data ();
|
|
Safe(NULL);
|
|
SafeANK(NULL);
|
|
}
|
|
|
|
void CMemory::FreeSDD1Data ()
|
|
{
|
|
if (SDD1Index)
|
|
{
|
|
free ((char *) SDD1Index);
|
|
SDD1Index = NULL;
|
|
}
|
|
if (SDD1Data)
|
|
{
|
|
free ((char *) SDD1Data);
|
|
SDD1Data = NULL;
|
|
}
|
|
}
|
|
|
|
/**********************************************************************************************/
|
|
/* LoadROM() */
|
|
/* This function loads a Snes-Backup image */
|
|
/**********************************************************************************************/
|
|
|
|
bool8 CMemory::LoadROM (const char *filename)
|
|
{
|
|
int32 TotalFileSize = 0;
|
|
bool8 Interleaved = FALSE;
|
|
bool8 Tales = FALSE;
|
|
|
|
uint8* RomHeader=ROM;
|
|
|
|
ExtendedFormat=NOPE;
|
|
|
|
|
|
if(CleanUp7110!=NULL)
|
|
(*CleanUp7110)();
|
|
|
|
memset (&SNESGameFixes, 0, sizeof(SNESGameFixes));
|
|
SNESGameFixes.SRAMInitialValue = 0x60;
|
|
|
|
CPU.TriedInterleavedMode2 = FALSE;
|
|
|
|
CalculatedSize = 0;
|
|
retry_count =0;
|
|
|
|
again:
|
|
Settings.DisplayColor=0xffff;
|
|
SET_UI_COLOR(255,255,255);
|
|
|
|
TotalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE);
|
|
|
|
if (!TotalFileSize)
|
|
return FALSE; // it ends here
|
|
|
|
#ifndef NGC
|
|
else if(!Settings.NoPatch)
|
|
CheckForIPSPatch (filename, HeaderCount != 0, TotalFileSize);
|
|
#endif
|
|
|
|
//fix hacked games here.
|
|
if((strncmp("HONKAKUHA IGO GOSEI", (char*)&ROM[0x7FC0],19)==0)&&(ROM[0x7FD5]!=0x31))
|
|
{
|
|
ROM[0x7FD5]=0x31;
|
|
ROM[0x7FD6]=0x02;
|
|
Settings.DisplayColor=BUILD_PIXEL(31,0,0);
|
|
SET_UI_COLOR(255,0,0);
|
|
S9xMessage(S9X_ERROR,S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!");
|
|
}
|
|
|
|
if((strncmp("HONKAKUHA IGO GOSEI", (char*)&ROM[0xFFC0],19)==0)&&(ROM[0xFFD5]!=0x31))
|
|
{
|
|
ROM[0xFFD5]=0x31;
|
|
ROM[0xFFD6]=0x02;
|
|
Settings.DisplayColor=BUILD_PIXEL(31,0,0);
|
|
SET_UI_COLOR(255,0,0);
|
|
S9xMessage(S9X_ERROR,S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!");
|
|
}
|
|
|
|
if((ROM[0x7FD5]==0x42)&&(ROM[0x7FD6]==0x13)&&(strncmp("METAL COMBAT",(char*)&ROM[0x7FC0],12)==0))
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(31,0,0);
|
|
SET_UI_COLOR(255,0,0);
|
|
S9xMessage(S9X_ERROR,S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!");
|
|
}
|
|
|
|
int orig_hi_score, orig_lo_score;
|
|
int hi_score, lo_score;
|
|
|
|
orig_hi_score = hi_score = ScoreHiROM (FALSE);
|
|
orig_lo_score = lo_score = ScoreLoROM (FALSE);
|
|
|
|
if (HeaderCount == 0 && !Settings.ForceNoHeader &&
|
|
((hi_score > lo_score && ScoreHiROM (TRUE) > hi_score) ||
|
|
(hi_score <= lo_score && ScoreLoROM (TRUE) > lo_score)))
|
|
{
|
|
memmove (Memory.ROM, Memory.ROM + 512, TotalFileSize - 512);
|
|
TotalFileSize -= 512;
|
|
S9xMessage (S9X_INFO, S9X_HEADER_WARNING,
|
|
"Try specifying the -nhd command line option if the game doesn't work\n");
|
|
//modifying ROM, so we need to rescore
|
|
orig_hi_score = hi_score = ScoreHiROM (FALSE);
|
|
orig_lo_score = lo_score = ScoreLoROM (FALSE);
|
|
}
|
|
|
|
CalculatedSize = (TotalFileSize / 0x2000) * 0x2000;
|
|
ZeroMemory (ROM + CalculatedSize, MAX_ROM_SIZE - CalculatedSize);
|
|
|
|
if(CalculatedSize >0x400000&&
|
|
!(ROM[0x7FD5]==0x32&&((ROM[0x7FD6]&0xF0)==0x40)) && //exclude S-DD1
|
|
!(ROM[0xFFD5]==0x3A&&((ROM[0xFFD6]&0xF0)==0xF0))) //exclude SPC7110
|
|
{
|
|
//you might be a Jumbo!
|
|
ExtendedFormat=YEAH;
|
|
}
|
|
|
|
//If both vectors are invalid, it's type 1 LoROM
|
|
|
|
if(ExtendedFormat==NOPE&&((ROM[0x7FFC]|(ROM[0x7FFD]<<8))<0x8000)&&((ROM[0xFFFC]|(ROM[0xFFFD]<<8)) <0x8000))
|
|
{
|
|
if(Settings.DisplayColor==0xffff)
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(0,31,0);
|
|
SET_UI_COLOR(0,255,0);
|
|
}
|
|
if(!Settings.ForceInterleaved)
|
|
S9xDeinterleaveType1(TotalFileSize, ROM);
|
|
}
|
|
|
|
//CalculatedSize is now set, so rescore
|
|
orig_hi_score = hi_score = ScoreHiROM (FALSE);
|
|
orig_lo_score = lo_score = ScoreLoROM (FALSE);
|
|
|
|
if(NOPE!=ExtendedFormat)
|
|
{
|
|
int loromscore, hiromscore, swappedlorom, swappedhirom;
|
|
loromscore=ScoreLoROM(FALSE);
|
|
hiromscore=ScoreHiROM(FALSE);
|
|
swappedlorom=ScoreLoROM(FALSE, 0x400000);
|
|
swappedhirom=ScoreHiROM(FALSE, 0x400000);
|
|
|
|
//set swapped here.
|
|
|
|
if(max(swappedlorom, swappedhirom) >= max(loromscore, hiromscore))
|
|
{
|
|
ExtendedFormat = BIGFIRST;
|
|
hi_score=swappedhirom;
|
|
lo_score=swappedlorom;
|
|
RomHeader=ROM+0x400000;
|
|
}
|
|
else
|
|
{
|
|
ExtendedFormat = SMALLFIRST;
|
|
lo_score=loromscore;
|
|
hi_score=hiromscore;
|
|
RomHeader=ROM;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
Interleaved = Settings.ForceInterleaved || Settings.ForceInterleaved2;
|
|
if (Settings.ForceLoROM || (!Settings.ForceHiROM && lo_score >= hi_score))
|
|
{
|
|
LoROM = TRUE;
|
|
HiROM = FALSE;
|
|
|
|
// Ignore map type byte if not 0x2x or 0x3x
|
|
if ((RomHeader [0x7fd5] & 0xf0) == 0x20 || (RomHeader [0x7fd5] & 0xf0) == 0x30)
|
|
{
|
|
switch (RomHeader [0x7fd5] & 0xf)
|
|
{
|
|
case 1:
|
|
Interleaved = TRUE;
|
|
break;
|
|
case 5:
|
|
Interleaved = TRUE;
|
|
Tales = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((RomHeader [0xffd5] & 0xf0) == 0x20 || (RomHeader [0xffd5] & 0xf0) == 0x30)
|
|
{
|
|
switch (RomHeader [0xffd5] & 0xf)
|
|
{
|
|
case 0:
|
|
case 3:
|
|
Interleaved = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
LoROM = FALSE;
|
|
HiROM = TRUE;
|
|
}
|
|
|
|
// More
|
|
if (!Settings.ForceHiROM && !Settings.ForceLoROM &&
|
|
!Settings.ForceInterleaved && !Settings.ForceInterleaved2 &&
|
|
!Settings.ForceNotInterleaved && !Settings.ForcePAL &&
|
|
!Settings.ForceSuperFX && !Settings.ForceDSP1 &&
|
|
!Settings.ForceSA1 && !Settings.ForceC4 &&
|
|
!Settings.ForceSDD1)
|
|
{
|
|
|
|
|
|
#ifdef DETECT_NASTY_FX_INTERLEAVE
|
|
//MK: Damn. YI trips a BRK currently. Maybe even on a real cart.
|
|
|
|
if(strncmp((char *)&ROM[0x7fc0], "YOSHI'S ISLAND", 14) == 0 && READ_WORD(ROM+0x7FDE)==57611 && ROM[0x10002]==0xA9)
|
|
{
|
|
Interleaved=true;
|
|
Settings.ForceInterleaved2=true;
|
|
}
|
|
#endif
|
|
if (strncmp ((char *) &ROM [0x7fc0], "YUYU NO QUIZ DE GO!GO!", 22) == 0)
|
|
{
|
|
LoROM = TRUE;
|
|
HiROM = FALSE;
|
|
Interleaved = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!Settings.ForceNotInterleaved && Interleaved)
|
|
{
|
|
CPU.TriedInterleavedMode2 = TRUE;
|
|
S9xMessage (S9X_INFO, S9X_ROM_INTERLEAVED_INFO,
|
|
"ROM image is in interleaved format - converting...");
|
|
|
|
if (Tales)
|
|
{
|
|
if(Memory.ExtendedFormat==BIGFIRST)
|
|
{
|
|
S9xDeinterleaveType1(0x400000, ROM);
|
|
S9xDeinterleaveType1(CalculatedSize-0x400000, ROM+0x400000);
|
|
}
|
|
else
|
|
{
|
|
S9xDeinterleaveType1(CalculatedSize-0x400000, ROM);
|
|
S9xDeinterleaveType1(0x400000, ROM+CalculatedSize-0x400000);
|
|
|
|
}
|
|
|
|
LoROM = FALSE;
|
|
HiROM = TRUE;
|
|
|
|
|
|
}
|
|
else if (Settings.ForceInterleaved2)
|
|
{
|
|
S9xDeinterleaveType2(FALSE);
|
|
}
|
|
else if (Settings.ForceInterleaveGD24 && CalculatedSize ==0x300000)
|
|
{
|
|
bool8 t = LoROM;
|
|
|
|
LoROM = HiROM;
|
|
HiROM = t;
|
|
S9xDeinterleaveGD24(CalculatedSize, ROM);
|
|
}
|
|
else
|
|
{
|
|
if(Settings.DisplayColor==0xffff)
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(0,31,0);
|
|
SET_UI_COLOR(0,255,0);
|
|
}
|
|
bool8 t = LoROM;
|
|
|
|
LoROM = HiROM;
|
|
HiROM = t;
|
|
|
|
S9xDeinterleaveType1(CalculatedSize, ROM);
|
|
}
|
|
|
|
hi_score = ScoreHiROM (FALSE);
|
|
lo_score = ScoreLoROM (FALSE);
|
|
|
|
if ((HiROM &&
|
|
(lo_score >= hi_score || hi_score < 0)) ||
|
|
(LoROM &&
|
|
(hi_score > lo_score || lo_score < 0)))
|
|
{
|
|
if (retry_count == 0)
|
|
{
|
|
S9xMessage (S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO,
|
|
"ROM lied about its type! Trying again.");
|
|
Settings.ForceNotInterleaved = TRUE;
|
|
Settings.ForceInterleaved = FALSE;
|
|
retry_count++;
|
|
goto again;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ExtendedFormat==SMALLFIRST)
|
|
Tales=true;
|
|
|
|
FreeSDD1Data ();
|
|
InitROM (Tales);
|
|
|
|
#ifndef NGC
|
|
S9xLoadCheatFile (S9xGetFilename(".cht", PATCH_DIR));
|
|
S9xInitCheatData ();
|
|
S9xApplyCheats ();
|
|
#endif
|
|
|
|
S9xReset ();
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
uint32 CMemory::FileLoader (uint8* buffer, const char* filename, int32 maxsize)
|
|
{
|
|
|
|
|
|
#ifndef NGC
|
|
STREAM ROMFile;
|
|
int len = 0;
|
|
int nFormat=FILE_DEFAULT;
|
|
#endif
|
|
|
|
int32 TotalFileSize = 0;
|
|
char dir [_MAX_DIR + 1];
|
|
char drive [_MAX_DRIVE + 1];
|
|
char name [_MAX_FNAME + 1];
|
|
char ext [_MAX_EXT + 1];
|
|
char fname [_MAX_PATH + 1];
|
|
|
|
unsigned long FileSize = 0;
|
|
|
|
#ifdef UNZIP_SUPPORT
|
|
unzFile file=NULL;
|
|
#endif
|
|
|
|
_splitpath (filename, drive, dir, name, ext);
|
|
_makepath (fname, drive, dir, name, ext);
|
|
|
|
#if defined(__WIN32__) || defined(__MACOSX__)
|
|
memmove (&ext [0], &ext[1], 4);
|
|
#endif
|
|
|
|
#ifndef NGC
|
|
if (strcasecmp (ext, "zip") == 0)
|
|
nFormat = FILE_ZIP;
|
|
else if (strcasecmp (ext, "rar") == 0)
|
|
nFormat = FILE_RAR;
|
|
else if (strcasecmp (ext, "jma") == 0)
|
|
nFormat = FILE_JMA;
|
|
else
|
|
nFormat = FILE_DEFAULT;
|
|
|
|
switch( nFormat )
|
|
{
|
|
case FILE_ZIP:
|
|
|
|
#ifdef UNZIP_SUPPORT
|
|
|
|
file = unzOpen(fname);
|
|
|
|
if(file != NULL)
|
|
{
|
|
|
|
// its a valid ZIP, close it and let LoadZIP handle it.
|
|
|
|
unzClose(file);
|
|
|
|
if (!LoadZip (fname, &TotalFileSize, &HeaderCount, ROM))
|
|
return (0);
|
|
|
|
strcpy (ROMFilename, fname);
|
|
|
|
}
|
|
else
|
|
{
|
|
// its a bad zip file. Walk away
|
|
|
|
S9xMessage (S9X_ERROR, S9X_ROM_INFO, "Invalid Zip Archive.");
|
|
return (0);
|
|
}
|
|
#else
|
|
S9xMessage (S9X_ERROR, S9X_ROM_INFO, "This binary was not created with Zip support.");
|
|
return (0);
|
|
#endif
|
|
break;
|
|
|
|
case FILE_JMA:
|
|
{
|
|
#ifdef JMA_SUPPORT
|
|
size_t FileSize = load_jma_file(fname, ROM);
|
|
|
|
if (!FileSize)
|
|
{
|
|
S9xMessage (S9X_ERROR, S9X_ROM_INFO, "Invalid JMA.");
|
|
return (0);
|
|
}
|
|
|
|
TotalFileSize = FileSize;
|
|
HeaderCount = 0;
|
|
|
|
size_t calc_size = (FileSize / 0x2000) * 0x2000;
|
|
|
|
|
|
if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) ||
|
|
Settings.ForceHeader)
|
|
{
|
|
memmove (ROM, ROM + 512, calc_size);
|
|
HeaderCount = 1;
|
|
FileSize -= 512;
|
|
}
|
|
|
|
strcpy (ROMFilename, fname);
|
|
#else
|
|
S9xMessage (S9X_ERROR, S9X_ROM_INFO, "This binary was not created with JMA support.");
|
|
return (0);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case FILE_RAR:
|
|
// non existant rar loading
|
|
S9xMessage (S9X_ERROR, S9X_ROM_INFO, "Rar Archives are not currently supported.");
|
|
return (0);
|
|
break;
|
|
|
|
case FILE_DEFAULT:
|
|
default:
|
|
// any other roms go here
|
|
|
|
if ((ROMFile = OPEN_STREAM (fname, "rb")) == NULL)
|
|
return (0);
|
|
|
|
strcpy (ROMFilename, fname);
|
|
|
|
HeaderCount = 0;
|
|
uint8 *ptr = buffer;
|
|
bool8 more = FALSE;
|
|
|
|
do
|
|
{
|
|
FileSize = READ_STREAM (ptr, maxsize + 0x200 - (ptr - ROM), ROMFile);
|
|
CLOSE_STREAM (ROMFile);
|
|
|
|
int calc_size = (FileSize / 0x2000) * 0x2000;
|
|
|
|
if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) ||
|
|
Settings.ForceHeader)
|
|
{
|
|
memmove (ptr, ptr + 512, calc_size);
|
|
HeaderCount++;
|
|
FileSize -= 512;
|
|
}
|
|
|
|
ptr += FileSize;
|
|
TotalFileSize += FileSize;
|
|
|
|
|
|
// check for multi file roms
|
|
|
|
if (ptr - ROM < maxsize + 0x200 &&
|
|
(isdigit (ext [0]) && ext [1] == 0 && ext [0] < '9'))
|
|
{
|
|
more = TRUE;
|
|
ext [0]++;
|
|
#if defined(__WIN32__) || defined(__MACOSX__)
|
|
memmove (&ext [1], &ext [0], 4);
|
|
ext [0] = '.';
|
|
#endif
|
|
_makepath (fname, drive, dir, name, ext);
|
|
}
|
|
else if (ptr - ROM < maxsize + 0x200 &&
|
|
(((len = strlen (name)) == 7 || len == 8) &&
|
|
strncasecmp (name, "sf", 2) == 0 &&
|
|
isdigit (name [2]) && isdigit (name [3]) && isdigit (name [4]) &&
|
|
isdigit (name [5]) && isalpha (name [len - 1])))
|
|
{
|
|
more = TRUE;
|
|
name [len - 1]++;
|
|
#if defined(__WIN32__) || defined(__MACOSX__)
|
|
memmove (&ext [1], &ext [0], 4);
|
|
ext [0] = '.';
|
|
#endif
|
|
_makepath (fname, drive, dir, name, ext);
|
|
}
|
|
else
|
|
more = FALSE;
|
|
|
|
} while (more && (ROMFile = OPEN_STREAM (fname, "rb")) != NULL);
|
|
|
|
break;
|
|
}
|
|
|
|
#else
|
|
|
|
/*** Nintendo Gamecube ARAM ROM File Loader
|
|
This is simply a modified version of FILE_DEFAULT, which uses
|
|
the ARAM as temporary ROM storage.
|
|
|
|
NB: Make sure ARAM_ROMSIZE is correct! All hell ensues if you don't
|
|
***/
|
|
HeaderCount = 0;
|
|
uint8 *ptr = buffer;
|
|
|
|
unsigned long ARAM_max = maxsize + 0x200 - (ptr - ROM);
|
|
FileSize = ARAM_ROMSIZE;
|
|
|
|
if ( FileSize > ARAM_max )
|
|
FileSize = ARAM_max;
|
|
|
|
if ( hasloaded == 0 )
|
|
ARAMFetchSlow( (char *)ptr, (char *)AR_SNESROM, FileSize );
|
|
|
|
int calc_size = (FileSize / 0x2000) * 0x2000;
|
|
|
|
if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) ||
|
|
Settings.ForceHeader)
|
|
{
|
|
memmove (ptr, ptr + 512, calc_size);
|
|
HeaderCount++;
|
|
FileSize -= 512;
|
|
}
|
|
|
|
ptr += FileSize;
|
|
TotalFileSize += FileSize;
|
|
|
|
#endif
|
|
|
|
if (HeaderCount == 0)
|
|
S9xMessage (S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found.");
|
|
else
|
|
{
|
|
if (HeaderCount == 1)
|
|
S9xMessage (S9X_INFO, S9X_HEADERS_INFO,
|
|
"Found ROM file header (and ignored it).");
|
|
else
|
|
S9xMessage (S9X_INFO, S9X_HEADERS_INFO,
|
|
"Found multiple ROM file headers (and ignored them).");
|
|
}
|
|
|
|
|
|
return TotalFileSize;
|
|
|
|
}
|
|
|
|
#if 0
|
|
/**********************************************************************************************/
|
|
/* LoadMulti() */
|
|
/* This function loads a Slotted SNES-Backup image and fills the slot. */
|
|
/**********************************************************************************************/
|
|
|
|
bool8 CMemory::LoadMulti (const char *basename, const char *slot1name, const char *slot2name)
|
|
{
|
|
unsigned long FileSize = 0;
|
|
|
|
if(*basename=='\0')
|
|
return FALSE;
|
|
|
|
SufamiTurbo=TRUE;
|
|
|
|
int32 offset;
|
|
|
|
memset (&SNESGameFixes, 0, sizeof(SNESGameFixes));
|
|
SNESGameFixes.SRAMInitialValue = 0x60;
|
|
|
|
CalculatedSize = 0;
|
|
|
|
Settings.DisplayColor=0xffff;
|
|
SET_UI_COLOR(255,255,255);
|
|
|
|
int32 TotalFileSize = FileLoader(ROM, basename, MAX_ROM_SIZE);
|
|
|
|
if(0== TotalFileSize) return FALSE;
|
|
|
|
#ifndef NGC
|
|
CheckForIPSPatch (basename, HeaderCount != 0, TotalFileSize);
|
|
#endif
|
|
|
|
CalculatedSize=TotalFileSize;
|
|
|
|
for(offset=0; offset<TotalFileSize; offset+=0x100000);
|
|
|
|
//insert base type test here.
|
|
|
|
if(slot1name[0]!='\0')
|
|
{
|
|
|
|
TotalFileSize = FileLoader(ROM+offset, slot1name, MAX_ROM_SIZE);
|
|
|
|
if(0== TotalFileSize) return FALSE;
|
|
#ifndef NGC
|
|
CheckForIPSPatch (slot1name, HeaderCount != 0, TotalFileSize);
|
|
#endif
|
|
ROMOffset1=&ROM[offset];
|
|
Slot1Size=TotalFileSize;
|
|
}
|
|
int32 temp=offset;
|
|
for(; offset<temp+TotalFileSize; offset+=0x100000);
|
|
|
|
if(slot2name[0]!='\0')
|
|
{
|
|
TotalFileSize = FileLoader(ROM+offset, slot2name, MAX_ROM_SIZE);
|
|
|
|
if(0== TotalFileSize) return FALSE;
|
|
#ifndef NGC
|
|
CheckForIPSPatch (slot2name, HeaderCount != 0, TotalFileSize);
|
|
#endif
|
|
ROMOffset2=&ROM[offset];
|
|
Slot2Size=TotalFileSize;
|
|
}
|
|
|
|
InitROM (FALSE);
|
|
|
|
#ifndef NGC
|
|
S9xLoadCheatFile (S9xGetFilename(".cht", PATCH_DIR));
|
|
S9xInitCheatData ();
|
|
S9xApplyCheats ();
|
|
#endif
|
|
|
|
S9xReset ();
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
bool8 SufamiTurboBIOSSig(uint8* file, int32 size)
|
|
{
|
|
if(!strcmp((char*)file, "BANDAI SFC-ADX")&&!strcmp((char*)(file+0x10), "SFC-ADX BACKUP"))
|
|
{
|
|
//possible match.
|
|
//check size
|
|
if(size!=0x40000)
|
|
return FALSE;
|
|
//and CRC32
|
|
if(0x9B4CA911==caCRC32(file, size))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool8 SufamiTurboCartSig(uint8* file, int32 size)
|
|
{
|
|
//test not a BIOS
|
|
if(!strcmp((char*)file, "BANDAI SFC-ADX")&&strcmp((char*)(file+0x10), "SFC-ADX BACKUP"))
|
|
{
|
|
//possible match.
|
|
//check size
|
|
if(size>0x100000||size <0x80000)
|
|
return FALSE;
|
|
//probably a minicart
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool8 SameGameSig(uint8* file, int32 size)
|
|
{
|
|
//preheader sig
|
|
if(strcmp((char*)(file+0xFFA0),"1995/12/16 10:2018ZS5J"))
|
|
return FALSE;
|
|
if(size!=0x100000)
|
|
return FALSE;
|
|
if(0x133E1C5B==caCRC32(file, size))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
bool8 GNextSig(uint8* file, int32 size)
|
|
{
|
|
//preheader sig
|
|
if(strcmp((char*)(file+0xFFAA),"GNEXT B2ZX3J"))
|
|
return FALSE;
|
|
if(size!=0x180000)
|
|
return FALSE;
|
|
if(0x845E420D==caCRC32(file, size))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
int MultiType(uint8* file, int32 size)
|
|
{
|
|
//check for ST signiture
|
|
if(SufamiTurboBIOSSig(file, size))
|
|
return 1;
|
|
//check for Same Game signiture
|
|
if(SameGameSig(file, size))
|
|
return 2;
|
|
//check for G-Next signiture
|
|
if(GNextSig(file, size))
|
|
return 3;
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
//compatibility wrapper
|
|
void S9xDeinterleaveMode2 ()
|
|
{
|
|
S9xDeinterleaveType2();
|
|
}
|
|
|
|
void S9xDeinterleaveType2 (bool8 reset)
|
|
{
|
|
if(Settings.DisplayColor==0xffff||Settings.DisplayColor==BUILD_PIXEL(0,31,0))
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(31,14,6);
|
|
SET_UI_COLOR(255,119,25);
|
|
|
|
}
|
|
S9xMessage (S9X_INFO, S9X_ROM_INTERLEAVED_INFO,
|
|
"ROM image is in interleaved format - converting...");
|
|
|
|
int nblocks = Memory.CalculatedSize >> 16;
|
|
int step = 64;
|
|
|
|
while (nblocks <= step)
|
|
step >>= 1;
|
|
|
|
nblocks = step;
|
|
uint8 blocks [256];
|
|
int i;
|
|
|
|
for (i = 0; i < nblocks * 2; i++)
|
|
{
|
|
blocks [i] = (i & ~0xF) | ((i & 3) << 2) |
|
|
((i & 12) >> 2);
|
|
}
|
|
|
|
uint8 *tmp = (uint8 *) malloc (0x10000);
|
|
|
|
if (tmp)
|
|
{
|
|
for (i = 0; i < nblocks * 2; i++)
|
|
{
|
|
for (int j = i; j < nblocks * 2; j++)
|
|
{
|
|
if (blocks [j] == i)
|
|
{
|
|
memmove (tmp, &Memory.ROM [blocks [j] * 0x10000], 0x10000);
|
|
memmove (&Memory.ROM [blocks [j] * 0x10000],
|
|
&Memory.ROM [blocks [i] * 0x10000], 0x10000);
|
|
memmove (&Memory.ROM [blocks [i] * 0x10000], tmp, 0x10000);
|
|
uint8 b = blocks [j];
|
|
blocks [j] = blocks [i];
|
|
blocks [i] = b;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
free ((char *) tmp);
|
|
tmp=NULL;
|
|
}
|
|
if(reset)
|
|
{
|
|
Memory.InitROM (FALSE);
|
|
S9xReset ();
|
|
}
|
|
}
|
|
|
|
//CRC32 for char arrays
|
|
inline uint32 caCRC32(uint8 *array, uint32 size, register uint32 crc32)
|
|
{
|
|
for (register uint32 i = 0; i < size; i++)
|
|
{
|
|
crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ array[i]) & 0xFF];
|
|
}
|
|
return ~crc32;
|
|
}
|
|
|
|
void CMemory::InitROM (bool8 Interleaved)
|
|
{
|
|
#ifndef ZSNES_FX
|
|
SuperFX.nRomBanks = CalculatedSize >> 15;
|
|
#endif
|
|
Settings.DSP1Master = Settings.ForceDSP1;
|
|
Settings.SuperFX = FALSE;
|
|
Settings.SA1 = FALSE;
|
|
Settings.C4 = FALSE;
|
|
Settings.SDD1 = FALSE;
|
|
Settings.SRTC = FALSE;
|
|
Settings.SPC7110=FALSE;
|
|
Settings.SPC7110RTC=FALSE;
|
|
Settings.BS=FALSE;
|
|
Settings.OBC1=FALSE;
|
|
Settings.SETA=FALSE;
|
|
s7r.DataRomSize = 0;
|
|
CalculatedChecksum=0;
|
|
|
|
uint8* RomHeader;
|
|
|
|
RomHeader=ROM+0x7FB0;
|
|
|
|
if(ExtendedFormat==BIGFIRST)
|
|
RomHeader+=0x400000;
|
|
|
|
if(HiROM)
|
|
RomHeader+=0x8000;
|
|
|
|
for (int i = 0; i < MEMMAP_NUM_BLOCKS; i++)
|
|
{
|
|
Map [MEMMAP_NUM_BLOCKS] = (uint8 *) MAP_NONE;
|
|
BlockIsRAM [MEMMAP_NUM_BLOCKS] = FALSE;
|
|
BlockIsROM [MEMMAP_NUM_BLOCKS] = FALSE;
|
|
}
|
|
|
|
S9xInitBSX();
|
|
|
|
::SRAM = SRAM;
|
|
memset (ROMId, 0, 5);
|
|
memset (CompanyId, 0, 3);
|
|
|
|
ParseSNESHeader(RomHeader);
|
|
|
|
// Try to auto-detect the DSP1 chip
|
|
if (!Settings.ForceNoDSP1 &&
|
|
(ROMType & 0xf) >= 3 && (ROMType & 0xf0) == 0)
|
|
Settings.DSP1Master = TRUE;
|
|
|
|
if (Memory.HiROM)
|
|
{
|
|
// Enable S-RTC (Real Time Clock) emulation for Dai Kaijyu Monogatari 2
|
|
Settings.SRTC = ((ROMType & 0xf0) >> 4) == 5;
|
|
|
|
if(((ROMSpeed&0x0F)==0x0A)&&((ROMType&0xF0)==0xF0))
|
|
{
|
|
Settings.SPC7110=true;
|
|
if((ROMType&0x0F)==0x09)
|
|
Settings.SPC7110RTC=true;
|
|
}
|
|
|
|
if (Settings.BS)
|
|
/* Do nothing */;
|
|
else if(Settings.SPC7110)
|
|
{
|
|
SPC7110HiROMMap();
|
|
}
|
|
else if ((ROMSpeed & ~0x10) == 0x25)
|
|
{
|
|
TalesROMMap (Interleaved);
|
|
}
|
|
else HiROMMap ();
|
|
}
|
|
else
|
|
{
|
|
Settings.SuperFX = Settings.ForceSuperFX;
|
|
|
|
if(ROMType==0x25)
|
|
{
|
|
Settings.OBC1=TRUE;
|
|
}
|
|
|
|
if ((ROMType & 0xf0) == 0x10)
|
|
Settings.SuperFX = !Settings.ForceNoSuperFX;
|
|
|
|
Settings.SDD1 = Settings.ForceSDD1;
|
|
if ((ROMType & 0xf0) == 0x40)
|
|
Settings.SDD1 = !Settings.ForceNoSDD1;
|
|
|
|
if (Settings.SDD1)
|
|
S9xLoadSDD1Data ();
|
|
|
|
if(((ROMType &0xF0) == 0xF0)&((ROMSpeed&0x0F)!=5))
|
|
{
|
|
SRAMSize=2;
|
|
SNESGameFixes.SRAMInitialValue = 0x00;
|
|
if((ROMType &0x0F)==6)
|
|
{
|
|
if(ROM[0x7FD7]==0x09)
|
|
{
|
|
Settings.SETA=ST_011;
|
|
SetSETA=&S9xSetST011;
|
|
GetSETA=&S9xGetST011;
|
|
}
|
|
else
|
|
{
|
|
Settings.SETA=ST_010;
|
|
SetSETA=&S9xSetST010;
|
|
GetSETA=&S9xGetST010;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Settings.SETA=ST_018;
|
|
SRAMSize=2;
|
|
}
|
|
}
|
|
|
|
Settings.C4 = Settings.ForceC4;
|
|
if ((ROMType & 0xf0) == 0xf0 &&
|
|
(strncmp (ROMName, "MEGAMAN X", 9) == 0 ||
|
|
strncmp (ROMName, "ROCKMAN X", 9) == 0))
|
|
{
|
|
Settings.C4 = !Settings.ForceNoC4;
|
|
}
|
|
|
|
if(Settings.SETA&&Settings.SETA!=ST_018)
|
|
{
|
|
SetaDSPMap();
|
|
}
|
|
else if (Settings.SuperFX)
|
|
{
|
|
//::SRAM = ROM + 1024 * 1024 * 4;
|
|
SuperFXROMMap ();
|
|
Settings.MultiPlayer5Master = FALSE;
|
|
//Settings.MouseMaster = FALSE;
|
|
//Settings.SuperScopeMaster = FALSE;
|
|
Settings.DSP1Master = FALSE;
|
|
Settings.SA1 = FALSE;
|
|
Settings.C4 = FALSE;
|
|
Settings.SDD1 = FALSE;
|
|
}
|
|
else if (Settings.ForceSA1 ||
|
|
(!Settings.ForceNoSA1 && (ROMSpeed & ~0x10) == 0x23 &&
|
|
(ROMType & 0xf) > 3 && (ROMType & 0xf0) == 0x30))
|
|
{
|
|
Settings.SA1 = TRUE;
|
|
// Settings.MultiPlayer5Master = FALSE;
|
|
//Settings.MouseMaster = FALSE;
|
|
//Settings.SuperScopeMaster = FALSE;
|
|
Settings.DSP1Master = FALSE;
|
|
Settings.C4 = FALSE;
|
|
Settings.SDD1 = FALSE;
|
|
SA1ROMMap ();
|
|
}
|
|
else if ((ROMSpeed & ~0x10) == 0x25)
|
|
TalesROMMap (Interleaved);
|
|
else if(ExtendedFormat!=NOPE)
|
|
JumboLoROMMap(Interleaved);
|
|
else if (strncmp ((char *) &Memory.ROM [0x7fc0], "SOUND NOVEL-TCOOL", 17) == 0 ||
|
|
strncmp ((char *) &Memory.ROM [0x7fc0], "DERBY STALLION 96", 17) == 0)
|
|
{
|
|
LoROM24MBSMap ();
|
|
Settings.DSP1Master = FALSE;
|
|
}
|
|
|
|
else if (strncmp ((char *) &Memory.ROM [0x7fc0], "THOROUGHBRED BREEDER3", 21) == 0 ||
|
|
strncmp ((char *) &Memory.ROM [0x7fc0], "RPG-TCOOL 2", 11) == 0)
|
|
{
|
|
SRAM512KLoROMMap ();
|
|
Settings.DSP1Master = FALSE;
|
|
}
|
|
else if (strncmp ((char *) &Memory.ROM [0x7fc0], "ADD-ON BASE CASSETE", 19) == 0)
|
|
{
|
|
Settings.MultiPlayer5Master = FALSE;
|
|
Settings.MouseMaster = FALSE;
|
|
Settings.SuperScopeMaster = FALSE;
|
|
Settings.DSP1Master = FALSE;
|
|
SufamiTurboLoROMMap();
|
|
Memory.SRAMSize = 3;
|
|
}
|
|
else if ((ROMSpeed & ~0x10) == 0x22 &&
|
|
strncmp (ROMName, "Super Street Fighter", 20) != 0)
|
|
{
|
|
AlphaROMMap ();
|
|
}
|
|
else if (Settings.BS)
|
|
/* Do nothing */;
|
|
else LoROMMap ();
|
|
}
|
|
|
|
uint32 sum1 = 0;
|
|
uint32 sum2 = 0;
|
|
if(0==CalculatedChecksum)
|
|
{
|
|
int power2 = 0;
|
|
int size = CalculatedSize;
|
|
|
|
while (size >>= 1)
|
|
power2++;
|
|
|
|
size = 1 << power2;
|
|
uint32 remainder = CalculatedSize - size;
|
|
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < size; i++)
|
|
sum1 += ROM [i];
|
|
|
|
for (i = 0; i < (int) remainder; i++)
|
|
sum2 += ROM [size + i];
|
|
|
|
int sub = 0;
|
|
if (Settings.BS && !Settings.BSXItself)
|
|
{
|
|
if (Memory.HiROM)
|
|
{
|
|
for (i = 0; i < 48; i++)
|
|
sub += ROM[0xffb0 + i];
|
|
}
|
|
else if (Memory.LoROM)
|
|
{
|
|
for (i = 0; i < 48; i++)
|
|
sub += ROM[0x7fb0 + i];
|
|
}
|
|
sum1 -= sub;
|
|
}
|
|
|
|
|
|
if (remainder)
|
|
{
|
|
sum1 += sum2 * (size / remainder);
|
|
}
|
|
|
|
|
|
sum1 &= 0xffff;
|
|
Memory.CalculatedChecksum=sum1;
|
|
}
|
|
//now take a CRC32
|
|
ROMCRC32 = caCRC32(ROM, CalculatedSize);
|
|
|
|
if (Settings.ForceNTSC)
|
|
Settings.PAL = FALSE;
|
|
else if (Settings.ForcePAL)
|
|
Settings.PAL = TRUE;
|
|
else
|
|
{
|
|
//Korea refers to South Korea, which uses NTSC
|
|
switch(ROMRegion)
|
|
{
|
|
case 13:
|
|
case 1:
|
|
case 0:
|
|
Settings.PAL=FALSE;
|
|
break;
|
|
default: Settings.PAL=TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Timings.H_Max_Master = SNES_CYCLES_PER_SCANLINE;
|
|
Timings.H_Max = Timings.H_Max_Master;
|
|
Timings.HBlankStart = SNES_HBLANK_START_HC;
|
|
Timings.HBlankEnd = SNES_HBLANK_END_HC;
|
|
Timings.HDMAInit = SNES_HDMA_INIT_HC;
|
|
Timings.HDMAStart = SNES_HDMA_START_HC;
|
|
Timings.RenderPos = SNES_RENDER_START_HC;
|
|
Timings.V_Max_Master = Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER;
|
|
Timings.V_Max = Timings.V_Max_Master;
|
|
|
|
if (Settings.PAL)
|
|
{
|
|
Settings.FrameTime = Settings.FrameTimePAL;
|
|
Memory.ROMFramesPerSecond = 50;
|
|
}
|
|
else
|
|
{
|
|
Settings.FrameTime = Settings.FrameTimeNTSC;
|
|
Memory.ROMFramesPerSecond = 60;
|
|
}
|
|
|
|
ROMName[ROM_NAME_LEN - 1] = 0;
|
|
if (strlen (ROMName))
|
|
{
|
|
char *p = ROMName + strlen (ROMName);
|
|
if(p>ROMName+21 && ROMName[20]==' ') p=ROMName+21;
|
|
|
|
while (p > ROMName && *(p - 1) == ' ')
|
|
p--;
|
|
*p = 0;
|
|
}
|
|
|
|
{
|
|
SRAMMask = Memory.SRAMSize ?
|
|
((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0;
|
|
}
|
|
if((ROMChecksum + ROMComplementChecksum != 0xffff) || ROMChecksum != CalculatedChecksum || ((uint32)CalculatedSize > (uint32)(((1<<(ROMSize-7))*128)*1024)))
|
|
{
|
|
if(Settings.DisplayColor==0xffff || Settings.DisplayColor!=BUILD_PIXEL(31,0,0))
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(31,31,0);
|
|
SET_UI_COLOR(255,255,0);
|
|
}
|
|
}
|
|
|
|
IAPU.OneCycle = ONE_APU_CYCLE;
|
|
Settings.Shutdown = Settings.ShutdownMaster;
|
|
|
|
SetDSP=&DSP1SetByte;
|
|
GetDSP=&DSP1GetByte;
|
|
|
|
CPU.FastROMSpeed = 0;
|
|
ResetSpeedMap();
|
|
ApplyROMFixes ();
|
|
|
|
char displayName[ROM_NAME_LEN];
|
|
strcpy (RawROMName, ROMName);
|
|
sprintf (displayName, "%s", SafeANK (ROMName));
|
|
sprintf (ROMName, "%s", Safe (ROMName));
|
|
sprintf (ROMId, "%s", Safe (ROMId));
|
|
sprintf (CompanyId, "%s", Safe (CompanyId));
|
|
|
|
sprintf (String, "\"%s\" [%s] %s, %s, Type: %s, Mode: %s, TV: %s, S-RAM: %s, ROMId: %s Company: %2.2s CRC32: %08X",
|
|
displayName,
|
|
(ROMChecksum + ROMComplementChecksum != 0xffff ||
|
|
ROMChecksum != CalculatedChecksum) ? "bad checksum" : "checksum ok",
|
|
MapType (),
|
|
Size (),
|
|
KartContents (),
|
|
MapMode (),
|
|
TVStandard (),
|
|
StaticRAMSize (),
|
|
ROMId,
|
|
CompanyId,
|
|
ROMCRC32);
|
|
|
|
S9xMessage (S9X_INFO, S9X_ROM_INFO, String);
|
|
#ifdef __WIN32__
|
|
#ifndef _XBOX
|
|
EnableMenuItem(GUI.hMenu, IDM_ROM_INFO, MF_ENABLED);
|
|
#endif
|
|
#ifdef RTC_DEBUGGER
|
|
if(Settings.SPC7110RTC)
|
|
EnableMenuItem(GUI.hMenu, IDM_7110_RTC, MF_ENABLED);
|
|
else EnableMenuItem(GUI.hMenu, IDM_7110_RTC, MF_GRAYED);
|
|
#endif
|
|
#endif
|
|
Settings.ForceHeader = Settings.ForceHiROM = Settings.ForceLoROM =
|
|
Settings.ForceInterleaved = Settings.ForceNoHeader = Settings.ForceNotInterleaved =
|
|
Settings.ForceInterleaved2=false;
|
|
|
|
S9xVerifyControllers();
|
|
}
|
|
|
|
bool8 CMemory::LoadSRAM (const char *filename)
|
|
{
|
|
int size = Memory.SRAMSize ?
|
|
(1 << (Memory.SRAMSize + 3)) * 128 : 0;
|
|
|
|
memset (SRAM, SNESGameFixes.SRAMInitialValue, 0x20000);
|
|
|
|
if (size > 0x20000)
|
|
size = 0x20000;
|
|
#ifndef NGC
|
|
if (size)
|
|
{
|
|
FILE *file;
|
|
if ((file = fopen (filename, "rb")))
|
|
{
|
|
int len = fread ((char*) ::SRAM, 1, 0x20000, file);
|
|
fclose (file);
|
|
if (len - size == 512)
|
|
{
|
|
// S-RAM file has a header - remove it
|
|
memmove (::SRAM, ::SRAM + 512, size);
|
|
}
|
|
if (len == size + SRTC_SRAM_PAD)
|
|
{
|
|
S9xSRTCPostLoadState ();
|
|
S9xResetSRTC ();
|
|
rtc.index = -1;
|
|
rtc.mode = MODE_READ;
|
|
}
|
|
else
|
|
S9xHardResetSRTC ();
|
|
|
|
if(Settings.SPC7110RTC)
|
|
{
|
|
S9xLoadSPC7110RTC (&rtc_f9);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
else
|
|
if (Settings.BS && !Settings.BSXItself)
|
|
{
|
|
// The BS game's SRAM was not found
|
|
// Try to read BS-X.srm instead
|
|
|
|
char path[_MAX_PATH + 1];
|
|
|
|
strcpy(path, S9xGetDirectory(SRAM_DIR));
|
|
strcat(path, SLASH_STR);
|
|
strcat(path, "BS-X.srm");
|
|
|
|
if ((file = fopen(path, "rb")))
|
|
{
|
|
fread((char *) ::SRAM, 1, 0x20000, file);
|
|
fclose (file);
|
|
S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found: BS-X.srm was read instead.");
|
|
S9xHardResetSRTC();
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found, BS-X.srm wasn't found either.");
|
|
S9xHardResetSRTC();
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
S9xHardResetSRTC ();
|
|
return (FALSE);
|
|
}
|
|
if (Settings.SDD1)
|
|
S9xSDD1LoadLoggedData ();
|
|
|
|
#endif
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
bool8 CMemory::SaveSRAM (const char *filename)
|
|
{
|
|
if(Settings.SuperFX && Memory.ROMType < 0x15)
|
|
return TRUE;
|
|
if(Settings.SA1 && Memory.ROMType == 0x34)
|
|
return TRUE;
|
|
|
|
int size = Memory.SRAMSize ?
|
|
(1 << (Memory.SRAMSize + 3)) * 128 : 0;
|
|
if (Settings.SRTC)
|
|
{
|
|
size += SRTC_SRAM_PAD;
|
|
S9xSRTCPreSaveState ();
|
|
}
|
|
|
|
if (Settings.SDD1)
|
|
S9xSDD1SaveLoggedData ();
|
|
|
|
if (size > 0x20000)
|
|
size = 0x20000;
|
|
|
|
if (size && *Memory.ROMFilename)
|
|
{
|
|
FILE *file;
|
|
if ((file = fopen (filename, "wb")))
|
|
{
|
|
fwrite ((char *) ::SRAM, size, 1, file);
|
|
fclose (file);
|
|
#if defined(__linux)
|
|
chown (filename, getuid (), getgid ());
|
|
#endif
|
|
if(Settings.SPC7110RTC)
|
|
{
|
|
S9xSaveSPC7110RTC (&rtc_f9);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
void CMemory::FixROMSpeed ()
|
|
{
|
|
int c;
|
|
|
|
if(CPU.FastROMSpeed==0)
|
|
CPU.FastROMSpeed=SLOW_ONE_CYCLE;
|
|
|
|
|
|
for (c = 0x800; c < 0x1000; c++)
|
|
{
|
|
if (c&0x8 || c&0x400)
|
|
MemorySpeed [c] = (uint8) CPU.FastROMSpeed;
|
|
}
|
|
}
|
|
|
|
|
|
void CMemory::ResetSpeedMap()
|
|
{
|
|
int i;
|
|
memset(MemorySpeed, SLOW_ONE_CYCLE, 0x1000);
|
|
for(i=0;i<0x400;i+=0x10)
|
|
{
|
|
MemorySpeed[i+2]=MemorySpeed[0x800+i+2]= ONE_CYCLE;
|
|
MemorySpeed[i+3]=MemorySpeed[0x800+i+3]= ONE_CYCLE;
|
|
MemorySpeed[i+4]=MemorySpeed[0x800+i+4]= ONE_CYCLE;
|
|
MemorySpeed[i+5]=MemorySpeed[0x800+i+5]= ONE_CYCLE;
|
|
}
|
|
CMemory::FixROMSpeed ();
|
|
}
|
|
|
|
void CMemory::WriteProtectROM ()
|
|
{
|
|
memmove ((void *) WriteMap, (void *) Map, sizeof (Map));
|
|
for (int c = 0; c < 0x1000; c++)
|
|
{
|
|
if (BlockIsROM [c])
|
|
WriteMap [c] = (uint8 *) MAP_NONE;
|
|
}
|
|
}
|
|
|
|
void CMemory::MapRAM ()
|
|
{
|
|
int c;
|
|
|
|
if(Memory.LoROM&&!Settings.SDD1)
|
|
{
|
|
// Banks 70->77, S-RAM
|
|
for (c = 0; c < 0x0f; c++)
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
Map [(c<<4) + 0xF00+i]=Map [(c<<4) + 0x700+i] = (uint8 *) MAP_LOROM_SRAM;
|
|
BlockIsRAM [(c<<4) + 0xF00+i] =BlockIsRAM [(c<<4) + 0x700+i] = TRUE;
|
|
BlockIsROM [(c<<4) + 0xF00+i] =BlockIsROM [(c<<4) + 0x700+i] = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else if(Memory.LoROM&&Settings.SDD1)
|
|
{
|
|
// Banks 70->77, S-RAM
|
|
for (c = 0; c < 0x0f; c++)
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
Map [(c<<4) + 0x700+i] = (uint8 *) MAP_LOROM_SRAM;
|
|
BlockIsRAM [(c<<4) + 0x700+i] = TRUE;
|
|
BlockIsROM [(c<<4) + 0x700+i] = FALSE;
|
|
}
|
|
}
|
|
}
|
|
// Banks 7e->7f, RAM
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [c + 0x7e0] = RAM;
|
|
Map [c + 0x7f0] = RAM + 0x10000;
|
|
BlockIsRAM [c + 0x7e0] = TRUE;
|
|
BlockIsRAM [c + 0x7f0] = TRUE;
|
|
BlockIsROM [c + 0x7e0] = FALSE;
|
|
BlockIsROM [c + 0x7f0] = FALSE;
|
|
}
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::MapExtraRAM ()
|
|
{
|
|
int c;
|
|
|
|
// Banks 7e->7f, RAM
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [c + 0x7e0] = RAM;
|
|
Map [c + 0x7f0] = RAM + 0x10000;
|
|
BlockIsRAM [c + 0x7e0] = TRUE;
|
|
BlockIsRAM [c + 0x7f0] = TRUE;
|
|
BlockIsROM [c + 0x7e0] = FALSE;
|
|
BlockIsROM [c + 0x7f0] = FALSE;
|
|
}
|
|
|
|
// Banks 70->73, S-RAM
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [c + 0x700] = ::SRAM;
|
|
Map [c + 0x710] = ::SRAM + 0x8000;
|
|
Map [c + 0x720] = ::SRAM + 0x10000;
|
|
Map [c + 0x730] = ::SRAM + 0x18000;
|
|
|
|
BlockIsRAM [c + 0x700] = TRUE;
|
|
BlockIsROM [c + 0x700] = FALSE;
|
|
BlockIsRAM [c + 0x710] = TRUE;
|
|
BlockIsROM [c + 0x710] = FALSE;
|
|
BlockIsRAM [c + 0x720] = TRUE;
|
|
BlockIsROM [c + 0x720] = FALSE;
|
|
BlockIsRAM [c + 0x730] = TRUE;
|
|
BlockIsROM [c + 0x730] = FALSE;
|
|
}
|
|
}
|
|
|
|
void CMemory::LoROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
int j;
|
|
int mask[4];
|
|
for (j=0; j<4; j++)
|
|
mask[j]=0x00ff;
|
|
|
|
mask[0]=(CalculatedSize/0x8000)-1;
|
|
|
|
int x;
|
|
bool foundZeros;
|
|
bool pastZeros;
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
x=1;
|
|
foundZeros=false;
|
|
pastZeros=false;
|
|
|
|
mask[j+1]=mask[j];
|
|
|
|
while (x>0x100&&!pastZeros)
|
|
{
|
|
if(mask[j]&x)
|
|
{
|
|
x<<=1;
|
|
if(foundZeros)
|
|
pastZeros=true;
|
|
}
|
|
else
|
|
{
|
|
foundZeros=true;
|
|
pastZeros=false;
|
|
mask[j+1]|=x;
|
|
x<<=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
if(Settings.SETA==ST_018)
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_SETA_RISC;
|
|
else Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
if (Settings.DSP1Master)
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP;
|
|
}
|
|
else if (Settings.C4)
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_C4;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_C4;
|
|
}
|
|
else if(Settings.OBC1)
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_OBC_RAM;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_OBC_RAM;
|
|
}
|
|
else
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
}
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
int e=3;
|
|
int d=c>>4;
|
|
while(d>mask[0])
|
|
{
|
|
d&=mask[e];
|
|
e--;
|
|
}
|
|
Map [i] = Map [i + 0x800] = ROM + (((d)-1)*0x8000);
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Settings.DSP1Master)
|
|
{
|
|
// Banks 30->3f and b0->bf
|
|
for (c = 0x300; c < 0x400; c += 16)
|
|
{
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = (uint8 *) MAP_DSP;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 8; i++)
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) % CalculatedSize];
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
int e=3;
|
|
int d=(c+0x400)>>4;
|
|
while(d>mask[0])
|
|
{
|
|
d&=mask[e];
|
|
e--;
|
|
}
|
|
|
|
Map [i + 0x400] = Map [i + 0xc00] = ROM + (((d)-1)*0x8000);
|
|
}
|
|
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Settings.DSP1Master)
|
|
{
|
|
for (c = 0; c < 0x100; c++)
|
|
{
|
|
Map [c + 0xe00] = (uint8 *) MAP_DSP;
|
|
BlockIsROM [c + 0xe00] = FALSE;
|
|
}
|
|
}
|
|
|
|
int sum=0, k,l, bankcount;
|
|
bankcount=1<<(ROMSize-7);//Mbits
|
|
|
|
//safety for corrupt headers
|
|
if(bankcount > 128)
|
|
bankcount = (CalculatedSize/0x8000)/4;
|
|
bankcount*=4;//to banks
|
|
bankcount<<=4;//Map banks
|
|
bankcount+=0x800;//normalize
|
|
for(k=0x800;k<(bankcount);k+=16)
|
|
{
|
|
uint8* bank=0x8000+Map[k+8];
|
|
for(l=0;l<0x8000;l++)
|
|
sum+=bank[l];
|
|
}
|
|
CalculatedChecksum=sum&0xFFFF;
|
|
|
|
MapRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::SetaDSPMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
int j;
|
|
int mask[4];
|
|
for (j=0; j<4; j++)
|
|
mask[j]=0x00ff;
|
|
|
|
mask[0]=(CalculatedSize/0x8000)-1;
|
|
|
|
int x;
|
|
bool foundZeros;
|
|
bool pastZeros;
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
x=1;
|
|
foundZeros=false;
|
|
pastZeros=false;
|
|
|
|
mask[j+1]=mask[j];
|
|
|
|
while (x>0x100&&!pastZeros)
|
|
{
|
|
if(mask[j]&x)
|
|
{
|
|
x<<=1;
|
|
if(foundZeros)
|
|
pastZeros=true;
|
|
}
|
|
else
|
|
{
|
|
foundZeros=true;
|
|
pastZeros=false;
|
|
mask[j+1]|=x;
|
|
x<<=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
int e=3;
|
|
int d=c>>4;
|
|
while(d>mask[0])
|
|
{
|
|
d&=mask[e];
|
|
e--;
|
|
}
|
|
Map [i] = Map [i + 0x800] = ROM + (((d)-1)*0x8000);
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
int e=3;
|
|
int d=(c+0x400)>>4;
|
|
while(d>mask[0])
|
|
{
|
|
d&=mask[e];
|
|
e--;
|
|
}
|
|
|
|
Map [i + 0x400] = Map [i + 0xc00] = ROM + (((d)-1)*0x8000);
|
|
}
|
|
|
|
//only upper half is ROM
|
|
for (i = c+8; i < c + 16; i++)
|
|
{
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
memset(SRAM, 0, 0x1000);
|
|
for (c=0x600;c<0x680;c+=0x10)
|
|
{
|
|
for(i=0;i<0x08;i++)
|
|
{
|
|
//where does the SETA chip access, anyway?
|
|
//please confirm this?
|
|
Map[c+0x80+i]=(uint8*)MAP_SETA_DSP;
|
|
BlockIsROM [c+0x80+i] = FALSE;
|
|
BlockIsRAM [c+0x80+i] = TRUE;
|
|
}
|
|
|
|
for(i=0;i<0x04;i++)
|
|
{
|
|
//and this!
|
|
Map[c+i]=(uint8*)MAP_SETA_DSP;
|
|
BlockIsROM [c+i] = FALSE;
|
|
}
|
|
}
|
|
|
|
int sum=0, k,l, bankcount;
|
|
bankcount=1<<(ROMSize-7);//Mbits
|
|
//safety for corrupt headers
|
|
if(bankcount > 128)
|
|
bankcount = (CalculatedSize/0x8000)/4;
|
|
bankcount*=4;//to banks
|
|
bankcount<<=4;//Map banks
|
|
bankcount+=0x800;//normalize
|
|
for(k=0x800;k<(bankcount);k+=16)
|
|
{
|
|
uint8* bank=0x8000+Map[k+8];
|
|
for(l=0;l<0x8000;l++)
|
|
sum+=bank[l];
|
|
}
|
|
CalculatedChecksum=sum&0xFFFF;
|
|
|
|
MapRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::HiROMMap ()
|
|
{
|
|
int i;
|
|
int c;
|
|
int j;
|
|
|
|
int mask[4];
|
|
for (j=0; j<4; j++)
|
|
mask[j]=0x00ff;
|
|
|
|
mask[0]=(CalculatedSize/0x10000)-1;
|
|
|
|
if (Settings.ForceSA1 ||
|
|
(!Settings.ForceNoSA1 && (ROMSpeed & ~0x10) == 0x23 &&
|
|
(ROMType & 0xf) > 3 && (ROMType & 0xf0) == 0x30))
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(31,0,0);
|
|
SET_UI_COLOR(255,0,0);
|
|
}
|
|
|
|
|
|
int x;
|
|
bool foundZeros;
|
|
bool pastZeros;
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
x=1;
|
|
foundZeros=false;
|
|
pastZeros=false;
|
|
|
|
mask[j+1]=mask[j];
|
|
|
|
while (x>0x100&&!pastZeros)
|
|
{
|
|
if(mask[j]&x)
|
|
{
|
|
x<<=1;
|
|
if(foundZeros)
|
|
pastZeros=true;
|
|
}
|
|
else
|
|
{
|
|
foundZeros=true;
|
|
pastZeros=false;
|
|
mask[j+1]|=x;
|
|
x<<=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
|
|
if (Settings.DSP1Master)
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP;
|
|
}
|
|
else
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
}
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
int e=3;
|
|
int d=c>>4;
|
|
while(d>mask[0])
|
|
{
|
|
d&=mask[e];
|
|
e--;
|
|
}
|
|
Map [i] = Map [i + 0x800] = ROM + (d*0x10000);
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM.
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [0x306 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [0x307 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [0xb06 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [0xb07 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
BlockIsRAM [0x306 + (c << 4)] = TRUE;
|
|
BlockIsRAM [0x307 + (c << 4)] = TRUE;
|
|
BlockIsRAM [0xb06 + (c << 4)] = TRUE;
|
|
BlockIsRAM [0xb07 + (c << 4)] = TRUE;
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
int e=3;
|
|
int d=(c)>>4;
|
|
while(d>mask[0])
|
|
{
|
|
d&=mask[e];
|
|
e--;
|
|
}
|
|
Map [i + 0x400] = Map [i + 0xc00] = ROM + (d*0x10000);
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
int bankmax=0x40+ (1<<(ROMSize-6));
|
|
//safety for corrupt headers
|
|
if(bankmax > 128)
|
|
bankmax = 0x80;
|
|
int sum=0;
|
|
for(i=0x40;i<bankmax; i++)
|
|
{
|
|
uint8 * bank_low=(uint8*)Map[i<<4];
|
|
for (c=0;c<0x10000; c++)
|
|
{
|
|
sum+=bank_low[c];
|
|
}
|
|
}
|
|
CalculatedChecksum=sum&0xFFFF;
|
|
|
|
MapRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::TalesROMMap (bool8 Interleaved)
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
if(Interleaved)
|
|
{
|
|
if(Settings.DisplayColor==0xffff)
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(0,31,0);
|
|
SET_UI_COLOR(0,255,0);
|
|
}
|
|
}
|
|
uint32 OFFSET0 = 0x400000;
|
|
uint32 OFFSET1 = 0x400000;
|
|
uint32 OFFSET2 = 0x000000;
|
|
|
|
if (Interleaved)
|
|
{
|
|
OFFSET0 = 0x000000;
|
|
OFFSET1 = 0x000000;
|
|
OFFSET2 = CalculatedSize-0x400000; //changed to work with interleaved DKJM2.
|
|
}
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
|
|
//makes more sense to map the range here.
|
|
//ToP seems to use sram to skip intro???
|
|
if(c>=0x300)
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_HIROM_SRAM;
|
|
BlockIsRAM [6 + c] = BlockIsRAM [7 + c] =
|
|
BlockIsRAM [0x806 + c]= BlockIsRAM [0x807 + c] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
|
|
}
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = &ROM [((c << 12) % (CalculatedSize-0x400000)) + OFFSET0];
|
|
Map [i + 0x800] = &ROM [((c << 12) % 0x400000) + OFFSET2];
|
|
BlockIsROM [i] = TRUE;
|
|
BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 8; i++)
|
|
{
|
|
Map [i + 0x400] = &ROM [((c << 12) % (CalculatedSize-0x400000)) + OFFSET1];
|
|
Map [i + 0x408] = &ROM [((c << 12) % (CalculatedSize-0x400000)) + OFFSET1];
|
|
Map [i + 0xc00] = &ROM [((c << 12) %0x400000)+ OFFSET2];
|
|
Map [i + 0xc08] = &ROM [((c << 12) % 0x400000) + OFFSET2];
|
|
BlockIsROM [i + 0x400] = TRUE;
|
|
BlockIsROM [i + 0x408] = TRUE;
|
|
BlockIsROM [i + 0xc00] = TRUE;
|
|
BlockIsROM [i + 0xc08] = TRUE;
|
|
}
|
|
}
|
|
|
|
if((strncmp("TALES",(char*)Map[8]+0xFFC0, 5)==0))
|
|
{
|
|
if(((*(Map[8]+0xFFDE))==(*(Map[0x808]+0xFFDE))))
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(31,0,0);
|
|
SET_UI_COLOR(255,0,0);
|
|
}
|
|
}
|
|
|
|
ROMChecksum = *(Map[8]+0xFFDE) + (*(Map[8]+0xFFDF) << 8);
|
|
ROMComplementChecksum = *(Map[8]+0xFFDC) + (*(Map[8]+0xFFDD) << 8);
|
|
|
|
int sum=0;
|
|
for(i=0x40;i<0x80; i++)
|
|
{
|
|
uint8 * bank_low=(uint8*)Map[i<<4];
|
|
uint8 * bank_high=(uint8*)Map[(i<<4)+0x800];
|
|
for (c=0;c<0x10000; c++)
|
|
{
|
|
sum+=bank_low[c];
|
|
sum+=bank_high[c];
|
|
}
|
|
}
|
|
|
|
CalculatedChecksum=sum&0xFFFF;
|
|
|
|
MapRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::AlphaROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
|
|
BlockIsROM [i] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
Map [i + 0x400] = &ROM [(c << 12) % CalculatedSize];
|
|
Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
MapRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void DetectSuperFxRamSize()
|
|
{
|
|
if(ROM[0x7FDA]==0x33)
|
|
{
|
|
Memory.SRAMSize=ROM[0x7FBD];
|
|
}
|
|
else
|
|
{
|
|
if(strncmp(Memory.ROMName, "STAR FOX 2", 10)==0)
|
|
{
|
|
Memory.SRAMSize=6;
|
|
}
|
|
else Memory.SRAMSize=5;
|
|
}
|
|
}
|
|
|
|
void CMemory::SuperFXROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
DetectSuperFxRamSize();
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [0x006 + c] = Map [0x806 + c] = (uint8 *) ::SRAM - 0x6000;
|
|
Map [0x007 + c] = Map [0x807 + c] = (uint8 *) ::SRAM - 0x6000;
|
|
BlockIsRAM [0x006 + c] = BlockIsRAM [0x007 + c] = BlockIsRAM [0x806 + c] = BlockIsRAM [0x807 + c] = TRUE;
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 7e->7f, RAM
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [c + 0x7e0] = RAM;
|
|
Map [c + 0x7f0] = RAM + 0x10000;
|
|
BlockIsRAM [c + 0x7e0] = TRUE;
|
|
BlockIsRAM [c + 0x7f0] = TRUE;
|
|
BlockIsROM [c + 0x7e0] = FALSE;
|
|
BlockIsROM [c + 0x7f0] = FALSE;
|
|
}
|
|
|
|
// Banks 70->71, S-RAM
|
|
for (c = 0; c < 32; c++)
|
|
{
|
|
Map [c + 0x700] = ::SRAM + (((c >> 4) & 1) << 16);
|
|
BlockIsRAM [c + 0x700] = TRUE;
|
|
BlockIsROM [c + 0x700] = FALSE;
|
|
}
|
|
|
|
// Replicate the first 2Mb of the ROM at ROM + 2MB such that each 32K
|
|
// block is repeated twice in each 64K block.
|
|
for (c = 0; c < 64; c++)
|
|
{
|
|
memmove (&ROM [0x200000 + c * 0x10000], &ROM [c * 0x8000], 0x8000);
|
|
memmove (&ROM [0x208000 + c * 0x10000], &ROM [c * 0x8000], 0x8000);
|
|
}
|
|
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::SA1ROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) &Memory.FillRAM [0x3000] - 0x3000;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_BWRAM;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_BWRAM;
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
Map [i + 0x400] = (uint8 *) &SRAM [(c << 12) & 0x1ffff];
|
|
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
BlockIsROM [i + 0x400] = FALSE;
|
|
}
|
|
}
|
|
|
|
// c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
|
|
BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [c + 0x7e0] = RAM;
|
|
Map [c + 0x7f0] = RAM + 0x10000;
|
|
BlockIsRAM [c + 0x7e0] = TRUE;
|
|
BlockIsRAM [c + 0x7f0] = TRUE;
|
|
BlockIsROM [c + 0x7e0] = FALSE;
|
|
BlockIsROM [c + 0x7f0] = FALSE;
|
|
}
|
|
WriteProtectROM ();
|
|
|
|
// Now copy the map and correct it for the SA1 CPU.
|
|
memmove ((void *) SA1.WriteMap, (void *) WriteMap, sizeof (WriteMap));
|
|
memmove ((void *) SA1.Map, (void *) Map, sizeof (Map));
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
SA1.Map [c + 0] = SA1.Map [c + 0x800] = &Memory.FillRAM [0x3000];
|
|
SA1.Map [c + 1] = SA1.Map [c + 0x801] = (uint8 *) MAP_NONE;
|
|
SA1.WriteMap [c + 0] = SA1.WriteMap [c + 0x800] = &Memory.FillRAM [0x3000];
|
|
SA1.WriteMap [c + 1] = SA1.WriteMap [c + 0x801] = (uint8 *) MAP_NONE;
|
|
}
|
|
|
|
// Banks 60->6f
|
|
for (c = 0; c < 0x100; c++)
|
|
SA1.Map [c + 0x600] = SA1.WriteMap [c + 0x600] = (uint8 *) MAP_BWRAM_BITMAP;
|
|
|
|
BWRAM = SRAM;
|
|
}
|
|
|
|
void CMemory::LoROM24MBSMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x200; c += 16)
|
|
{
|
|
Map [c + 0x800] = RAM;
|
|
Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i + 0x800] = &ROM [c << 11] - 0x8000 + 0x200000;
|
|
BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 8; i++)
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000];
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000];
|
|
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
MapExtraRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::SufamiTurboLoROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 8; i++)
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000];
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000];
|
|
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Settings.DSP1Master)
|
|
{
|
|
for (c = 0; c < 0x100; c++)
|
|
{
|
|
Map [c + 0xe00] = (uint8 *) MAP_DSP;
|
|
BlockIsROM [c + 0xe00] = FALSE;
|
|
}
|
|
}
|
|
|
|
// Banks 7e->7f, RAM
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [c + 0x7e0] = RAM;
|
|
Map [c + 0x7f0] = RAM + 0x10000;
|
|
BlockIsRAM [c + 0x7e0] = TRUE;
|
|
BlockIsRAM [c + 0x7f0] = TRUE;
|
|
BlockIsROM [c + 0x7e0] = FALSE;
|
|
BlockIsROM [c + 0x7f0] = FALSE;
|
|
}
|
|
|
|
// Banks 60->67, S-RAM
|
|
for (c = 0; c < 0x80; c++)
|
|
{
|
|
Map [c + 0x600] = (uint8 *) MAP_LOROM_SRAM;
|
|
BlockIsRAM [c + 0x600] = TRUE;
|
|
BlockIsROM [c + 0x600] = FALSE;
|
|
}
|
|
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
#if 0
|
|
|
|
//untested!!
|
|
void CMemory::SameGameMap ()
|
|
{
|
|
int i;
|
|
int c;
|
|
int j;
|
|
|
|
int mask[4];
|
|
int mask2[4];
|
|
for (j=0; j<4; j++)
|
|
mask[j]=mask2[j]=0x00ff;
|
|
|
|
mask[0]=(CalculatedSize/0x10000)-1;
|
|
mask2[0]=(Slot1Size/0x10000)-1;
|
|
|
|
int x;
|
|
bool foundZeros;
|
|
bool pastZeros;
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
x=1;
|
|
foundZeros=false;
|
|
pastZeros=false;
|
|
|
|
mask[j+1]=mask[j];
|
|
|
|
while (x>0x100&&!pastZeros)
|
|
{
|
|
if(mask[j]&x)
|
|
{
|
|
x<<=1;
|
|
if(foundZeros)
|
|
pastZeros=true;
|
|
}
|
|
else
|
|
{
|
|
foundZeros=true;
|
|
pastZeros=false;
|
|
mask[j+1]|=x;
|
|
x<<=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
x=1;
|
|
foundZeros=false;
|
|
pastZeros=false;
|
|
|
|
mask2[j+1]=mask2[j];
|
|
|
|
while (x>0x100&&!pastZeros)
|
|
{
|
|
if(mask2[j]&x)
|
|
{
|
|
x<<=1;
|
|
if(foundZeros)
|
|
pastZeros=true;
|
|
}
|
|
else
|
|
{
|
|
foundZeros=true;
|
|
pastZeros=false;
|
|
mask2[j+1]|=x;
|
|
x<<=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
}
|
|
|
|
// Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM.
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [0x306 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [0x307 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [0xb06 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [0xb07 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
BlockIsRAM [0x306 + (c << 4)] = TRUE;
|
|
BlockIsRAM [0x307 + (c << 4)] = TRUE;
|
|
BlockIsRAM [0xb06 + (c << 4)] = TRUE;
|
|
BlockIsRAM [0xb07 + (c << 4)] = TRUE;
|
|
}
|
|
|
|
for c=0; c<0x200; c+=16)
|
|
{
|
|
for(i=0;i<8;i++)
|
|
{
|
|
int e=3;
|
|
int d=c>>4;
|
|
while(d>mask[0])
|
|
{
|
|
d&=mask[e];
|
|
e--;
|
|
}
|
|
|
|
int f=3;
|
|
int g=c>>4;
|
|
while(g>mask2[0])
|
|
{
|
|
g&=mask2[f];
|
|
f--;
|
|
}
|
|
|
|
//stuff in HiROM areas
|
|
Map[c+0x400+i]=&ROM[d*0x10000];
|
|
Map[c+0xC00+i]=&ROM[d*0x10000];
|
|
//MINI
|
|
Map[c+0x600+i]=&ROMOffset1[g*0x10000];
|
|
Map[c+0xE00+i]=&ROMOffset1[g*0x10000];
|
|
|
|
}
|
|
for(i=8;i<16;i++)
|
|
{
|
|
int e=3;
|
|
int d=c>>4;
|
|
while(d>mask[0])
|
|
{
|
|
d&=mask[e];
|
|
e--;
|
|
}
|
|
|
|
int f=3;
|
|
int g=c>>4;
|
|
while(g>mask2[0])
|
|
{
|
|
g&=mask2[f];
|
|
f--;
|
|
}
|
|
|
|
|
|
//all stuff
|
|
//BASE
|
|
Map[c+i]=&ROM[d*0x10000];
|
|
Map[c+0x800+i]=&ROM[d*0x10000];
|
|
Map[c+0x400+i]=&ROM[d*0x10000];
|
|
Map[c+0xC00+i]=&ROM[d*0x10000];
|
|
//MINI
|
|
Map[c+0x200+i]=&ROMOffset1[g*0x10000];
|
|
Map[c+0xA00+i]=&ROMOffset1[g*0x10000];
|
|
Map[c+0x600+i]=&ROMOffset1[g*0x10000];
|
|
Map[c+0xE00+i]=&ROMOffset1[g*0x10000];
|
|
}
|
|
|
|
}
|
|
|
|
int bankmax=0x40+ (1<<(ROMSize-6));
|
|
//safety for corrupt headers
|
|
if(bankmax > 128)
|
|
bankmax = 0x80;
|
|
int sum=0;
|
|
for(i=0x40;i<bankmax; i++)
|
|
{
|
|
uint8 * bank_low=(uint8*)Map[i<<4];
|
|
for (c=0;c<0x10000; c++)
|
|
{
|
|
sum+=bank_low[c];
|
|
}
|
|
}
|
|
CalculatedChecksum=sum&0xFFFF;
|
|
|
|
MapRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
|
|
//Untested!!
|
|
void CMemory::GNextROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) &Memory.FillRAM [0x3000] - 0x3000;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_BWRAM;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_BWRAM;
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// Banks 40->4f (was 7f, but SNES docs and GNext overdumping shows nothing here.)
|
|
for (c = 0; c < 0x100; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
Map [i + 0x400] = (uint8 *) &SRAM [(c << 12) & 0x1ffff];
|
|
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
BlockIsROM [i + 0x400] = FALSE;
|
|
}
|
|
}
|
|
|
|
for (c = 0; c < 0x100; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
Map [i + 0x700] = (uint8 *) &ROMOffset1 [(c << 12) & (Slot1Size-1)];
|
|
}
|
|
|
|
// c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
|
|
BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [c + 0x7e0] = RAM;
|
|
Map [c + 0x7f0] = RAM + 0x10000;
|
|
BlockIsRAM [c + 0x7e0] = TRUE;
|
|
BlockIsRAM [c + 0x7f0] = TRUE;
|
|
BlockIsROM [c + 0x7e0] = FALSE;
|
|
BlockIsROM [c + 0x7f0] = FALSE;
|
|
}
|
|
WriteProtectROM ();
|
|
|
|
// Now copy the map and correct it for the SA1 CPU.
|
|
memmove ((void *) SA1.WriteMap, (void *) WriteMap, sizeof (WriteMap));
|
|
memmove ((void *) SA1.Map, (void *) Map, sizeof (Map));
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
SA1.Map [c + 0] = SA1.Map [c + 0x800] = &Memory.FillRAM [0x3000];
|
|
SA1.Map [c + 1] = SA1.Map [c + 0x801] = (uint8 *) MAP_NONE;
|
|
SA1.WriteMap [c + 0] = SA1.WriteMap [c + 0x800] = &Memory.FillRAM [0x3000];
|
|
SA1.WriteMap [c + 1] = SA1.WriteMap [c + 0x801] = (uint8 *) MAP_NONE;
|
|
}
|
|
|
|
// Banks 60->6f
|
|
for (c = 0; c < 0x100; c++)
|
|
SA1.Map [c + 0x600] = SA1.WriteMap [c + 0x600] = (uint8 *) MAP_BWRAM_BITMAP;
|
|
|
|
BWRAM = SRAM;
|
|
}
|
|
|
|
void CMemory::SufamiTurboAltROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
if(Slot1Size!=0)
|
|
Slot1SRAMSize=(1<<((uint8)ROMOffset1[0x32]))*1024;
|
|
else Slot1Size=0x8000;
|
|
if(Slot2Size!=0)
|
|
Slot2SRAMSize=(1<<((uint8)ROMOffset2[0x32]))*1024;
|
|
else Slot2Size=0x8000;
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
|
|
// for (i = c + 8; i < c + 16; i++)
|
|
// {
|
|
// Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
|
|
// BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
// }
|
|
|
|
}
|
|
|
|
//Map Bios
|
|
|
|
for (c=0; c<0x200; c+=16)
|
|
{
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [((c>>4)*0x8000)%CalculatedSize] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
for (c=0x200; c<0x400; c+=16)
|
|
{
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
if(Slot1Size!=0)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROMOffset1 [(((c>>4)*0x8000)%Slot1Size)] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
else Map [i] = Map [i + 0x800] = (uint8*)MAP_NONE;
|
|
}
|
|
|
|
}
|
|
|
|
for (c=0x400; c<0x600; c+=16)
|
|
{
|
|
for (i = c; i < c + 8; i++)
|
|
{
|
|
if(Slot2Size!=0)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROMOffset2[(((c>>4)*0x8000)%Slot2Size)];
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
else Map [i] = Map [i + 0x800] = (uint8*)MAP_NONE;
|
|
|
|
}
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
if(Slot2Size!=0)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROMOffset2[(((c>>4)*0x8000)%Slot2Size)] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
else Map [i] = Map [i + 0x800] = (uint8*)MAP_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Banks 60->67 (7F?), S-RAM
|
|
if(Slot1SRAMSize!=0)
|
|
{
|
|
for (c = 0; c < 0x100; c++)
|
|
{
|
|
Map [c + 0xE00] = Map [c + 0x600] = (uint8 *) MAP_LOROM_SRAM;
|
|
BlockIsRAM [c + 0xE00] = BlockIsRAM [c + 0x600] = TRUE;
|
|
BlockIsROM [c + 0xE00] = BlockIsROM [c + 0x600] = FALSE;
|
|
}
|
|
}
|
|
if(Slot2SRAMSize!=0)
|
|
{
|
|
for (c = 0; c < 0x100; c++)
|
|
{
|
|
Map [c + 0xF00] = Map [c + 0x700] = (uint8 *) MAP_LOROM_SRAM;
|
|
BlockIsRAM [c + 0xF00] = BlockIsRAM [c + 0x700] = TRUE;
|
|
BlockIsROM [c + 0xF00] = BlockIsROM [c + 0x700] = FALSE;
|
|
}
|
|
}
|
|
|
|
// Banks 7e->7f, RAM
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [c + 0x7e0] = RAM;
|
|
Map [c + 0x7f0] = RAM + 0x10000;
|
|
BlockIsRAM [c + 0x7e0] = TRUE;
|
|
BlockIsRAM [c + 0x7f0] = TRUE;
|
|
BlockIsROM [c + 0x7e0] = FALSE;
|
|
BlockIsROM [c + 0x7f0] = FALSE;
|
|
}
|
|
|
|
WriteProtectROM ();
|
|
}
|
|
#endif
|
|
|
|
|
|
void CMemory::SRAM512KLoROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 8; i++)
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000];
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000];
|
|
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
MapExtraRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::JumboLoROMMap (bool8 Interleaved)
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
uint32 OFFSET0 = 0x400000;
|
|
uint32 OFFSET1 = 0x400000;
|
|
uint32 OFFSET2 = 0x000000;
|
|
|
|
if (Interleaved)
|
|
{
|
|
OFFSET0 = 0x000000;
|
|
OFFSET1 = 0x000000;
|
|
OFFSET2 = CalculatedSize-0x400000; //changed to work with interleaved DKJM2.
|
|
}
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
if (Settings.DSP1Master)
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP;
|
|
}
|
|
else if (Settings.C4)
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_C4;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_C4;
|
|
}
|
|
else
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE;
|
|
}
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i]= &ROM [((c << 11) % (CalculatedSize - 0x400000)) + OFFSET0] - 0x8000;
|
|
Map [i + 0x800] = &ROM [((c << 11) % (0x400000)) + OFFSET2] - 0x8000;
|
|
BlockIsROM [i + 0x800] = BlockIsROM [i] = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Settings.DSP1Master)
|
|
{
|
|
// Banks 30->3f and b0->bf
|
|
for (c = 0x300; c < 0x400; c += 16)
|
|
{
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i + 0x800] = (uint8 *) MAP_DSP;
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0x400; c < 0x800; c += 16)
|
|
{
|
|
//updated mappings to correct A15 mirroring
|
|
for (i = c; i < c + 8; i++)
|
|
{
|
|
Map [i]= &ROM [((c << 11) % (CalculatedSize - 0x400000)) + OFFSET0];
|
|
Map [i + 0x800] = &ROM [((c << 11) % 0x400000) +OFFSET2];
|
|
}
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i]= &ROM [((c << 11) % (CalculatedSize - 0x400000)) + OFFSET0] - 0x8000;
|
|
Map [i + 0x800] = &ROM [((c << 11) % 0x400000) + OFFSET2 ] - 0x8000;
|
|
}
|
|
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
//ROM type has to be 64 Mbit header!
|
|
int sum=0, k,l;
|
|
for(k=0;k<256;k++)
|
|
{
|
|
uint8* bank=0x8000+Map[8+(k<<4)];//use upper half of the banks, and adjust for LoROM.
|
|
for(l=0;l<0x8000;l++)
|
|
sum+=bank[l];
|
|
}
|
|
CalculatedChecksum=sum&0xFFFF;
|
|
|
|
MapRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
void CMemory::SPC7110HiROMMap ()
|
|
{
|
|
int c;
|
|
int i;
|
|
|
|
// Banks 00->3f and 80->bf
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 0] = Map [c + 0x800] = RAM;
|
|
BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE;
|
|
Map [c + 1] = Map [c + 0x801] = RAM;
|
|
BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE;
|
|
|
|
Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU;
|
|
Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU;
|
|
Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU;
|
|
Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU;
|
|
|
|
Map [c + 6] /*= Map [c + 0x806]*/ = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [c + 7] /*= Map [c + 0x807]*/ = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [c + 0x806]=Map [c + 0x807]= (uint8 *) MAP_NONE;
|
|
|
|
for (i = c + 8; i < c + 16; i++)
|
|
{
|
|
Map [i] = Map [i + 0x800] = &ROM [(c << 12) % CalculatedSize];
|
|
BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE;
|
|
}
|
|
}
|
|
|
|
// Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM.
|
|
for (c = 0; c < 16; c++)
|
|
{
|
|
Map [0x306 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [0x307 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM;
|
|
Map [0xb06 + (c << 4)] = (uint8 *) MAP_NONE;
|
|
Map [0xb07 + (c << 4)] = (uint8 *) MAP_NONE;
|
|
BlockIsRAM [0x306 + (c << 4)] = TRUE;
|
|
BlockIsRAM [0x307 + (c << 4)] = TRUE;
|
|
// BlockIsRAM [0xb06 + (c << 4)] = TRUE;
|
|
// BlockIsRAM [0xb07 + (c << 4)] = TRUE;
|
|
}
|
|
|
|
// Banks 40->7f and c0->ff
|
|
for (c = 0; c < 0x400; c += 16)
|
|
{
|
|
for (i = c; i < c + 16; i++)
|
|
{
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize];
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE;
|
|
}
|
|
}
|
|
|
|
for (c=0;c<0x10;c++)
|
|
{
|
|
Map [0x500+c]=(uint8 *)MAP_SPC7110_DRAM;
|
|
BlockIsROM [0x500+c]=TRUE;
|
|
}
|
|
|
|
for (c=0;c<0x100;c++)
|
|
{
|
|
Map [0xD00+c] = (uint8 *) MAP_SPC7110_ROM;
|
|
Map [0xE00+c] = (uint8 *) MAP_SPC7110_ROM;
|
|
Map [0xF00+c] = (uint8 *) MAP_SPC7110_ROM;
|
|
BlockIsROM [0xD00+c] = BlockIsROM [0xE00+c] = BlockIsROM [0xF00+c] = TRUE;
|
|
|
|
}
|
|
S9xSpc7110Init();
|
|
|
|
int sum=0;
|
|
for(i=0;i<(int)CalculatedSize; i++)
|
|
{
|
|
sum+=ROM[i];
|
|
}
|
|
|
|
if(CalculatedSize==0x300000)
|
|
sum<<=1;
|
|
CalculatedChecksum=sum&0xFFFF;
|
|
|
|
MapRAM ();
|
|
WriteProtectROM ();
|
|
}
|
|
void CMemory::SPC7110Sram(uint8 newstate)
|
|
{
|
|
if(newstate&0x80)
|
|
{
|
|
Memory.Map[6]=(uint8 *)MAP_HIROM_SRAM;
|
|
Memory.Map[7]=(uint8 *)MAP_HIROM_SRAM;
|
|
Memory.Map[0x306]=(uint8 *)MAP_HIROM_SRAM;
|
|
Memory.Map[0x307]=(uint8 *)MAP_HIROM_SRAM;
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
Memory.Map[6]=(uint8 *)MAP_RONLY_SRAM;
|
|
Memory.Map[7]=(uint8 *)MAP_RONLY_SRAM;
|
|
Memory.Map[0x306]=(uint8 *)MAP_RONLY_SRAM;
|
|
Memory.Map[0x307]=(uint8 *)MAP_RONLY_SRAM;
|
|
}
|
|
}
|
|
const char *CMemory::TVStandard ()
|
|
{
|
|
return (Settings.PAL ? "PAL" : "NTSC");
|
|
}
|
|
|
|
const char *CMemory::Speed ()
|
|
{
|
|
return (ROMSpeed & 0x10 ? "120ns" : "200ns");
|
|
}
|
|
|
|
const char *CMemory::MapType ()
|
|
{
|
|
return (HiROM ? "HiROM" : "LoROM");
|
|
}
|
|
|
|
const char *CMemory::StaticRAMSize ()
|
|
{
|
|
static char tmp [20];
|
|
|
|
if (Memory.SRAMSize > 16)
|
|
return ("Corrupt");
|
|
sprintf (tmp, "%dKB", (SRAMMask + 1) / 1024);
|
|
return (tmp);
|
|
}
|
|
|
|
const char *CMemory::Size ()
|
|
{
|
|
static char tmp [20];
|
|
|
|
if (ROMSize < 7 || ROMSize - 7 > 23)
|
|
return ("Corrupt");
|
|
sprintf (tmp, "%dMbits", 1 << (ROMSize - 7));
|
|
return (tmp);
|
|
}
|
|
|
|
const char *CMemory::KartContents ()
|
|
{
|
|
static char tmp [30];
|
|
static const char *CoPro [16] = {
|
|
"DSP", "SuperFX", "OBC1", "SA-1", "S-DD1", "S-RTC", "CoPro#6",
|
|
"CoPro#7", "CoPro#8", "CoPro#9", "CoPro#10", "CoPro#11", "CoPro#12",
|
|
"CoPro#13", "CoPro#14", "CoPro-Custom"
|
|
};
|
|
static const char *Contents [3] = {
|
|
"ROM", "ROM+RAM", "ROM+RAM+BAT"
|
|
};
|
|
static const char *DSPSel [4] = {
|
|
"DSP1", "DSP2", "DSP3", "DSP4"
|
|
};
|
|
if (ROMType == 0&&!Settings.BS)
|
|
return ("ROM only");
|
|
|
|
sprintf (tmp, "%s", Contents [(ROMType & 0xf) % 3]);
|
|
|
|
if(Settings.BS)
|
|
sprintf (tmp, "%s+%s", tmp, "BSX");
|
|
else if(Settings.SPC7110&&Settings.SPC7110RTC)
|
|
sprintf (tmp, "%s+%s", tmp, "SPC7110+RTC");
|
|
else if(Settings.SPC7110)
|
|
sprintf (tmp, "%s+%s", tmp, "SPC7110");
|
|
else if(Settings.C4)
|
|
sprintf (tmp, "%s+%s", tmp, "C4");
|
|
else if(Settings.SETA!=0)
|
|
{
|
|
switch(Settings.SETA)
|
|
{
|
|
case ST_010:
|
|
sprintf (tmp, "%s+%s", tmp, "ST-010");
|
|
break;
|
|
case ST_011:
|
|
sprintf (tmp, "%s+%s", tmp, "ST-011");
|
|
break;
|
|
|
|
case ST_018:
|
|
sprintf (tmp, "%s+%s", tmp, "ST-018");
|
|
break;
|
|
|
|
}
|
|
}
|
|
else if ((ROMType & 0xf) >= 3)
|
|
{
|
|
if (ROMType & 0xf0)
|
|
sprintf (tmp, "%s+%s", tmp, CoPro [(ROMType & 0xf0) >> 4]);
|
|
else
|
|
sprintf (tmp, "%s+%s", tmp, DSPSel [DSP1.version]);
|
|
}
|
|
|
|
return (tmp);
|
|
}
|
|
|
|
const char *CMemory::MapMode ()
|
|
{
|
|
static char tmp [4];
|
|
sprintf (tmp, "%02x", ROMSpeed & ~0x10);
|
|
return (tmp);
|
|
}
|
|
|
|
const char *CMemory::ROMID ()
|
|
{
|
|
return (ROMId);
|
|
}
|
|
|
|
void CMemory::ApplyROMFixes ()
|
|
{
|
|
#ifdef __W32_HEAP
|
|
if(_HEAPOK!=_heapchk())
|
|
MessageBox(GUI.hWnd, "CMemory::ApplyROMFixes", "Heap Corrupt", MB_OK);
|
|
#endif
|
|
|
|
//don't steal my work! -MK
|
|
if(ROMCRC32 == 0x1B4A5616 && strncmp(ROMName, "RUDORA NO HIHOU", 15)==0)
|
|
{
|
|
strncpy(ROMName, "THIS SCRIPT WAS STOLEN", 22);
|
|
Settings.DisplayColor=BUILD_PIXEL(31,0,0);
|
|
SET_UI_COLOR(255,0,0);
|
|
}
|
|
|
|
/*
|
|
HACKS NSRT can fix that we hadn't detected before.
|
|
[14:25:13] <@Nach> case 0x0c572ef0: //So called Hook (US)(2648)
|
|
[14:25:13] <@Nach> case 0x6810aa95: //Bazooka Blitzkreig swapped sizes hack -handled
|
|
[14:25:17] <@Nach> case 0x61E29C06: //The Tick region hack
|
|
[14:25:19] <@Nach> case 0x1EF90F74: //Jikkyou Keiba Simulation Stable Star PAL hack
|
|
[14:25:23] <@Nach> case 0x4ab225b5: //So called Krusty's Super Fun House (E)
|
|
[14:25:25] <@Nach> case 0x77fd806a: //Donkey Kong Country 2 (E) v1.1 bad dump -handled
|
|
[14:25:27] <@Nach> case 0x340f23e5: //Donkey Kong Country 3 (U) copier hack - handled
|
|
*/
|
|
|
|
if(ROMCRC32==0x6810aa95 || ROMCRC32==0x340f23e5 || ROMCRC32==0x77fd806a ||
|
|
strncmp (ROMName, "HIGHWAY BATTLE 2", 16)==0 ||
|
|
(strcmp (ROMName, "FX SKIING NINTENDO 96") == 0 && ROM[0x7FDA]==0))
|
|
{
|
|
Settings.DisplayColor=BUILD_PIXEL(31,0,0);
|
|
SET_UI_COLOR(255,0,0);
|
|
}
|
|
|
|
//Ambiguous chip function pointer assignments
|
|
DSP1.version=0;
|
|
|
|
//DSP switching:
|
|
if(strncmp(ROMName, "DUNGEON MASTER", 14)==0)
|
|
{
|
|
//Set DSP-2
|
|
DSP1.version=1;
|
|
SetDSP=&DSP2SetByte;
|
|
GetDSP=&DSP2GetByte;
|
|
}
|
|
|
|
if(strncmp(ROMName, "SD\x0b6\x0de\x0dd\x0c0\x0de\x0d1GX", 10)==0) // SD Gundam GX
|
|
{
|
|
//Set DSP-3
|
|
DSP1.version=2;
|
|
SetDSP = &DSP3SetByte;
|
|
GetDSP = &DSP3GetByte;
|
|
DSP3_Reset();
|
|
}
|
|
|
|
if(strncmp(ROMName, "TOP GEAR 3000", 13)==0
|
|
||strncmp(ROMName, "PLANETS CHAMP TG3000", 20)==0)
|
|
{
|
|
//Set DSP-4
|
|
DSP1.version=3;
|
|
SetDSP=&DSP4SetByte;
|
|
GetDSP=&DSP4GetByte;
|
|
// FIXME: memory map correction
|
|
for (int c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map[c + 6] = Map[c + 0x806] = (uint8 *) MAP_NONE;
|
|
Map[c + 7] = Map[c + 0x807] = (uint8 *) MAP_NONE;
|
|
}
|
|
WriteProtectROM();
|
|
}
|
|
|
|
//memory map corrections
|
|
if(strncmp(ROMName, "XBAND",5)==0)
|
|
{
|
|
for (int c=0xE00;c<0xE10;c++)
|
|
{
|
|
Map [c] = (uint8 *) MAP_LOROM_SRAM;
|
|
BlockIsRAM [c] = TRUE;
|
|
BlockIsROM [c] = FALSE;
|
|
}
|
|
WriteProtectROM ();
|
|
}
|
|
|
|
//not MAD-1 compliant
|
|
if(strcmp (ROMName, "WANDERERS FROM YS") == 0)
|
|
{
|
|
for(int c=0;c<0xE0;c++)
|
|
{
|
|
Map[c+0x700]=(uint8*)MAP_LOROM_SRAM;
|
|
BlockIsROM[c+0x700]=FALSE;
|
|
BlockIsRAM[c+0x700]=TRUE;
|
|
}
|
|
WriteProtectROM();
|
|
}
|
|
|
|
#if 0
|
|
// These two games don't have SRAM. Sounds like OpenBus issue...
|
|
if (strcmp (ROMName, "GOGO ACKMAN3") == 0 ||
|
|
strcmp (ROMName, "HOME ALONE") == 0)
|
|
{
|
|
// Banks 00->3f and 80->bf
|
|
for (int c = 0; c < 0x400; c += 16)
|
|
{
|
|
Map [c + 6] = Map [c + 0x806] = SRAM;
|
|
Map [c + 7] = Map [c + 0x807] = SRAM;
|
|
BlockIsROM [c + 6] = BlockIsROM [c + 0x806] = FALSE;
|
|
BlockIsROM [c + 7] = BlockIsROM [c + 0x807] = FALSE;
|
|
BlockIsRAM [c + 6] = BlockIsRAM [c + 0x806] = TRUE;
|
|
BlockIsRAM [c + 7] = BlockIsRAM [c + 0x807] = TRUE;
|
|
}
|
|
WriteProtectROM ();
|
|
}
|
|
#endif
|
|
|
|
if (strncmp (ROMName, "BATMAN--REVENGE JOKER", 21) == 0)
|
|
{
|
|
Memory.HiROM = FALSE;
|
|
Memory.LoROM = TRUE;
|
|
LoROMMap ();
|
|
}
|
|
|
|
// Force Disabling a speed-up hack (CPU_Shutdown())
|
|
// Games which spool sound samples between the SNES and sound CPU using
|
|
// H-DMA as the sample is playing.
|
|
if (strcmp (ROMName, "EARTHWORM JIM 2") == 0 ||
|
|
strcmp (ROMName, "PRIMAL RAGE") == 0 ||
|
|
strcmp (ROMName, "CLAY FIGHTER") == 0 ||
|
|
strcmp (ROMName, "ClayFighter 2") == 0 ||
|
|
strncasecmp (ROMName, "MADDEN", 6) == 0 ||
|
|
strncmp (ROMName, "NHL", 3) == 0 ||
|
|
strcmp (ROMName, "WeaponLord") == 0 ||
|
|
strncmp(ROMName, "WAR 2410", 8) == 0 ||
|
|
strncmp (ROMId, "ARF", 3) == 0) // Star Ocean
|
|
{
|
|
Settings.Shutdown = FALSE;
|
|
}
|
|
|
|
//APU timing hacks
|
|
|
|
// Stunt Racer FX
|
|
if (strcmp (ROMId, "CQ ") == 0 ||
|
|
// Illusion of Gaia
|
|
strncmp (ROMId, "JG", 2) == 0 ||
|
|
strcmp (ROMName, "GAIA GENSOUKI 1 JPN") == 0)
|
|
{
|
|
IAPU.OneCycle = 13;
|
|
}
|
|
|
|
// RENDERING RANGER R2
|
|
if (strcmp (ROMId, "AVCJ") == 0 ||
|
|
//Mark Davis
|
|
strncmp(ROMName, "THE FISHING MASTER", 18)==0 || //needs >= actual APU timing. (21 is .002 Mhz slower)
|
|
// Star Ocean
|
|
strncmp (ROMId, "ARF", 3) == 0 ||
|
|
// Tales of Phantasia
|
|
strncmp (ROMId, "ATV", 3) == 0 ||
|
|
// Act Raiser 1 & 2
|
|
strncasecmp (ROMName, "ActRaiser", 9) == 0 ||
|
|
// Soulblazer
|
|
strcmp (ROMName, "SOULBLAZER - 1 USA") == 0 ||
|
|
strcmp (ROMName, "SOULBLADER - 1") == 0 ||
|
|
|
|
// Terranigma
|
|
strncmp (ROMId, "AQT", 3) == 0 ||
|
|
// Robotrek
|
|
strncmp (ROMId, "E9 ", 3) == 0 ||
|
|
strcmp (ROMName, "SLAP STICK 1 JPN") == 0 ||
|
|
// ZENNIHON PURORESU2
|
|
strncmp (ROMId, "APR", 3) == 0 ||
|
|
// Bomberman 4
|
|
strncmp (ROMId, "A4B", 3) == 0 ||
|
|
// UFO KAMEN YAKISOBAN
|
|
strncmp (ROMId, "Y7 ", 3) == 0 ||
|
|
strncmp (ROMId, "Y9 ", 3) == 0 ||
|
|
// Panic Bomber World
|
|
strncmp (ROMId, "APB", 3) == 0 ||
|
|
((strncmp (ROMName, "Parlor", 6) == 0 ||
|
|
strcmp (ROMName, "HEIWA Parlor!Mini8") == 0 ||
|
|
strncmp (ROMName, "SANKYO Fever! \xCC\xA8\xB0\xCA\xDE\xB0!", 21) == 0) && //SANKYO Fever! Fever!
|
|
strcmp (CompanyId, "A0") == 0) ||
|
|
strcmp (ROMName, "DARK KINGDOM") == 0 ||
|
|
strcmp (ROMName, "ZAN3 SFC") == 0 ||
|
|
strcmp (ROMName, "HIOUDEN") == 0 ||
|
|
strcmp (ROMName, "\xC3\xDD\xBC\xC9\xB3\xC0") == 0 || //Tenshi no Uta
|
|
strcmp (ROMName, "FORTUNE QUEST") == 0 ||
|
|
strcmp (ROMName, "FISHING TO BASSING") == 0 ||
|
|
strncmp (ROMName, "TokyoDome '95Battle 7", 21) == 0 ||
|
|
strcmp (ROMName, "OHMONO BLACKBASS") == 0 ||
|
|
strncmp (ROMName, "SWORD WORLD SFC", 15) == 0 ||
|
|
strcmp (ROMName, "MASTERS") ==0 || //Augusta 2 J
|
|
strcmp (ROMName, "SFC \xB6\xD2\xDD\xD7\xB2\xC0\xDE\xB0") == 0 || //Kamen Rider
|
|
strcmp (ROMName, "ZENKI TENCHIMEIDOU") == 0 ||
|
|
strncmp (ROMName, "LETs PACHINKO(", 14) == 0) //A set of BS games
|
|
{
|
|
IAPU.OneCycle = 15;
|
|
}
|
|
|
|
//Specific game fixes
|
|
|
|
// for ZSNES SuperFX: is it still necessary?
|
|
Settings.WinterGold = strcmp (ROMName, "FX SKIING NINTENDO 96") == 0 ||
|
|
strcmp (ROMName, "DIRT RACER") == 0;
|
|
|
|
//OAM hacks because we don't fully understand the
|
|
//behavior of the SNES.
|
|
//Totally wacky display...
|
|
//seems to need a disproven behavior, so
|
|
//we're definitely overlooking some other bug?
|
|
if(strncmp(ROMName, "UNIRACERS", 9)==0)
|
|
SNESGameFixes.Uniracers=true;
|
|
|
|
#if 0
|
|
if (strcmp (ROMName, "\xBD\xB0\xCA\xDF\xB0\xCC\xA7\xD0\xBD\xC0") == 0 || //Super Famista
|
|
strcmp (ROMName, "\xBD\xB0\xCA\xDF\xB0\xCC\xA7\xD0\xBD\xC0 2") == 0 || //Super Famista 2
|
|
strcmp (ROMName, "GANBA LEAGUE") == 0)
|
|
{
|
|
SNESGameFixes.APU_OutPorts_ReturnValueFix = TRUE;
|
|
}
|
|
#endif
|
|
|
|
//CPU timing hacks
|
|
Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * Settings.CyclesPercentage) / 100;
|
|
Timings.HBlankStart = SNES_HBLANK_START_HC;
|
|
Timings.HDMAStart = SNES_HDMA_START_HC;
|
|
Timings.RenderPos = SNES_RENDER_START_HC;
|
|
|
|
//The first new hack since timings were changed :(
|
|
if (strncmp(ROMName, "SeikenDensetsu 2", 16) == 0 ||
|
|
strncmp(ROMName, "Secret of MANA", 14) == 0)
|
|
{
|
|
Timings.HBlankStart -= 34;
|
|
Timings.HDMAStart -= 34;
|
|
}
|
|
|
|
/* if(strcmp(ROMName, "HOME IMPROVEMENT")==0)
|
|
Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 200) / 100;
|
|
|
|
if (strcmp (ROMId, "ASRJ") == 0 && Settings.CyclesPercentage == 100)
|
|
// Street Racer
|
|
Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 95) / 100;
|
|
|
|
// Power Rangers Fight
|
|
if (strncmp (ROMId, "A3R", 3) == 0 ||
|
|
// Clock Tower
|
|
strncmp (ROMId, "AJE", 3) == 0)
|
|
Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 103) / 100;
|
|
|
|
if (strncmp (ROMId, "A3M", 3) == 0 && Settings.CyclesPercentage == 100)
|
|
// Mortal Kombat 3. Fixes cut off speech sample
|
|
Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 110) / 100;
|
|
|
|
//Darkness Beyond Twilight
|
|
//Crimson beyond blood that flows
|
|
//buried in the stream of time
|
|
//is where your power grows
|
|
//I pledge myself to conquer
|
|
//all the foes who stand
|
|
//before the might gift betsowed
|
|
//in my unworthy hand
|
|
if (strcmp (ROMName, "\x0bd\x0da\x0b2\x0d4\x0b0\x0bd\x0de") == 0 &&
|
|
Settings.CyclesPercentage == 100)
|
|
Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 101) / 100;
|
|
// Start Trek: Deep Sleep 9
|
|
if (strncmp (ROMId, "A9D", 3) == 0 && Settings.CyclesPercentage == 100)
|
|
Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 110) / 100;
|
|
*/
|
|
Timings.H_Max_Master = Timings.H_Max;
|
|
|
|
//SA-1 Speedup settings
|
|
SA1.WaitAddress = 0xffffffff;
|
|
SA1.WaitByteAddress1 = NULL;
|
|
SA1.WaitByteAddress2 = NULL;
|
|
|
|
/* Bass Fishing */
|
|
if (strcmp (ROMId, "ZBPJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x0093f1;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x304a;
|
|
}
|
|
/* DAISENRYAKU EXPERTWW2 */
|
|
if (strcmp (ROMId, "AEVJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x0ed18d;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x3000;
|
|
}
|
|
/* debjk2 */
|
|
if (strcmp (ROMId, "A2DJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x008b62;
|
|
}
|
|
/* Dragon Ballz HD */
|
|
if (strcmp (ROMId, "AZIJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x008083;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x3020;
|
|
}
|
|
/* SFC SDGUNDAMGNEXT */
|
|
if (strcmp (ROMId, "ZX3J") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x0087f2;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x30c4;
|
|
}
|
|
/* ShougiNoHanamichi */
|
|
if (strcmp (ROMId, "AARJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0xc1f85a;
|
|
SA1.WaitByteAddress1 = SRAM + 0x0c64;
|
|
SA1.WaitByteAddress2 = SRAM + 0x0c66;
|
|
}
|
|
/* KATO HIFUMI9DAN SYOGI */
|
|
if (strcmp (ROMId, "A23J") == 0)
|
|
{
|
|
SA1.WaitAddress = 0xc25037;
|
|
SA1.WaitByteAddress1 = SRAM + 0x0c06;
|
|
SA1.WaitByteAddress2 = SRAM + 0x0c08;
|
|
}
|
|
/* idaten */
|
|
if (strcmp (ROMId, "AIIJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0xc100be;
|
|
SA1.WaitByteAddress1 = SRAM + 0x1002;
|
|
SA1.WaitByteAddress2 = SRAM + 0x1004;
|
|
}
|
|
/* igotais */
|
|
if (strcmp (ROMId, "AITJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x0080b7;
|
|
}
|
|
/* J96 DREAM STADIUM */
|
|
if (strcmp (ROMId, "AJ6J") == 0)
|
|
{
|
|
SA1.WaitAddress = 0xc0f74a;
|
|
}
|
|
/* JumpinDerby */
|
|
if (strcmp (ROMId, "AJUJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x00d926;
|
|
}
|
|
/* JKAKINOKI SHOUGI */
|
|
if (strcmp (ROMId, "AKAJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x00f070;
|
|
}
|
|
/* HOSHI NO KIRBY 3 & KIRBY'S DREAM LAND 3 JAP & US */
|
|
if (strcmp (ROMId, "AFJJ") == 0 || strcmp (ROMId, "AFJE") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x0082d4;
|
|
SA1.WaitByteAddress1 = SRAM + 0x72a4;
|
|
}
|
|
/* KIRBY SUPER DELUXE JAP */
|
|
if (strcmp (ROMId, "AKFJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x008c93;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x300a;
|
|
SA1.WaitByteAddress2 = FillRAM + 0x300e;
|
|
}
|
|
/* KIRBY SUPER DELUXE US */
|
|
if (strcmp (ROMId, "AKFE") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x008cb8;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x300a;
|
|
SA1.WaitByteAddress2 = FillRAM + 0x300e;
|
|
}
|
|
/* SUPER MARIO RPG JAP & US */
|
|
if (strcmp (ROMId, "ARWJ") == 0 || strcmp (ROMId, "ARWE") == 0)
|
|
{
|
|
SA1.WaitAddress = 0xc0816f;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x3000;
|
|
}
|
|
/* marvelous.zip */
|
|
if (strcmp (ROMId, "AVRJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x0085f2;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x3024;
|
|
}
|
|
/* AUGUSTA3 MASTERS NEW */
|
|
if (strcmp (ROMId, "AO3J") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x00dddb;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x37b4;
|
|
}
|
|
/* OSHABERI PARODIUS */
|
|
if (strcmp (ROMId, "AJOJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x8084e5;
|
|
}
|
|
/* PANIC BOMBER WORLD */
|
|
if (strcmp (ROMId, "APBJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x00857a;
|
|
}
|
|
/* PEBBLE BEACH NEW */
|
|
if (strcmp (ROMId, "AONJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x00df33;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x37b4;
|
|
}
|
|
/* PGA EUROPEAN TOUR */
|
|
if (strcmp (ROMId, "AEPE") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x003700;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x3102;
|
|
}
|
|
/* PGA TOUR 96 */
|
|
if (strcmp (ROMId, "A3GE") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x003700;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x3102;
|
|
}
|
|
/* POWER RANGERS 4 */
|
|
if (strcmp (ROMId, "A4RE") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x009899;
|
|
SA1.WaitByteAddress1 = FillRAM + 0x3000;
|
|
}
|
|
/* PACHISURO PALUSUPE */
|
|
if (strcmp (ROMId, "AGFJ") == 0)
|
|
{
|
|
// Never seems to turn on the SA-1!
|
|
}
|
|
/* SD F1 GRAND PRIX */
|
|
if (strcmp (ROMId, "AGFJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x0181bc;
|
|
}
|
|
/* SHOUGI MARJONG */
|
|
if (strcmp (ROMId, "ASYJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x00f2cc;
|
|
SA1.WaitByteAddress1 = SRAM + 0x7ffe;
|
|
SA1.WaitByteAddress2 = SRAM + 0x7ffc;
|
|
}
|
|
/* shogisai2 */
|
|
if (strcmp (ROMId, "AX2J") == 0)
|
|
{
|
|
SA1.WaitAddress = 0x00d675;
|
|
}
|
|
|
|
/* SHINING SCORPION */
|
|
if (strcmp (ROMId, "A4WJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0xc048be;
|
|
}
|
|
/* SHIN SHOUGI CLUB */
|
|
if (strcmp (ROMId, "AHJJ") == 0)
|
|
{
|
|
SA1.WaitAddress = 0xc1002a;
|
|
SA1.WaitByteAddress1 = SRAM + 0x0806;
|
|
SA1.WaitByteAddress2 = SRAM + 0x0808;
|
|
}
|
|
|
|
|
|
//Other
|
|
|
|
// Additional game fixes by sanmaiwashi ...
|
|
if (strcmp (ROMName, "SFX \xC5\xB2\xC4\xB6\xDE\xDD\xC0\xDE\xD1\xD3\xC9\xB6\xDE\xC0\xD8 1") == 0) // Gundam Knight Story
|
|
{
|
|
// bytes0x2000 [0xb18] = 0x4c;
|
|
// bytes0x2000 [0xb19] = 0x4b;
|
|
// bytes0x2000 [0xb1a] = 0xea;
|
|
SNESGameFixes.SRAMInitialValue = 0x6b;
|
|
}
|
|
|
|
|
|
// HITOMI3
|
|
if (strcmp (ROMName, "HITOMI3") == 0)
|
|
{
|
|
Memory.SRAMSize = 1;
|
|
SRAMMask = Memory.SRAMSize ?
|
|
((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0;
|
|
}
|
|
|
|
//sram value fixes
|
|
if (strcmp (Memory.ROMName, "SUPER DRIFT OUT") == 0 ||
|
|
strcmp(Memory.ROMName, "SATAN IS OUR FATHER!") == 0 ||
|
|
strcmp (ROMName, "goemon 4") == 0)
|
|
SNESGameFixes.SRAMInitialValue = 0x00;
|
|
|
|
#if 0
|
|
if(strcmp (ROMName, "XBAND JAPANESE MODEM") == 0)
|
|
{
|
|
for (c = 0x200; c < 0x400; c += 16)
|
|
{
|
|
for (int i = c; i < c + 16; i++)
|
|
{
|
|
Map [i + 0x400] = Map [i + 0xc00] = &ROM[c * 0x1000];
|
|
BlockIsRAM [i + 0x400] = BlockIsRAM [i + 0xc00] = TRUE;
|
|
BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = FALSE;
|
|
}
|
|
}
|
|
WriteProtectROM ();
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
// XXX: wait-and-see...
|
|
#define RomPatch(adr,ov,nv) \
|
|
if (ROM [adr] == ov) \
|
|
ROM [adr] = nv
|
|
|
|
// Love Quest
|
|
if (strcmp (ROMName, "LOVE QUEST") == 0)
|
|
{
|
|
RomPatch (0x1385ec, 0xd0, 0xea);
|
|
RomPatch (0x1385ed, 0xb2, 0xea);
|
|
}
|
|
//BNE D0 into nops
|
|
|
|
//this is a cmp on $00:2140
|
|
// Super Batter Up
|
|
if (strcmp (ROMName, "Super Batter Up") == 0)
|
|
{
|
|
RomPatch (0x27ae0, 0xd0, 0xea);
|
|
RomPatch (0x27ae1, 0xfa, 0xea);
|
|
}
|
|
//BNE
|
|
#endif
|
|
}
|
|
|
|
#ifndef NGC
|
|
// Read variable size MSB int from a file
|
|
static long ReadInt (Reader *r, unsigned nbytes)
|
|
{
|
|
long v = 0;
|
|
while (nbytes--)
|
|
{
|
|
int c = r->get_char();
|
|
if (c == EOF)
|
|
return -1;
|
|
v = (v << 8) | (c & 0xFF);
|
|
}
|
|
return (v);
|
|
}
|
|
#endif
|
|
|
|
#define IPS_EOF 0x00454F46l
|
|
|
|
#ifndef NGC
|
|
static bool8 ReadIPSPatch(Reader *r, long offset, int32 &rom_size)
|
|
{
|
|
char fname[6];
|
|
for(int i=0; i<5; i++){
|
|
int c=r->get_char();
|
|
if(c==EOF) return 0;
|
|
fname[i]=(char) c;
|
|
}
|
|
fname[5]=0;
|
|
if (strncmp (fname, "PATCH", 5) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int32 ofs;
|
|
|
|
for (;;)
|
|
{
|
|
long len;
|
|
long rlen;
|
|
int rchar;
|
|
|
|
ofs = ReadInt (r, 3);
|
|
if (ofs == -1)
|
|
goto err_eof;
|
|
|
|
if (ofs == IPS_EOF)
|
|
break;
|
|
|
|
ofs -= offset;
|
|
|
|
len = ReadInt (r, 2);
|
|
if (len == -1)
|
|
goto err_eof;
|
|
|
|
/* Apply patch block */
|
|
if (len)
|
|
{
|
|
if (ofs + len > CMemory::MAX_ROM_SIZE)
|
|
goto err_eof;
|
|
|
|
while (len--)
|
|
{
|
|
rchar = r->get_char();
|
|
if (rchar == EOF)
|
|
goto err_eof;
|
|
ROM [ofs++] = (uint8) rchar;
|
|
}
|
|
if (ofs > rom_size)
|
|
rom_size = ofs;
|
|
}
|
|
else
|
|
{
|
|
rlen = ReadInt (r, 2);
|
|
if (rlen == -1)
|
|
goto err_eof;
|
|
|
|
rchar = r->get_char();
|
|
if (rchar == EOF)
|
|
goto err_eof;
|
|
|
|
if (ofs + rlen > CMemory::MAX_ROM_SIZE)
|
|
goto err_eof;
|
|
|
|
while (rlen--)
|
|
ROM [ofs++] = (uint8) rchar;
|
|
|
|
if (ofs > rom_size)
|
|
rom_size = ofs;
|
|
}
|
|
}
|
|
|
|
// Check if ROM image needs to be truncated
|
|
ofs = ReadInt (r, 3);
|
|
if (ofs != -1 && ofs - offset < rom_size)
|
|
{
|
|
// Need to truncate ROM image
|
|
rom_size = ofs - offset;
|
|
}
|
|
return 1;
|
|
|
|
err_eof:
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef NGC
|
|
static int unzFindExtension(unzFile &file, const char *ext, bool restart=true, bool print=true){
|
|
int port;
|
|
int l=strlen(ext);
|
|
|
|
if(restart){
|
|
port=unzGoToFirstFile(file);
|
|
} else {
|
|
port=unzGoToNextFile(file);
|
|
}
|
|
unz_file_info info;
|
|
while(port==UNZ_OK){
|
|
char name[132];
|
|
unzGetCurrentFileInfo(file, &info, name,128, NULL,0, NULL,0);
|
|
int len=strlen(name);
|
|
if(len>=l+1 && name[len-l-1]=='.' && strcasecmp(name+len-l, ext)==0 &&
|
|
unzOpenCurrentFile(file)==UNZ_OK){
|
|
if(print) printf("Using IPS patch %s", name);
|
|
return port;
|
|
}
|
|
port = unzGoToNextFile(file);
|
|
}
|
|
return port;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef NGC
|
|
void CMemory::CheckForIPSPatch (const char *rom_filename, bool8 header,
|
|
int32 &rom_size)
|
|
{
|
|
if(Settings.NoPatch) return;
|
|
|
|
char dir [_MAX_DIR + 1];
|
|
char drive [_MAX_DRIVE + 1];
|
|
char name [_MAX_FNAME + 1];
|
|
char ext [_MAX_EXT + 1];
|
|
char ips [_MAX_EXT + 3];
|
|
char fname [_MAX_PATH + 1];
|
|
STREAM patch_file = NULL;
|
|
long offset = header ? 512 : 0;
|
|
int ret;
|
|
bool8 flag;
|
|
uint32 i;
|
|
|
|
_splitpath (rom_filename, drive, dir, name, ext);
|
|
_makepath (fname, drive, dir, name, "ips");
|
|
if ((patch_file = OPEN_STREAM (fname, "rb")))
|
|
{
|
|
printf ("Using IPS patch %s", fname);
|
|
ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size);
|
|
CLOSE_STREAM(patch_file);
|
|
if(ret){
|
|
printf("!\n");
|
|
return;
|
|
} else printf(" failed!\n");
|
|
}
|
|
if(_MAX_EXT>6){
|
|
i=0;
|
|
flag=0;
|
|
do {
|
|
snprintf(ips, 8, "%03d.ips", i);
|
|
_makepath(fname, drive, dir, name, ips);
|
|
if(!(patch_file = OPEN_STREAM (fname, "rb"))) break;
|
|
printf ("Using IPS patch %s", fname);
|
|
ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size);
|
|
CLOSE_STREAM(patch_file);
|
|
if(ret){
|
|
flag=1;
|
|
printf("!\n");
|
|
} else {
|
|
printf(" failed!\n");
|
|
break;
|
|
}
|
|
} while(++i<1000);
|
|
if(flag) return;
|
|
}
|
|
if(_MAX_EXT>3){
|
|
i=0;
|
|
flag=0;
|
|
do {
|
|
snprintf(ips, _MAX_EXT+2, "ips%d", i);
|
|
if(strlen(ips)>_MAX_EXT) break;
|
|
_makepath(fname, drive, dir, name, ips);
|
|
if(!(patch_file = OPEN_STREAM (fname, "rb"))) break;
|
|
printf ("Using IPS patch %s", fname);
|
|
ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size);
|
|
CLOSE_STREAM(patch_file);
|
|
if(ret){
|
|
flag=1;
|
|
printf("!\n");
|
|
} else {
|
|
printf(" failed!\n");
|
|
break;
|
|
}
|
|
} while(++i!=0);
|
|
if(flag) return;
|
|
}
|
|
if(_MAX_EXT>2){
|
|
i=0;
|
|
flag=0;
|
|
do {
|
|
snprintf(ips, 4, "ip%d", i);
|
|
_makepath(fname, drive, dir, name, ips);
|
|
if(!(patch_file = OPEN_STREAM (fname, "rb"))) break;
|
|
printf ("Using IPS patch %s", fname);
|
|
ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size);
|
|
CLOSE_STREAM(patch_file);
|
|
if(ret){
|
|
flag=1;
|
|
printf("!\n");
|
|
} else {
|
|
printf(" failed!\n");
|
|
break;
|
|
}
|
|
} while(++i<10);
|
|
if(flag) return;
|
|
}
|
|
|
|
#ifdef UNZIP_SUPPORT
|
|
if (strcasecmp(ext, "zip")==0) {
|
|
unzFile file=unzOpen(rom_filename);
|
|
if(file!=NULL){
|
|
int port=unzFindExtension(file, "ips");
|
|
while(port==UNZ_OK){
|
|
printf(" in %s", rom_filename);
|
|
ret=ReadIPSPatch(new unzReader(file), offset, rom_size);
|
|
unzCloseCurrentFile(file);
|
|
if(ret){
|
|
printf("!\n");
|
|
flag=1;
|
|
} else printf (" failed!\n");
|
|
port = unzFindExtension(file, "ips", false);
|
|
}
|
|
if(!flag){
|
|
i=0;
|
|
do {
|
|
snprintf(ips, _MAX_EXT+2, "ips%d", i);
|
|
if(strlen(ips)>_MAX_EXT) break;
|
|
if(unzFindExtension(file, ips)!=UNZ_OK) break;
|
|
printf(" in %s", rom_filename);
|
|
ret=ReadIPSPatch(new unzReader(file), offset, rom_size);
|
|
unzCloseCurrentFile(file);
|
|
if(ret){
|
|
flag=1;
|
|
printf("!\n");
|
|
} else {
|
|
printf(" failed!\n");
|
|
break;
|
|
}
|
|
if(unzFindExtension(file, ips, false, false)==UNZ_OK) printf("WARNING: Ignoring extra .%s files!\n", ips);
|
|
} while(++i!=0);
|
|
}
|
|
if(!flag){
|
|
i=0;
|
|
do {
|
|
snprintf(ips, 4, "ip%d", i);
|
|
if(unzFindExtension(file, ips)!=UNZ_OK) break;
|
|
printf(" in %s", rom_filename);
|
|
ret=ReadIPSPatch(new unzReader(file), offset, rom_size);
|
|
unzCloseCurrentFile(file);
|
|
if(ret){
|
|
flag=1;
|
|
printf("!\n");
|
|
} else {
|
|
printf(" failed!\n");
|
|
break;
|
|
}
|
|
if(unzFindExtension(file, ips, false, false)==UNZ_OK) printf("WARNING: Ignoring extra .%s files!\n", ips);
|
|
} while(++i<10);
|
|
}
|
|
assert(unzClose(file)==UNZ_OK);
|
|
if(flag) return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
const char *n;
|
|
n=S9xGetFilename(".ips", PATCH_DIR);
|
|
if((patch_file=OPEN_STREAM(n, "rb"))) {
|
|
printf("Using IPS patch %s", n);
|
|
ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size);
|
|
CLOSE_STREAM(patch_file);
|
|
if(ret){
|
|
printf("!\n");
|
|
return;
|
|
} else printf(" failed!\n");
|
|
}
|
|
if(_MAX_EXT>6){
|
|
i=0;
|
|
flag=0;
|
|
do {
|
|
snprintf(ips, 9, ".%03d.ips", i);
|
|
n=S9xGetFilename(ips, PATCH_DIR);
|
|
if(!(patch_file = OPEN_STREAM(n, "rb"))) break;
|
|
printf ("Using IPS patch %s", n);
|
|
ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size);
|
|
CLOSE_STREAM(patch_file);
|
|
if(ret){
|
|
flag=1;
|
|
printf("!\n");
|
|
} else {
|
|
printf(" failed!\n");
|
|
break;
|
|
}
|
|
} while(++i<1000);
|
|
if(flag) return;
|
|
}
|
|
if(_MAX_EXT>3){
|
|
i=0;
|
|
flag=0;
|
|
do {
|
|
snprintf(ips, _MAX_EXT+3, ".ips%d", i);
|
|
if(strlen(ips)>_MAX_EXT+1) break;
|
|
n=S9xGetFilename(ips, PATCH_DIR);
|
|
if(!(patch_file = OPEN_STREAM(n, "rb"))) break;
|
|
printf ("Using IPS patch %s", n);
|
|
ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size);
|
|
CLOSE_STREAM(patch_file);
|
|
if(ret){
|
|
flag=1;
|
|
printf("!\n");
|
|
} else {
|
|
printf(" failed!\n");
|
|
break;
|
|
}
|
|
} while(++i!=0);
|
|
if(flag) return;
|
|
}
|
|
if(_MAX_EXT>2){
|
|
i=0;
|
|
flag=0;
|
|
do {
|
|
snprintf(ips, 5, ".ip%d", i);
|
|
n=S9xGetFilename(ips, PATCH_DIR);
|
|
if(!(patch_file = OPEN_STREAM(n, "rb"))) break;
|
|
printf ("Using IPS patch %s", n);
|
|
ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size);
|
|
CLOSE_STREAM(patch_file);
|
|
if(ret){
|
|
flag=1;
|
|
printf("!\n");
|
|
} else {
|
|
printf(" failed!\n");
|
|
break;
|
|
}
|
|
} while(++i<10);
|
|
if(flag) return;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
void CMemory::ParseSNESHeader(uint8 *RomHeader)
|
|
{
|
|
bool8 bs = Settings.BS & !Settings.BSXItself;
|
|
|
|
strncpy(ROMName, (char *) &RomHeader[0x10], ROM_NAME_LEN - 1);
|
|
if (bs)
|
|
memset(ROMName + 16, 0x20, ROM_NAME_LEN - 17);
|
|
|
|
if (bs)
|
|
{
|
|
if (!(((RomHeader[0x29] & 0x20) && CalculatedSize < 0x100000) ||
|
|
(!(RomHeader[0x29] & 0x20) && CalculatedSize == 0x100000)))
|
|
printf("BS: Size mismatch\n");
|
|
|
|
// FIXME
|
|
int p = 0;
|
|
while ((1 << p) < (int) CalculatedSize)
|
|
p++;
|
|
ROMSize = p - 10;
|
|
}
|
|
else
|
|
ROMSize = RomHeader[0x27];
|
|
|
|
Memory.SRAMSize = bs ? 5 /* BS-X */: RomHeader[0x28];
|
|
|
|
ROMSpeed = bs ? RomHeader[0x28] : RomHeader[0x25];
|
|
ROMType = bs ? 0xE5 /* BS-X */ : RomHeader[0x26];
|
|
ROMRegion = bs ? 0 : RomHeader[0x29];
|
|
|
|
ROMChecksum = RomHeader[0x2E] + (RomHeader[0x2F] << 8);
|
|
ROMComplementChecksum = RomHeader[0x2C] + (RomHeader[0x2D] << 8);
|
|
|
|
memmove(ROMId, &RomHeader[0x02], 4);
|
|
|
|
if (RomHeader[0x2A] == 0x33)
|
|
memmove(CompanyId, &RomHeader[0x00], 2);
|
|
else
|
|
sprintf(CompanyId, "%02X", RomHeader[0x2A]);
|
|
}
|
|
|
|
#undef INLINE
|
|
#define INLINE
|
|
#include "getset.h"
|
|
|