2202 lines
52 KiB
C
Executable File
2202 lines
52 KiB
C
Executable File
/*
|
|
Copyright (C) 1997-2005 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
|
|
|
|
http://www.zsnes.com
|
|
http://sourceforge.net/projects/zsnes
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later
|
|
version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
|
|
|
|
#ifdef __UNIXSDL__
|
|
#include "gblhdr.h"
|
|
#define DIR_SLASH "/"
|
|
#else
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#define DIR_SLASH "\\"
|
|
#endif
|
|
#include "cpu/memtable.h"
|
|
#include "zip/zunzip.h"
|
|
#include "jma/zsnesjma.h"
|
|
#include "asm_call.h"
|
|
|
|
#ifndef __GNUC__
|
|
#define strcasecmp stricmp
|
|
#define strncasecmp strnicmp
|
|
#endif
|
|
|
|
//C++ style code in C
|
|
#define bool unsigned char
|
|
#define true 1
|
|
#define false 0
|
|
|
|
//NSRT Goodness
|
|
#define Lo 0x7FC0
|
|
#define Hi 0xFFC0
|
|
#define EHi 0x40FFC0
|
|
|
|
#define MB_bytes 0x100000
|
|
#define Mbit_bytes 0x20000
|
|
|
|
//Offsets to add to infoloc start to reach particular variable
|
|
#define BankOffset 21 //Contains Speed as well
|
|
#define TypeOffset 22
|
|
#define ROMSizeOffset 23
|
|
#define SRAMSizeOffset 24
|
|
#define CountryOffset 25
|
|
#define CompanyOffset 26
|
|
#define VersionOffset 27
|
|
#define InvCSLowOffset 28
|
|
#define InvCSHiOffset 29
|
|
#define CSLowOffset 30
|
|
#define CSHiOffset 31
|
|
//Additional defines for the BS header
|
|
#define BSYearOffset 21 //Not sure how to calculate year yet
|
|
#define BSMonthOffset 22
|
|
#define BSDayOffset 23
|
|
#define BSBankOffset 24
|
|
#define BSSizeOffset 25 //Contains Type as well
|
|
//26 - 31 is the same
|
|
|
|
// Some archaic code from an unfinished Dynarec
|
|
extern unsigned int curexecstate;
|
|
extern unsigned char spcon;
|
|
|
|
void procexecloop()
|
|
{
|
|
curexecstate &= 0xFFFFFF00;
|
|
|
|
if (spcon) { curexecstate += 3; }
|
|
else { curexecstate += 1; }
|
|
}
|
|
|
|
void Debug_WriteString(char *str)
|
|
{
|
|
FILE *fp = 0;
|
|
fp = fopen("zsnes.dbg", "w");
|
|
if (!fp) { return; }
|
|
fputs(str, fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
//I want to port over the more complicated
|
|
//functions from init.asm, or replace with
|
|
//better versions from NSRT. -Nach
|
|
|
|
//init.asm goodness
|
|
extern unsigned int NumofBanks;
|
|
extern unsigned int NumofBytes;
|
|
extern unsigned int *romdata;
|
|
extern unsigned char romtype;
|
|
extern unsigned char Interleaved;
|
|
|
|
unsigned int maxromspace;
|
|
unsigned int curromspace;
|
|
unsigned int infoloc;
|
|
unsigned int ramsize;
|
|
unsigned int ramsizeand;
|
|
|
|
bool SplittedROM;
|
|
unsigned int addOnStart;
|
|
unsigned int addOnSize;
|
|
|
|
|
|
//Deinterleave functions
|
|
bool validChecksum(unsigned char *ROM, int BankLoc)
|
|
{
|
|
if (ROM[BankLoc + InvCSLowOffset] + (ROM[BankLoc + InvCSHiOffset] << 8) +
|
|
ROM[BankLoc + CSLowOffset] + (ROM[BankLoc + CSHiOffset] << 8) == 0xFFFF)
|
|
{
|
|
return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
bool EHiHeader(unsigned char *ROM, int BankLoc)
|
|
{
|
|
if (validChecksum(ROM, BankLoc) && ROM[BankLoc+BankOffset] == 53)
|
|
{
|
|
return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
void SwapData(unsigned int *loc1, unsigned int *loc2, unsigned int amount)
|
|
{
|
|
unsigned int temp, i;
|
|
for (i = 0; i < amount; i++)
|
|
{
|
|
temp = loc1[i];
|
|
loc1[i] = loc2[i];
|
|
loc2[i] = temp;
|
|
}
|
|
}
|
|
|
|
void swapBlocks(char *blocks)
|
|
{
|
|
unsigned int i, j;
|
|
for (i = 0; i < NumofBanks; i++)
|
|
{
|
|
for (j = 0; j < NumofBanks; j++)
|
|
{
|
|
if (blocks[j] == (char)i)
|
|
{
|
|
char b;
|
|
SwapData(romdata + blocks[i]*0x2000, romdata + blocks[j]*0x2000, 0x2000);
|
|
b = blocks[j];
|
|
blocks[j] = blocks[i];
|
|
blocks[i] = b;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void deintlv1()
|
|
{
|
|
char blocks[256];
|
|
int i, numblocks = NumofBanks/2;
|
|
for (i = 0; i < numblocks; i++)
|
|
{
|
|
blocks[i * 2] = i + numblocks;
|
|
blocks[i * 2 + 1] = i;
|
|
}
|
|
swapBlocks(blocks);
|
|
}
|
|
|
|
void CheckIntl1(unsigned char *ROM)
|
|
{
|
|
unsigned int ROMmidPoint = NumofBytes / 2;
|
|
if (validChecksum(ROM, ROMmidPoint + Lo) &&
|
|
!validChecksum(ROM, Lo) &&
|
|
ROM[ROMmidPoint+Lo+CountryOffset] < 14) //Country Code
|
|
{
|
|
deintlv1();
|
|
Interleaved = true;
|
|
}
|
|
else if (validChecksum(ROM, Lo) && !validChecksum(ROM, Hi) &&
|
|
ROM[Lo+CountryOffset] < 14 && //Country code
|
|
//Rom make up
|
|
(ROM[Lo+BankOffset] == 33 || ROM[Lo+BankOffset] == 49 ||
|
|
ROM[Lo+BankOffset] == 53 || ROM[Lo+BankOffset] == 58))
|
|
{
|
|
if (ROM[Lo+20] == 32 ||//Check that Header name did not overflow
|
|
!(ROM[Lo+BankOffset] == ROM[Lo+20] || ROM[Lo+BankOffset] == ROM[Lo+19] ||
|
|
ROM[Lo+BankOffset] == ROM[Lo+18] || ROM[Lo+BankOffset] == ROM[Lo+17]))
|
|
{
|
|
deintlv1();
|
|
Interleaved = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CheckIntlEHi(unsigned char *ROM)
|
|
{
|
|
if (EHiHeader(ROM, Lo))
|
|
{
|
|
unsigned int oldNumBanks = NumofBanks;
|
|
|
|
//Swap 4MB ROM with the other one
|
|
SwapData(romdata, romdata+((NumofBytes-0x400000)/4), 0x100000);
|
|
|
|
//Deinterleave the 4MB ROM first
|
|
NumofBanks = 128;
|
|
deintlv1();
|
|
|
|
//Now the other one
|
|
NumofBanks = oldNumBanks - 128;
|
|
romdata += 0x100000; //Ofset pointer
|
|
deintlv1();
|
|
|
|
//Now fix the data and we're done
|
|
NumofBanks = oldNumBanks;
|
|
romdata -= 0x100000;
|
|
|
|
Interleaved = true;
|
|
}
|
|
}
|
|
|
|
//These two functions interleave, yes interleave, because ZSNES has it's large ROM map backwards
|
|
void intlv1()
|
|
{
|
|
char blocks[256];
|
|
int i, numblocks = NumofBanks/2;
|
|
for (i = 0; i < numblocks; i++)
|
|
{
|
|
blocks[i + numblocks] = i * 2;
|
|
blocks[i] = i * 2 + 1;
|
|
}
|
|
swapBlocks(blocks);
|
|
}
|
|
|
|
//This is a mess, I wish we didn't need this, but it kicks the old asm code
|
|
void IntlEHi()
|
|
{
|
|
SwapData(romdata, romdata + 0x100000, 0x80000);
|
|
SwapData(romdata + 0x80000, romdata + 0x100000, 0x80000);
|
|
|
|
NumofBanks = 64;
|
|
intlv1();
|
|
NumofBanks = 192;
|
|
}
|
|
|
|
//ROM loading functions, which some strangly enough were in guiload.inc
|
|
bool AllASCII(unsigned char *b, int size)
|
|
{
|
|
int i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
if (b[i] < 32 || b[i] > 126)
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
return(true);
|
|
}
|
|
|
|
int InfoScore(unsigned char *Buffer)
|
|
{
|
|
int score = 0;
|
|
if (validChecksum(Buffer, 0)) { score += 4; }
|
|
if (Buffer[CompanyOffset] == 0x33) { score += 2; }
|
|
if (!(Buffer[61] & 0x80)) { score -= 4; }
|
|
if ((1 << (Buffer[ROMSizeOffset] - 7)) > 48) { score -= 1; }
|
|
if (Buffer[CountryOffset] < 14) { score += 1; }
|
|
if (!AllASCII(Buffer, 20)) { score -= 1; }
|
|
return(score);
|
|
}
|
|
|
|
extern unsigned char ForceHiLoROM;
|
|
extern unsigned char forceromtype;
|
|
|
|
void BankCheck()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
infoloc = 0;
|
|
Interleaved = false;
|
|
|
|
if (NumofBytes >= 0x500000)
|
|
{
|
|
//Deinterleave if neccesary
|
|
CheckIntlEHi(ROM);
|
|
|
|
if (EHiHeader(ROM, EHi))
|
|
{
|
|
romtype = 2;
|
|
infoloc = EHi;
|
|
}
|
|
}
|
|
|
|
if (!infoloc)
|
|
{
|
|
static bool CommandLineForce2 = false;
|
|
int loscore, hiscore;
|
|
|
|
//Deinterleave if neccesary
|
|
CheckIntl1(ROM);
|
|
|
|
loscore = InfoScore(ROM+Lo);
|
|
hiscore = InfoScore(ROM+Hi);
|
|
|
|
switch(ROM[Lo + BankOffset])
|
|
{
|
|
case 32: case 35: case 48: case 50:
|
|
loscore += 2;
|
|
case 128: case 156: case 176: case 188: case 252: //BS
|
|
loscore += 1;
|
|
break;
|
|
}
|
|
switch(ROM[Hi + BankOffset])
|
|
{
|
|
case 33: case 49: case 53: case 58:
|
|
hiscore += 2;
|
|
case 128: case 156: case 176: case 188: case 252: //BS
|
|
hiscore += 1;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Force code.
|
|
ForceHiLoROM is from the GUI.
|
|
forceromtype is from Command line, we have a static var
|
|
to prevent forcing a secong game loaded from the GUI when
|
|
the first was loaded from the command line with forcing.
|
|
*/
|
|
if (ForceHiLoROM == 1 ||
|
|
(forceromtype == 1 && !CommandLineForce2))
|
|
{
|
|
CommandLineForce2 = true;
|
|
loscore += 50;
|
|
}
|
|
else if (ForceHiLoROM == 2 ||
|
|
(forceromtype == 2 && !CommandLineForce2))
|
|
{
|
|
CommandLineForce2 = true;
|
|
hiscore += 50;
|
|
}
|
|
|
|
if (hiscore > loscore)
|
|
{
|
|
romtype = 2;
|
|
infoloc = Hi;
|
|
}
|
|
else
|
|
{
|
|
romtype = 1;
|
|
infoloc = Lo;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Chip detection functions
|
|
bool CHIPBATT;
|
|
bool BSEnable;
|
|
bool C4Enable;
|
|
bool DSP1Enable;
|
|
bool DSP2Enable;
|
|
bool DSP3Enable;
|
|
bool DSP4Enable;
|
|
bool OBCEnable;
|
|
bool RTCEnable;
|
|
bool SA1Enable;
|
|
bool SDD1Enable;
|
|
bool SETAEnable; //ST010 & 11
|
|
bool SFXEnable;
|
|
bool SGBEnable;
|
|
bool SPC7110Enable;
|
|
bool ST18Enable;
|
|
|
|
bool valid_normal_bank(unsigned char bankbyte)
|
|
{
|
|
switch (bankbyte)
|
|
{
|
|
case 32: case 33: case 48: case 49:
|
|
return(true);
|
|
break;
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
void chip_detect()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
C4Enable = false;
|
|
RTCEnable = false;
|
|
SA1Enable = false;
|
|
SDD1Enable = false;
|
|
OBCEnable = false;
|
|
CHIPBATT = false;
|
|
SGBEnable = false;
|
|
ST18Enable = false;
|
|
DSP1Enable = false;
|
|
DSP2Enable = false;
|
|
DSP3Enable = false;
|
|
DSP4Enable = false;
|
|
SPC7110Enable = false;
|
|
BSEnable = false;
|
|
SFXEnable = false;
|
|
SETAEnable = false;
|
|
|
|
//DSP Family
|
|
if (ROM[infoloc+TypeOffset] == 3)
|
|
{
|
|
if (ROM[infoloc+BankOffset] == 48)
|
|
{
|
|
DSP4Enable = true;
|
|
}
|
|
else
|
|
{
|
|
DSP1Enable = true;
|
|
}
|
|
return;
|
|
}
|
|
if (ROM[infoloc+TypeOffset] == 5)
|
|
{
|
|
CHIPBATT = true;
|
|
if (ROM[infoloc+BankOffset] == 32)
|
|
{
|
|
DSP2Enable = true;
|
|
}
|
|
else if (ROM[infoloc+BankOffset] == 48 && ROM[infoloc+CompanyOffset] == 0xB2) //Bandai
|
|
{
|
|
DSP3Enable = true;
|
|
}
|
|
else
|
|
{
|
|
DSP1Enable = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
switch((unsigned short)ROM[infoloc+BankOffset] | (ROM[infoloc+TypeOffset] << 8))
|
|
{
|
|
case 0x1320: //Mario Chip 1
|
|
case 0x1420: //GSU-x
|
|
SFXEnable = true;
|
|
return;
|
|
break;
|
|
|
|
|
|
case 0x1520: //GSU-x + Battery
|
|
case 0x1A20: //GSU-1 + Battery + Start in 21MHz
|
|
SFXEnable = true;
|
|
CHIPBATT = true;
|
|
return;
|
|
break;
|
|
|
|
case 0x2530:
|
|
OBCEnable = true;
|
|
CHIPBATT = true;
|
|
return;
|
|
break;
|
|
|
|
case 0x3423:
|
|
SA1Enable = true;
|
|
return;
|
|
break;
|
|
|
|
case 0x3523:
|
|
SA1Enable = true;
|
|
CHIPBATT = true;
|
|
return;
|
|
break;
|
|
|
|
case 0x4332:
|
|
SDD1Enable = true;
|
|
return;
|
|
break;
|
|
|
|
case 0x4532:
|
|
SDD1Enable = true;
|
|
CHIPBATT = true;
|
|
return;
|
|
break;
|
|
|
|
case 0x5535:
|
|
RTCEnable = true;
|
|
CHIPBATT = true;
|
|
return;
|
|
break;
|
|
|
|
case 0xE320:
|
|
SGBEnable = true;
|
|
return;
|
|
break;
|
|
|
|
case 0xF320:
|
|
C4Enable = true;
|
|
return;
|
|
break;
|
|
|
|
case 0xF530:
|
|
ST18Enable = true;
|
|
CHIPBATT = true; //Check later if this should be removed
|
|
return;
|
|
break;
|
|
|
|
case 0xF53A:
|
|
SPC7110Enable = true;
|
|
CHIPBATT = true;
|
|
return;
|
|
break;
|
|
|
|
case 0xF630:
|
|
SETAEnable = true;
|
|
CHIPBATT = true;
|
|
return;
|
|
break;
|
|
|
|
case 0xF93A:
|
|
SPC7110Enable = true;
|
|
RTCEnable = true;
|
|
CHIPBATT = true;
|
|
return;
|
|
break;
|
|
}
|
|
|
|
//BS Dump
|
|
if ((ROM[infoloc+CompanyOffset] == 0x33 || ROM[infoloc+CompanyOffset] == 0xFF) &&
|
|
(!ROM[infoloc+BSYearOffset] || (ROM[infoloc+BSYearOffset] & 131) == 128) &&
|
|
valid_normal_bank(ROM[infoloc+BSBankOffset]))
|
|
{
|
|
unsigned char m = ROM[infoloc+BSMonthOffset];
|
|
if (!m && !ROM[infoloc+BSDayOffset])
|
|
{
|
|
//BS Add-on cart
|
|
return;
|
|
}
|
|
if ((m == 0xFF && ROM[infoloc+BSDayOffset] == 0xFF) ||
|
|
(!(m & 0xF) && ((m >> 4) - 1 < 12)))
|
|
{
|
|
BSEnable = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//Checksum functions
|
|
unsigned short sum(unsigned char *array, unsigned int size)
|
|
{
|
|
unsigned short theSum = 0;
|
|
unsigned int i;
|
|
|
|
//Prevent crashing by reading too far (needed for messed up ROMs)
|
|
if (array + size > (unsigned char *)romdata + maxromspace)
|
|
{
|
|
return(0xFFFF);
|
|
}
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
theSum += array[i];
|
|
}
|
|
return(theSum);
|
|
}
|
|
|
|
extern unsigned short Checksumvalue;
|
|
void CalcChecksum()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
if (SplittedROM)
|
|
{
|
|
Checksumvalue = sum(ROM+addOnStart, addOnSize);
|
|
Checksumvalue -= sum(ROM+infoloc+addOnStart-16, 48);
|
|
}
|
|
else if (SPC7110Enable)
|
|
{
|
|
Checksumvalue = sum(ROM, NumofBytes);
|
|
if (NumofBytes == 0x300000) //Fix for 24Mb SPC7110 ROMs
|
|
{
|
|
Checksumvalue += Checksumvalue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Checksumvalue = sum(ROM, curromspace);
|
|
if (NumofBanks > 128 && maxromspace == 6*MB_bytes)
|
|
{
|
|
Checksumvalue += sum(ROM+4*MB_bytes, 2*MB_bytes);
|
|
}
|
|
if (BSEnable)
|
|
{
|
|
Checksumvalue -= sum(&ROM[infoloc - 16], 48); //Fix for BS Dumps
|
|
}
|
|
}
|
|
}
|
|
|
|
//Misc functions
|
|
void MirrorROM()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
unsigned int size, StartMirror = 0, ROMSize = curromspace;
|
|
//This will mirror up non power of two ROMs to powers of two
|
|
for (size = 1; size <= 64; size +=size)
|
|
{
|
|
unsigned int fullSize = size * Mbit_bytes,
|
|
halfSize = fullSize >> 1;
|
|
if ((ROMSize > halfSize) && (ROMSize < fullSize))
|
|
{
|
|
for (StartMirror = halfSize;
|
|
ROMSize < fullSize && ROMSize < maxromspace;)
|
|
{
|
|
ROM[ROMSize++] = ROM[StartMirror++];
|
|
}
|
|
curromspace = ROMSize;
|
|
break;
|
|
}
|
|
}
|
|
//This will mirror (now) full sized ROMs through the ROM buffer
|
|
for (StartMirror = 0; ROMSize < maxromspace;)
|
|
{
|
|
ROM[ROMSize++] = ROM[StartMirror++];
|
|
}
|
|
|
|
NumofBanks = curromspace >> 15;
|
|
}
|
|
|
|
void SetupSramSize()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
if (BSEnable)
|
|
{
|
|
ramsize = 0;
|
|
}
|
|
else if (SFXEnable)
|
|
{
|
|
if (ROM[infoloc+CompanyOffset] == 0x33) //Extended header
|
|
{
|
|
ramsize = 8 << ((unsigned int)ROM[infoloc-3]);
|
|
}
|
|
else
|
|
{
|
|
ramsize = 256;
|
|
}
|
|
}
|
|
else if (SETAEnable)
|
|
{
|
|
ramsize = 32;
|
|
}
|
|
else
|
|
{
|
|
ramsize = ((ROM[infoloc+SRAMSizeOffset]) ? (8 << ((unsigned int)ROM[infoloc+SRAMSizeOffset])) : 0);
|
|
}
|
|
//Convert from Kb to bytes;
|
|
ramsize *= 128;
|
|
ramsizeand = ramsize-1;
|
|
}
|
|
|
|
//File loading code
|
|
extern char *ZOpenFileName;
|
|
bool Header512;
|
|
|
|
|
|
extern char CSStatus[40];
|
|
extern char CSStatus2[40];
|
|
extern char CSStatus3[40];
|
|
extern bool RomInfo;
|
|
char *lastROMFileName;
|
|
void DumpROMLoadInfo()
|
|
{
|
|
FILE *fp = 0;
|
|
|
|
if (RomInfo) //rominfo.txt info dumping enabled?
|
|
{
|
|
fp = fopen("rominfo.txt", "w");
|
|
if (!fp) { return; }
|
|
fputs("This is the info for the last game you ran.\n\nFile: ", fp);
|
|
fputs(lastROMFileName, fp);
|
|
fputs(" Header: ", fp);
|
|
fputs(Header512 ? "Yes\n" : "No\n", fp);
|
|
fputs(CSStatus, fp);
|
|
fputs("\n", fp);
|
|
fputs(CSStatus2, fp);
|
|
fputs("\n", fp);
|
|
fputs(CSStatus3, fp);
|
|
fputs("\n", fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void loadFile(char *filename)
|
|
{
|
|
bool multifile = false;
|
|
char *incrementer = 0;
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
if (strlen(filename) >= 3) //Char + ".1"
|
|
{
|
|
char *ext = filename+strlen(filename)-2;
|
|
if (!strcmp(ext, ".1") || !strcasecmp(ext, ".A"))
|
|
{
|
|
incrementer = ext + 1;
|
|
multifile = true;
|
|
}
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
struct stat stat_results;
|
|
stat(filename, &stat_results);
|
|
|
|
if ((unsigned int)stat_results.st_size <= maxromspace+512-curromspace)
|
|
{
|
|
FILE *fp = 0;
|
|
fp = fopen(filename, "rb");
|
|
|
|
if (!fp) { return; }
|
|
|
|
if (curromspace && ((stat_results.st_size & 0x7FFF) == 512))
|
|
{
|
|
stat_results.st_size -= 512;
|
|
fseek(fp, 512, SEEK_SET);
|
|
}
|
|
|
|
fread(ROM+curromspace, stat_results.st_size, 1, fp);
|
|
fclose(fp);
|
|
|
|
curromspace += stat_results.st_size;
|
|
|
|
if (!multifile) { return; }
|
|
|
|
(*incrementer)++;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void loadGZipFile(char *filename)
|
|
{
|
|
int size, err;
|
|
gzFile GZipFile;
|
|
FILE *fp = 0;
|
|
fp = fopen(filename, "rb");
|
|
if (!fp) { return; }
|
|
fseek(fp, -4, SEEK_END);
|
|
//Size is read like this due to VC screwing up with optimizations
|
|
size = fgetc(fp);
|
|
size |= fgetc(fp) << 8;
|
|
size |= fgetc(fp) << 16;
|
|
size |= fgetc(fp) << 24;
|
|
fclose(fp);
|
|
|
|
if ((unsigned int)size > maxromspace+512) { return; }
|
|
|
|
//Open GZip file for decompression
|
|
GZipFile = gzopen(filename, "rb");
|
|
|
|
//Decompress file into memory
|
|
err = gzread(GZipFile, romdata, size);
|
|
|
|
//Close compressed file
|
|
gzclose(GZipFile);
|
|
|
|
if (err != size) { return; }
|
|
|
|
curromspace = size;
|
|
}
|
|
|
|
//void Output_Text();
|
|
//asm volatile("movl _ZOpenFileName, %edx \n"
|
|
// "movb $9, %ah \n"
|
|
// "call _Output_Text \n");
|
|
//system("pause");
|
|
|
|
void loadZipFile(char *filename)
|
|
{
|
|
int err, fileSize;
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
bool multifile = false, NSS = false;
|
|
char *incrementer = 0;
|
|
|
|
unzFile zipfile = unzOpen(filename); //Open zip file
|
|
int cFile = unzGoToFirstFile(zipfile); //Set cFile to first compressed file
|
|
unz_file_info cFileInfo; //Create variable to hold info for a compressed file
|
|
|
|
int LargestGoodFile = 0; //To keep track of largest file
|
|
|
|
//Variables for the file we pick
|
|
char ourFile[256];
|
|
ourFile[0] = '\n';
|
|
|
|
while(cFile == UNZ_OK) //While not at end of compressed file list
|
|
{
|
|
//Temporary char array for file name
|
|
char cFileName[256];
|
|
|
|
//Gets info on current file, and places it in cFileInfo
|
|
unzGetCurrentFileInfo(zipfile, &cFileInfo, cFileName, 256, NULL, 0, NULL, 0);
|
|
|
|
//Get the file's size
|
|
fileSize = cFileInfo.uncompressed_size;
|
|
|
|
//Find split files
|
|
if (strlen(cFileName) >= 3) //Char + ".1"
|
|
{
|
|
char *ext = cFileName+strlen(cFileName)-2;
|
|
if (!strcmp(ext, ".1") || !strcasecmp(ext, ".A"))
|
|
{
|
|
strcpy(ourFile, cFileName);
|
|
incrementer = ourFile+strlen(ourFile)-1;
|
|
multifile = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Find Nintendo Super System ROMs
|
|
if (strlen(cFileName) >= 5) //Char + ".IC2"
|
|
{
|
|
char *ext = cFileName+strlen(cFileName)-4;
|
|
if (!strncasecmp(ext, ".IC", 3))
|
|
{
|
|
strcpy(ourFile, cFileName);
|
|
incrementer = ourFile+strlen(ourFile)-1;
|
|
*incrementer = '7';
|
|
NSS = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Check for valid ROM based on size
|
|
if (((unsigned int)fileSize <= maxromspace+512) &&
|
|
(fileSize > LargestGoodFile))
|
|
{
|
|
strcpy(ourFile, cFileName);
|
|
LargestGoodFile = fileSize;
|
|
}
|
|
|
|
//Go to next file in zip file
|
|
cFile = unzGoToNextFile(zipfile);
|
|
}
|
|
|
|
//No files found
|
|
if (ourFile[0] == '\n')
|
|
{
|
|
unzClose(zipfile);
|
|
return;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
//Sets current file to the file we liked before
|
|
if (unzLocateFile(zipfile, ourFile, 1) != UNZ_OK)
|
|
{
|
|
if (NSS)
|
|
{
|
|
(*incrementer)--;
|
|
continue;
|
|
}
|
|
unzClose(zipfile);
|
|
return;
|
|
}
|
|
|
|
//Gets info on current file, and places it in cFileInfo
|
|
unzGetCurrentFileInfo(zipfile, &cFileInfo, ourFile, 256, NULL, 0, NULL, 0);
|
|
|
|
//Get the file's size
|
|
fileSize = cFileInfo.uncompressed_size;
|
|
|
|
//Too big?
|
|
if (curromspace + fileSize > maxromspace+512)
|
|
{
|
|
unzClose(zipfile);
|
|
return;
|
|
}
|
|
|
|
//Open file
|
|
unzOpenCurrentFile(zipfile);
|
|
|
|
//Read file into memory
|
|
err = unzReadCurrentFile(zipfile, ROM+curromspace, fileSize);
|
|
|
|
//Close file
|
|
unzCloseCurrentFile(zipfile);
|
|
|
|
//Encountered error?
|
|
if (err != fileSize)
|
|
{
|
|
unzClose(zipfile);
|
|
return;
|
|
}
|
|
|
|
if (curromspace && ((fileSize & 0x7FFF) == 512))
|
|
{
|
|
fileSize -= 512;
|
|
memmove(ROM+curromspace, ROM+curromspace+512, fileSize);
|
|
}
|
|
|
|
curromspace += fileSize;
|
|
|
|
if (NSS)
|
|
{
|
|
if (!*incrementer) { return; }
|
|
(*incrementer)--;
|
|
continue;
|
|
}
|
|
|
|
if (!multifile)
|
|
{
|
|
unzClose(zipfile);
|
|
return;
|
|
}
|
|
(*incrementer)++;
|
|
}
|
|
}
|
|
|
|
void load_file_fs(char *path)
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
unsigned int pathlen = strlen(path);
|
|
const char *ext = path+pathlen-4;
|
|
if (pathlen >= 5 && !strcasecmp(ext, ".jma"))
|
|
{
|
|
load_jma_file(path);
|
|
}
|
|
else if (pathlen >= 5 && !strcasecmp(ext, ".zip"))
|
|
{
|
|
loadZipFile(path);
|
|
}
|
|
else if (pathlen >= 4 && !strcasecmp(ext+1, ".gz"))
|
|
{
|
|
loadGZipFile(path);
|
|
}
|
|
else
|
|
{
|
|
loadFile(path);
|
|
}
|
|
|
|
if ((curromspace & 0x7FFF) == 512)
|
|
{
|
|
memmove(ROM, ROM+512, addOnStart);
|
|
curromspace -= 512;
|
|
}
|
|
}
|
|
|
|
char *STCart2 = 0;
|
|
void SplitSetup(char *basepath, char *basefile, unsigned int MirrorSystem)
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
curromspace = 0;
|
|
if (maxromspace < addOnStart+addOnSize) { return; }
|
|
memcpy(ROM+addOnStart, ROM, addOnSize);
|
|
|
|
if (STCart2)
|
|
{
|
|
if (maxromspace < 0x300000) { return; }
|
|
curromspace = 0;
|
|
load_file_fs(STCart2);
|
|
memcpy(ROM+0x200000, ROM, addOnSize);
|
|
curromspace = 0;
|
|
}
|
|
|
|
if (!*basepath)
|
|
{
|
|
load_file_fs(basefile);
|
|
}
|
|
else
|
|
{
|
|
load_file_fs(basepath);
|
|
}
|
|
|
|
if (!curromspace) { return; }
|
|
|
|
switch (MirrorSystem)
|
|
{
|
|
case 1:
|
|
memcpy(ROM+0x100000, ROM, 0x100000); //Mirror 8 to 16
|
|
break;
|
|
|
|
case 2:
|
|
memcpy(ROM+0x180000, ROM+0x100000, 0x80000); //Mirrors 12 to 16
|
|
memcpy(ROM+0x200000, ROM+0x400000, 0x80000); //Copy base over
|
|
memset(ROM+0x280000, 0, 0x180000); //Blank out rest
|
|
break;
|
|
|
|
case 3:
|
|
memcpy(ROM+0x40000, ROM, 0x40000);
|
|
memcpy(ROM+0x80000, ROM, 0x80000);
|
|
if (STCart2 && addOnSize < 0x100000)
|
|
{
|
|
memcpy(ROM+0x180000, ROM+0x100000, 0x80000);
|
|
memcpy(ROM+0x280000, ROM+0x200000, 0x80000);
|
|
}
|
|
break;
|
|
}
|
|
|
|
curromspace = addOnStart+addOnSize;
|
|
if (STCart2)
|
|
{
|
|
curromspace = 0x300000;
|
|
}
|
|
SplittedROM = true;
|
|
}
|
|
|
|
extern char STPath[1024];
|
|
extern char GNextPath[1024];
|
|
extern char SGPath[1024];
|
|
void SplitSupport()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
SplittedROM = false;
|
|
|
|
//Same Game add on
|
|
if (ROM[Hi+CompanyOffset] == 0x33 && curromspace == 0x80000 &&
|
|
!ROM[Hi+BankOffset] && !ROM[Hi+BSMonthOffset] && !ROM[Hi+BSDayOffset])
|
|
{
|
|
addOnStart = 0x200000;
|
|
addOnSize = 0x80000;
|
|
SplitSetup(SGPath, "SAMEGAME.ZIP", 1);
|
|
}
|
|
|
|
//SD Gundam G-Next add on
|
|
if (ROM[Lo+CompanyOffset] == 0x33 && curromspace == 0x80000 &&
|
|
!ROM[Lo+BankOffset] && !ROM[Lo+BSMonthOffset] && !ROM[Lo+BSDayOffset] && !strncmp(ROM+Lo, "GNEXT", 5))
|
|
{
|
|
addOnStart = 0x400000;
|
|
addOnSize = 0x80000;
|
|
SplitSetup(GNextPath, "G-NEXT.ZIP", 2);
|
|
addOnStart = 0x200000;
|
|
}
|
|
|
|
//Sufami Turbo
|
|
if (!strncmp(ROM, "BANDAI SFC-ADX", 14))
|
|
{
|
|
addOnStart = 0x100000;
|
|
addOnSize = curromspace;
|
|
SplitSetup(STPath, "STBIOS.ZIP", 3);
|
|
}
|
|
}
|
|
|
|
bool NSRTHead(unsigned char *ROM)
|
|
{
|
|
unsigned char *NSRTHead = ROM + 0x1D0; //NSRT Header Location
|
|
|
|
if (!strncmp("NSRT", (char*)&NSRTHead[24],4) && NSRTHead[28] == 22)
|
|
{
|
|
if ((sum(NSRTHead, 32) & 0xFF) != NSRTHead[30] ||
|
|
NSRTHead[30] + NSRTHead[31] != 255 ||
|
|
(NSRTHead[0] & 0x0F) > 13 ||
|
|
((NSRTHead[0] & 0xF0) >> 4) > 3 ||
|
|
((NSRTHead[0] & 0xF0) >> 4) == 0)
|
|
{
|
|
return(false); //Corrupt
|
|
}
|
|
return(true); //NSRT header
|
|
}
|
|
return(false); //None
|
|
}
|
|
|
|
extern bool EMUPause;
|
|
extern bool Sup48mbit;
|
|
extern bool Sup16mbit;
|
|
extern unsigned char snesmouse;
|
|
unsigned char snesinputdefault;
|
|
bool input1gp;
|
|
bool input1mouse;
|
|
bool input2gp;
|
|
bool input2mouse;
|
|
bool input2scope;
|
|
bool input2just;
|
|
void findZipIPS(char *);
|
|
void loadROM()
|
|
{
|
|
bool isCompressed = false, isZip = false;
|
|
|
|
EMUPause = false;
|
|
curromspace = 0;
|
|
|
|
maxromspace = 4194304;
|
|
if (Sup48mbit) { maxromspace += 2097152; }
|
|
if (Sup16mbit) { maxromspace -= 2097152; } //I don't get it either
|
|
|
|
lastROMFileName = ZOpenFileName;
|
|
|
|
if (strlen(ZOpenFileName) >= 5) //Char + ".jma"
|
|
{
|
|
char *ext = ZOpenFileName+strlen(ZOpenFileName)-4;
|
|
if (!strcasecmp(ext, ".jma"))
|
|
{
|
|
isCompressed = true;
|
|
load_jma_file(ZOpenFileName);
|
|
}
|
|
}
|
|
|
|
if (strlen(ZOpenFileName) >= 5) //Char + ".zip"
|
|
{
|
|
char *ext = ZOpenFileName+strlen(ZOpenFileName)-4;
|
|
if (!strcasecmp(ext, ".zip"))
|
|
{
|
|
isCompressed = true;
|
|
isZip = true;
|
|
loadZipFile(ZOpenFileName);
|
|
}
|
|
}
|
|
|
|
if (strlen(ZOpenFileName) >= 4) //Char + ".gz"
|
|
{
|
|
char *ext = ZOpenFileName+strlen(ZOpenFileName)-3;
|
|
if (!strcasecmp(ext, ".gz"))
|
|
{
|
|
isCompressed = true;
|
|
loadGZipFile(ZOpenFileName);
|
|
}
|
|
}
|
|
|
|
if (!isCompressed) { loadFile(ZOpenFileName); }
|
|
|
|
Header512 = false;
|
|
|
|
if (!curromspace) { return; }
|
|
|
|
if (!strncmp("GAME DOCTOR SF 3", (char *)romdata, 16) ||
|
|
!strncmp("SUPERUFO", (char *)romdata+8, 8))
|
|
{
|
|
Header512 = true;
|
|
}
|
|
else
|
|
{
|
|
int HeadRemain = (curromspace & 0x7FFF);
|
|
switch(HeadRemain)
|
|
{
|
|
case 0:
|
|
break;
|
|
|
|
case 512:
|
|
Header512 = true;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
//SMC/SWC header
|
|
if (ROM[8] == 0xAA && ROM[9]==0xBB && ROM[10]== 4)
|
|
{
|
|
Header512 = true;
|
|
}
|
|
//FIG header
|
|
else if ((ROM[4] == 0x77 && ROM[5] == 0x83) ||
|
|
(ROM[4] == 0xDD && ROM[5] == 0x82) ||
|
|
(ROM[4] == 0xDD && ROM[5] == 2) ||
|
|
(ROM[4] == 0xF7 && ROM[5] == 0x83) ||
|
|
(ROM[4] == 0xFD && ROM[5] == 0x82) ||
|
|
(ROM[4] == 0x00 && ROM[5] == 0x80) ||
|
|
(ROM[4] == 0x47 && ROM[5] == 0x83) ||
|
|
(ROM[4] == 0x11 && ROM[5] == 2))
|
|
{
|
|
Header512 = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
snesmouse = 0;
|
|
input1gp = true;
|
|
input1mouse = true;
|
|
input2gp = true;
|
|
input2mouse = true;
|
|
input2scope = true;
|
|
input2just = true;
|
|
|
|
if (Header512)
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
if (NSRTHead(ROM))
|
|
{
|
|
switch (ROM[0x1ED])
|
|
{
|
|
default: break;
|
|
|
|
case 0:
|
|
input1mouse = false;
|
|
input2mouse = false;
|
|
input2scope = false;
|
|
input2just = false;
|
|
break;
|
|
|
|
case 0x01: //Mouse port 2
|
|
snesmouse = 2;
|
|
input2gp = false;
|
|
input2scope = false;
|
|
input2just = false;
|
|
input1mouse = false;
|
|
break;
|
|
|
|
case 0x03: //Super Scope port 2
|
|
snesmouse = 3;
|
|
input2gp = false;
|
|
input2mouse = false;
|
|
input2just = false;
|
|
input1mouse = false;
|
|
break;
|
|
|
|
case 0x04: //Super Scope or Gamepad port 2
|
|
snesmouse = 3;
|
|
input2mouse = false;
|
|
input2just = false;
|
|
input1mouse = false;
|
|
break;
|
|
|
|
case 0x05: //Justifier (Lethal Enforcer gun) port 2
|
|
snesmouse = 4;
|
|
input2mouse = false;
|
|
input2scope = false;
|
|
input1mouse = false;
|
|
break;
|
|
|
|
case 0x06: //Multitap port 2
|
|
input2gp = false;
|
|
input2mouse = false;
|
|
input2just = false;
|
|
input2scope = false;
|
|
input1mouse = false;
|
|
break;
|
|
|
|
case 0x08: //Mouse or Multitap port 2
|
|
snesmouse = 2;
|
|
input2just = false;
|
|
input2scope = false;
|
|
input1mouse = false;
|
|
break;
|
|
|
|
case 0x10: //Mouse port 1
|
|
snesmouse = 1;
|
|
input2mouse = false;
|
|
input2just = false;
|
|
input2scope = false;
|
|
input1gp = false;
|
|
break;
|
|
|
|
case 0x20: //Mouse or Gamepad port 1
|
|
snesmouse = 1;
|
|
input2mouse = false;
|
|
input2just = false;
|
|
input2scope = false;
|
|
break;
|
|
|
|
case 0x22: //Mouse or Gamepad port 1 and port 2
|
|
snesmouse = 1;
|
|
input2just = false;
|
|
input2scope = false;
|
|
break;
|
|
|
|
case 0x27: //Mouse or Gamepad port 1, Mouse, Super Scope, or Gamepad port 2
|
|
input2just = false;
|
|
break;
|
|
|
|
case 0x99: break; //Lasabirdie
|
|
case 0x0A: break; //Barcode Battler
|
|
}
|
|
}
|
|
curromspace -= 512;
|
|
memmove((unsigned char *)romdata, ((unsigned char *)romdata)+512, curromspace);
|
|
}
|
|
|
|
snesinputdefault = snesmouse;
|
|
|
|
SplitSupport();
|
|
|
|
if (isZip) { findZipIPS(ZOpenFileName); }
|
|
}
|
|
|
|
|
|
//Memory Setup functions
|
|
extern unsigned char wramdataa[65536];
|
|
extern unsigned char ram7fa[65536];
|
|
extern unsigned char srama[65536];
|
|
extern unsigned char debugbufa[80000];
|
|
extern unsigned char regptra[49152];
|
|
extern unsigned char regptwa[49152];
|
|
extern unsigned char vidmemch2[4096];
|
|
extern unsigned char vidmemch4[4096];
|
|
extern unsigned char vidmemch8[4096];
|
|
extern unsigned char pal16b[1024];
|
|
extern unsigned char pal16bcl[1024];
|
|
extern unsigned char pal16bclha[1024];
|
|
extern unsigned char pal16bxcl[256];
|
|
extern unsigned char spcRam[65472];
|
|
|
|
extern unsigned char *sram;
|
|
extern unsigned char *vidbuffer;
|
|
extern unsigned char *vram;
|
|
extern unsigned char *vcache2b;
|
|
extern unsigned char *vcache4b;
|
|
extern unsigned char *vcache8b;
|
|
|
|
void clearSPCRAM()
|
|
{
|
|
/*
|
|
SPC RAM is filled with alternating 0x00 and 0xFF for 0x20 bytes.
|
|
|
|
Basically the SPCRAM is initialized as follows:
|
|
xx00 - xx1f: $00
|
|
xx20 - xx3f: $ff
|
|
xx40 - xx5f: $00
|
|
xx60 - xx7f: $ff
|
|
xx80 - xx9f: $00
|
|
xxa0 - xxbf: $ff
|
|
xxc0 - xxdf: $00
|
|
xxe0 - xxff: $ff
|
|
*/
|
|
unsigned int i;
|
|
for (i = 0; i < 65472; i += 0x40)
|
|
{
|
|
memset(spcRam+i, 0, 0x20);
|
|
memset(spcRam+i+0x20, 0xFF, 0x20);
|
|
}
|
|
}
|
|
|
|
void clearmem2()
|
|
{
|
|
memset(sram, 0xFF, 16384);
|
|
clearSPCRAM();
|
|
}
|
|
|
|
void clearmem()
|
|
{
|
|
memset(vidbuffer, 0, 131072);
|
|
memset(wramdataa, 0, 65536);
|
|
memset(ram7fa, 0, 65536);
|
|
memset(vram, 0, 65536);
|
|
memset(srama, 0, 65536);
|
|
memset(debugbufa, 0, 80000);
|
|
memset(regptra, 0, 49152);
|
|
memset(regptwa, 0, 49152);
|
|
memset(vcache2b, 0, 262144);
|
|
memset(vcache4b, 0, 131072);
|
|
memset(vcache8b, 0, 65536);
|
|
memset(vidmemch2, 0, 4096);
|
|
memset(vidmemch4, 0, 4096);
|
|
memset(vidmemch8, 0, 4096);
|
|
memset(pal16b, 0, 1024);
|
|
memset(pal16bcl, 0, 1024);
|
|
memset(pal16bclha, 0, 1024);
|
|
memset(pal16bxcl, 0xFF, 256);
|
|
memset(romdata, 0xFF, maxromspace+32768);
|
|
clearmem2();
|
|
}
|
|
|
|
extern unsigned char BRRBuffer[32];
|
|
extern unsigned char echoon0;
|
|
extern unsigned int PHdspsave;
|
|
extern unsigned int PHdspsave2;
|
|
unsigned char echobuf[90000];
|
|
extern unsigned char *spcBuffera;
|
|
extern unsigned char DSPMem[256];
|
|
|
|
void clearvidsound()
|
|
{
|
|
memset(vram, 0, 65536);
|
|
memset(vidmemch2, 0, 4096);
|
|
memset(vidmemch4, 0, 4096);
|
|
memset(vidmemch8, 0, 4096);
|
|
memset(&BRRBuffer, 0, PHdspsave);
|
|
memset(&echoon0, 0, PHdspsave2);
|
|
memset(echobuf, 0, 90000);
|
|
memset(spcBuffera, 0, 65536*4+4096);
|
|
memset(DSPMem, 0, 256);
|
|
}
|
|
|
|
/*
|
|
|
|
--------------Caution Hack City--------------
|
|
|
|
Would be nice to trash this section in the future
|
|
*/
|
|
|
|
|
|
extern unsigned char disablehdma;
|
|
extern unsigned char hdmaearlstart;
|
|
extern unsigned int WindowDisables;
|
|
extern unsigned char ClearScreenSkip;
|
|
extern unsigned char ENVDisable;
|
|
extern unsigned char latchyr;
|
|
extern unsigned char cycpb268;
|
|
extern unsigned char cycpb358;
|
|
extern unsigned char cycpbl2;
|
|
extern unsigned char cycpblt2;
|
|
extern unsigned char cycpbl;
|
|
extern unsigned char cycpblt;
|
|
extern unsigned char opexec268;
|
|
extern unsigned char opexec358;
|
|
extern unsigned char opexec268b;
|
|
extern unsigned char opexec358b;
|
|
extern unsigned char opexec268cph;
|
|
extern unsigned char opexec358cph;
|
|
extern unsigned char opexec268cphb;
|
|
extern unsigned char opexec358cphb;
|
|
extern unsigned char DSP1Type;
|
|
extern unsigned int ewj2hack;
|
|
extern unsigned char cycpl;
|
|
|
|
void headerhack()
|
|
{
|
|
char *RomData = (char *)romdata;
|
|
disablehdma = 0;
|
|
hdmaearlstart = 0;
|
|
WindowDisables = 0;
|
|
ClearScreenSkip = 0;
|
|
ENVDisable = 0;
|
|
|
|
if (curromspace < Lo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//These next fiew look like RAM init hacks, should be looked into
|
|
|
|
//Should be Super Famista (J), uses non-standard characters
|
|
if (!strncmp((RomData+Lo),"\x0bd\x0b0\x0ca\x0df\x0b0\x0cc\x0a7\x0d0\x0bd\x0c0 " ,16))
|
|
{
|
|
RomData[0x2762F] = 0xEA;
|
|
RomData[0x27630] = 0xEA;
|
|
}
|
|
|
|
//Should be Super Famista 2 (J), uses non-standard characters
|
|
if (!strncmp((RomData+Lo),"\x0bd\x0b0\x0ca\x0df\x0b0\x0cc\x0a7\x0d0\x0bd\x0c0 \x032 " ,16))
|
|
{
|
|
//Skip a check for value FF at 2140 when spc not initialized yet?!?
|
|
RomData[0x6CED] = 0xEA;
|
|
RomData[0x6CEE] = 0xEA;
|
|
//Skip a check for value FF at 2140 when spc not initialized yet?!?
|
|
RomData[0x6CF9] = 0xEA;
|
|
RomData[0x6CFA] = 0xEA;
|
|
}
|
|
|
|
//Kamen Rider (J)
|
|
if (!strncmp((RomData+Lo),"SFC \x0b6\x0d2\x0dd\x0d7\x0b2\x0c0\x0de\x0b0 " ,16))
|
|
{
|
|
latchyr = 2;
|
|
}
|
|
|
|
//Deae Tonosama Appare Ichiban (J)
|
|
if (!strncmp((RomData+Lo),"\x0c3\x0de\x0b1\x0b4\x0c4\x0c9\x0bb\x0cf \x0b1\x0af\x0ca" ,12))
|
|
{
|
|
RomData[0x17837] = 0xEA;
|
|
RomData[0x17838] = 0xEA;
|
|
}
|
|
|
|
/*
|
|
The asm indicates the hack is for HGP3, but all of these are affected
|
|
Human Grand Prix (J), Human Grand Prix II (J),
|
|
Human Grand Prix III - F1 Triple Battle (J).
|
|
Human Grand Prix IV is a HiROM and is not affected
|
|
*/
|
|
if (!strncmp((RomData+Lo),"HUMAN GRANDP" ,12))
|
|
{
|
|
cycpb268 = 135;
|
|
cycpb358 = 157;
|
|
cycpbl2 = 125;
|
|
cycpblt2 = 125;
|
|
cycpbl = 125;
|
|
cycpblt = 125;
|
|
}
|
|
|
|
//Accele Brid (J)
|
|
if (!strncmp((RomData+Lo),"ACCELEBRID " ,12))
|
|
{
|
|
RomData[0x34DA2] = 0;
|
|
RomData[0x34DA3] = 0;
|
|
}
|
|
|
|
//Battle Grand Prix (J)
|
|
if (!strncmp((RomData+Lo),"BATTLE GRAND" ,12))
|
|
{
|
|
RomData[0x18089] = 0xFB;
|
|
RomData[0x6C95] = 0xFB;
|
|
}
|
|
|
|
//Neugier (J), and it's English translation
|
|
if (!strncmp((RomData+Lo),"NEUGIER " ,12) ||
|
|
!strncmp((RomData+Lo),"Neugier (tr." ,12))
|
|
{
|
|
RomData[0xD4150] = 0xF9;
|
|
}
|
|
|
|
//Home Alone (J/E/U)
|
|
if (!strncmp((RomData+Lo),"HOME ALO" ,8))
|
|
{
|
|
RomData[0x666B] = 0xEE;
|
|
RomData[0x666C] = 0xBC;
|
|
}
|
|
|
|
//Emerald Dragon (J)
|
|
if (!strncmp((RomData+Hi),"EMERALD DRAG" ,12))
|
|
{
|
|
ENVDisable = true;
|
|
}
|
|
|
|
/*
|
|
Super Mario World 2 - Yoshi's Island (U/E),
|
|
Super Mario - Yossy Island (J), and variants
|
|
*/
|
|
if (!strncmp((RomData+Lo),"YOSSY'S ISLA" ,12) ||
|
|
!strncmp((RomData+Lo),"YOSHI'S ISLA" ,12))
|
|
{
|
|
hdmaearlstart = 2;
|
|
opexec268 = 116;
|
|
opexec358 = 126;
|
|
}
|
|
|
|
//Bubsy II (U/E)
|
|
if (!strncmp((RomData+Hi),"BUBSY II" ,8))
|
|
{
|
|
cycpb268 = 125;
|
|
cycpb358 = 147;
|
|
cycpbl2 = 125;
|
|
cycpblt2 = 125;
|
|
cycpbl = 125;
|
|
cycpblt = 125;
|
|
}
|
|
|
|
/*
|
|
Marvelous (J) has this hack in the asm, but disabled
|
|
|
|
Alternate if for Marvelous-inclusive version
|
|
if (!strncmp((RomData+Lo),"\x0cf\x0bo\x0b3\x0de", 4) ||
|
|
!strncmp((RomData+Lo),"REND", 4))
|
|
*/
|
|
//Rendering Ranger R2
|
|
if (!strncmp((RomData+Lo),"REND", 4))
|
|
{
|
|
cycpb268 = 157;
|
|
cycpb358 = 157;
|
|
cycpbl2 = 157;
|
|
cycpblt2 = 157;
|
|
cycpbl = 157;
|
|
cycpblt = 157;
|
|
}
|
|
|
|
//Clay Fighter (U), other versions are CLAYFIGHTER with no space
|
|
if (!strncmp((RomData+Hi),"CLAY FIGHTER " ,16))
|
|
{
|
|
//Intro
|
|
RomData[0x1A10B9] = 0xDE;
|
|
//In Game
|
|
RomData[0x1A1996] = 0xDE;
|
|
RomData[0x1AE563] = 0xDE;
|
|
RomData[0x1AE600] = 0xDE;
|
|
}
|
|
|
|
//Bahamut Lagoon (J) and all known translations
|
|
if (!strncmp((RomData+Hi),"Bahamut Lago" ,12))
|
|
{
|
|
RomData[0x10254] = 0xEE;
|
|
}
|
|
|
|
//Mortal Kombat (J/U/E), Super Punch-Out, Dragon Quest 5 (J)
|
|
if (!strncmp((RomData+Lo),"DRAGONQUEST5" ,12) ||
|
|
!strncmp((RomData+Lo),"MORTAL KOMBAT " ,16) ||
|
|
!strncmp((RomData+Lo),"Super Punch-Out!! ", 20))
|
|
{
|
|
disablehdma = true;
|
|
}
|
|
|
|
//Super Final Match Tennis (J)
|
|
if (!strncmp((RomData+Lo),"SP F", 4))
|
|
{
|
|
cycpb268 = 145;
|
|
cycpb358 = 147;
|
|
cycpbl2 = 145;
|
|
cycpblt2 = 145;
|
|
cycpbl = 145;
|
|
cycpblt = 145;
|
|
}
|
|
|
|
//Tuff E Nuff (U/E), Dead Dance (J),
|
|
//Cyber Knight II - Tikyu Teikoku no Yabou (J)
|
|
if (!strncmp((RomData+Lo),"CYBER KNIGHT 2 " ,16) ||
|
|
!strncmp((RomData+Lo),"DEAD", 4) ||
|
|
!strncmp((RomData+Lo),"TUFF", 4))
|
|
{
|
|
cycpb268 = 75;
|
|
cycpb358 = 77;
|
|
cycpbl2 = 75;
|
|
cycpblt2 = 75;
|
|
cycpbl = 75;
|
|
cycpblt = 75;
|
|
}
|
|
|
|
//Okaaay...
|
|
if(DSP1Type) { disablehdma = true; }
|
|
|
|
//Final Fantasy 3u/6j (extent unknown!)
|
|
if ((romdata[0x26AC] == 0xF00F2908) || !strncmp((RomData+Hi),"FINAL FANTASY 6" ,15))
|
|
{
|
|
//asm volatile("int $3");
|
|
opexec268 = 163;
|
|
opexec358 = 157;
|
|
opexec268cph = 39;
|
|
opexec358cph = 39;
|
|
}
|
|
|
|
//Earthworm Jim 2 (all regions?)
|
|
if (!strncmp((RomData+Lo),"EARTHWORM JIM 2 " ,20))
|
|
{
|
|
RomData[0x2A9C1A] = 0;
|
|
RomData[0x2A9C1B] = 0;
|
|
RomData[0x2A9C1F] = 0;
|
|
RomData[0x2A9C20] = 0;
|
|
ewj2hack = true;
|
|
}
|
|
|
|
//Lamborghini - American Challenge (U/E)
|
|
if (!strncmp((RomData+Lo), "LAMBORGHINI AMERICAN", 20))
|
|
{
|
|
opexec268 = 187;
|
|
opexec358 = 187;
|
|
}
|
|
|
|
//Addams Family Values (U/E)
|
|
if (!strncmp((RomData+Lo), "ADDAMS FAMILY VALUES", 20))
|
|
{
|
|
opexec268 = 120;
|
|
opexec358 = 100;
|
|
}
|
|
|
|
//Front Mission
|
|
if (!strncmp((RomData+Hi), "\x0cc\x0db\x0dd\x0c4\x0d0\x0af\x0bc\x0ae", 8) ||
|
|
!strncmp((RomData+Hi), "FRONT MI", 8))
|
|
{
|
|
opexec268 = 226;
|
|
opexec358 = 226;
|
|
opexec268cph = 80;
|
|
opexec358cph = 80;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
extern unsigned char per2exec;
|
|
|
|
void Setper2exec()
|
|
{
|
|
if (per2exec != 100)
|
|
{ // Decrease standard % of execution by 5% to replace branch and 16bit
|
|
// cycle deductions
|
|
opexec268b = (unsigned char)((opexec268 * 95 * per2exec) / 10000);
|
|
opexec358b = (unsigned char)((opexec358 * 87 * per2exec) / 10000); // 82
|
|
opexec268cphb = (unsigned char)((opexec268cph * 95 * per2exec) / 10000);
|
|
opexec358cphb = (unsigned char)((opexec358cph * 87 * per2exec) / 10000); // 82
|
|
}
|
|
}
|
|
|
|
extern char FEOEZPath[1024];
|
|
extern char SJNSPath[1024];
|
|
extern char MDHPath[1024];
|
|
extern char SPL4Path[1024];
|
|
char *SPC7110filep;
|
|
char SPC7110nfname[1024+12]; //12 is / plus 6.3
|
|
unsigned int SPC7110IndexSize;
|
|
extern unsigned int SPC7110Entries;
|
|
void SPC7PackIndexLoad()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
FILE *fp = 0;
|
|
SPC7110IndexSize = 0;
|
|
|
|
//Get correct path for the ROM we just loaded
|
|
if (!strncmp(ROM+infoloc, "HU TENGAI MAKYO ZERO ", 21))
|
|
{
|
|
strcpy(SPC7110nfname, *FEOEZPath ? FEOEZPath : "FEOEZSP7");
|
|
}
|
|
else if (!strncmp(ROM+infoloc, "JUMP TENGAIMAKYO ZERO", 21))
|
|
{
|
|
strcpy(SPC7110nfname, *SJNSPath ? SJNSPath : "SJNS-SP7");
|
|
}
|
|
else if (!strncmp(ROM+infoloc, "MOMOTETSU HAPPY ", 21))
|
|
{
|
|
strcpy(SPC7110nfname, *MDHPath ? MDHPath : "MDH-SP7");
|
|
}
|
|
else if (!strncmp(ROM+infoloc, "SUPER POWER LEAG 4 ", 21))
|
|
{
|
|
strcpy(SPC7110nfname, *SPL4Path ? SPL4Path : "SPL4-SP7");
|
|
}
|
|
|
|
//Add a slash if needed
|
|
if (SPC7110nfname[strlen(SPC7110nfname)-1] != *DIR_SLASH)
|
|
{
|
|
strcat(SPC7110nfname, DIR_SLASH);
|
|
}
|
|
|
|
//Set the pointer to after the slash - needed for sa1regs.asm
|
|
SPC7110filep = SPC7110nfname+strlen(SPC7110nfname);
|
|
|
|
//Index file;
|
|
strcat(SPC7110nfname, "index.bin");
|
|
|
|
//Load the index
|
|
fp = fopen(SPC7110nfname, "rb");
|
|
if (!fp) { return; }
|
|
SPC7110IndexSize = fread(ROM+0x580000, 1, 12*32768, fp);
|
|
fclose(fp);
|
|
|
|
SPC7110Entries = 0;
|
|
|
|
//Get file pointer ready for individual pack files
|
|
strcpy(SPC7110filep, "123456.bin"); //Extension Lower Case
|
|
}
|
|
|
|
void SPC7_Convert_Upper()
|
|
{
|
|
char *i = SPC7110filep;
|
|
while (*i)
|
|
{
|
|
*i = toupper(*i); //To make extension Upper case
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void SPC7_Convert_Lower()
|
|
{
|
|
char *i = SPC7110filep;
|
|
while (*i)
|
|
{
|
|
*i = tolower(*i); //To make everything Lower case
|
|
i++;
|
|
}
|
|
}
|
|
|
|
unsigned int crc32_table[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 };
|
|
|
|
unsigned int CalcCRC32 (unsigned char *start, unsigned int size)
|
|
{
|
|
unsigned int i, result=0xFFFFFFFF;
|
|
|
|
for (i=0 ; i<size ; i++)
|
|
{
|
|
result = (result >> 8) ^ (crc32_table[(result ^ (*(start+i))) & 0xFF]);
|
|
}
|
|
|
|
return (~result);
|
|
}
|
|
|
|
extern unsigned int MsgCount, MessageOn, CRC32;
|
|
extern unsigned char IPSPatched, *Msgptr;
|
|
|
|
unsigned int showinfogui()
|
|
{
|
|
unsigned int i;
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
if (infoloc == 0x40FFC0) { memcpy (CSStatus2+23, "EHi ", 4); }
|
|
else
|
|
{
|
|
if (romtype == 2) { memcpy (CSStatus2+23, "Hi ", 4); }
|
|
else { memcpy (CSStatus2+23, "Lo ", 4); }
|
|
}
|
|
|
|
for (i=0 ; i<20 ; i++)
|
|
{
|
|
CSStatus[i] = (ROM[infoloc + i]) ? ROM[infoloc + i] : 32;
|
|
}
|
|
|
|
if ((ROM[infoloc + 25] < 2 ) || (ROM[infoloc + 25] > 12))
|
|
{
|
|
memcpy (CSStatus3+6, "NTSC", 4);
|
|
}
|
|
else { memcpy (CSStatus3+6, "PAL ", 4); }
|
|
|
|
if (IPSPatched) { memcpy (CSStatus3+16, "IPS ", 4); }
|
|
else { memcpy (CSStatus3+16, " ", 4); }
|
|
|
|
memcpy (CSStatus+29, "NORMAL ", 8);
|
|
|
|
if (SA1Enable) { memcpy (CSStatus+29, "SA-1 ", 8); }
|
|
if (RTCEnable) { memcpy (CSStatus+29, "RTC ", 8); }
|
|
if (SPC7110Enable) { memcpy (CSStatus+29, "SPC7110 ", 8); }
|
|
if (SFXEnable) { memcpy (CSStatus+29, "SUPER FX", 8); }
|
|
if (C4Enable) { memcpy (CSStatus+29, "C4 ", 8); }
|
|
if (DSP1Enable) { memcpy (CSStatus+29, "DSP-1 ", 8); }
|
|
if (DSP2Enable) { memcpy (CSStatus+29, "DSP-2 ", 8); }
|
|
if (DSP3Enable) { memcpy (CSStatus+29, "DSP-3 ", 8); }
|
|
if (DSP4Enable) { memcpy (CSStatus+29, "DSP-4 ", 8); }
|
|
if (SDD1Enable) { memcpy (CSStatus+29, "S-DD1 ", 8); }
|
|
if (OBCEnable) { memcpy (CSStatus+29, "OBC1 ", 8); }
|
|
if (SETAEnable) { memcpy (CSStatus+29, "SETA DSP", 8); }
|
|
if (ST18Enable) { memcpy (CSStatus+29, "ST018 ", 8); }
|
|
if (SGBEnable) { memcpy (CSStatus+29, "SGB ", 8); }
|
|
if (BSEnable) { memcpy (CSStatus+29, "BROADCST", 8);
|
|
// dummy out date so CRC32 matches
|
|
ROM[infoloc + 22] = 0x42;
|
|
ROM[infoloc + 23] = 0x00;
|
|
// 42 is the answer, and the uCONSRT standard
|
|
}
|
|
|
|
if (Interleaved) { memcpy (CSStatus2+12, "Yes ", 4); }
|
|
else { memcpy (CSStatus2+12, "No ", 4); }
|
|
|
|
// calculate CRC32 for the whole ROM, or Add-on ROM only
|
|
CRC32 = (SplittedROM) ? CalcCRC32(ROM+addOnStart, addOnSize) : CalcCRC32(ROM, NumofBytes);
|
|
|
|
// place CRC32 on line
|
|
sprintf (CSStatus3+32, "%08X", CRC32);
|
|
|
|
CalcChecksum();
|
|
|
|
i = (SplittedROM) ? infoloc + 0x1E + addOnStart: infoloc + 0x1E;
|
|
|
|
if ((ROM[i] == (Checksumvalue & 0xFF)) && (ROM[i+1] == (Checksumvalue >> 8)))
|
|
{ memcpy (CSStatus2+36, "OK ", 4); }
|
|
else { memcpy (CSStatus2+36, "FAIL", 4); }
|
|
|
|
DumpROMLoadInfo();
|
|
|
|
MessageOn = 300;
|
|
Msgptr = CSStatus;
|
|
return (MsgCount);
|
|
}
|
|
|
|
extern unsigned int nmiprevaddrl, nmiprevaddrh, nmirept, nmiprevline, nmistatus;
|
|
extern unsigned int spcnumread, spchalted;
|
|
extern unsigned char NextLineCache, sramsavedis, sndrot, regsbackup[3019];
|
|
extern unsigned char yesoutofmemory, fnames[512];
|
|
|
|
void initsnes();
|
|
void outofmemfix();
|
|
void GUIDoReset();
|
|
|
|
bool loadSRAM(char *sramname)
|
|
{
|
|
FILE *sramfp;
|
|
int sramsize;
|
|
|
|
if ((sramfp = fopen(sramname, "rb")))
|
|
{
|
|
fseek(sramfp, 0, SEEK_END);
|
|
sramsize = ftell(sramfp);
|
|
rewind(sramfp);
|
|
if (sramsize) { fread(sram, 1, sramsize, sramfp); }
|
|
fclose(sramfp);
|
|
return (true);
|
|
}
|
|
else { return(false); }
|
|
}
|
|
|
|
extern unsigned int Voice0Freq, Voice1Freq, Voice2Freq, Voice3Freq;
|
|
extern unsigned int Voice4Freq, Voice5Freq, Voice6Freq, Voice7Freq;
|
|
extern unsigned int dspPAdj;
|
|
extern unsigned short Voice0Pitch, Voice1Pitch, Voice2Pitch, Voice3Pitch;
|
|
extern unsigned short Voice4Pitch, Voice5Pitch, Voice6Pitch, Voice7Pitch;
|
|
|
|
void initpitch()
|
|
{
|
|
Voice0Pitch = DSPMem[2+0*0x10];
|
|
Voice0Freq = ((((Voice0Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF);
|
|
Voice1Pitch = DSPMem[2+1*0x10];
|
|
Voice1Freq = ((((Voice1Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF);
|
|
Voice2Pitch = DSPMem[2+2*0x10];
|
|
Voice2Freq = ((((Voice2Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF);
|
|
Voice3Pitch = DSPMem[2+3*0x10];
|
|
Voice3Freq = ((((Voice3Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF);
|
|
Voice4Pitch = DSPMem[2+4*0x10];
|
|
Voice4Freq = ((((Voice4Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF);
|
|
Voice5Pitch = DSPMem[2+5*0x10];
|
|
Voice5Freq = ((((Voice5Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF);
|
|
Voice6Pitch = DSPMem[2+6*0x10];
|
|
Voice6Freq = ((((Voice6Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF);
|
|
Voice7Pitch = DSPMem[2+7*0x10];
|
|
Voice7Freq = ((((Voice7Pitch & 0x3FFF) * dspPAdj) >> 8) & 0xFFFFFFFF);
|
|
}
|
|
|
|
extern unsigned int SfxR1, SfxR2, SetaCmdEnable, SfxSFR, SfxSCMR;
|
|
extern unsigned char lorommapmode2, disablespcclr, *sfxramdata, SramExists;
|
|
extern unsigned char *setaramdata, *wramdata, *SA1RAMArea, cbitmode, curromsize;
|
|
extern unsigned char ForcePal, ForceROMTiming, romispal;
|
|
extern unsigned short totlines;
|
|
void SetAddressingModes(), GenerateBank0Table();
|
|
void SetAddressingModesSA1(), GenerateBank0TableSA1();
|
|
void calculate_state_sizes(), InitRewindVars();
|
|
void InitDSP(), InitDSP2(), InitDSP4(), InitFxTables(), initregr(), initregw();
|
|
void SPC7110Load(), DOSClearScreen(), dosmakepal();
|
|
|
|
void CheckROMType()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
BankCheck();
|
|
MirrorROM();
|
|
|
|
lorommapmode2 = 0;
|
|
if (!strncmp(ROM+0x207FC0, "DERBY STALLION 96", 17) || !strncmp(ROM+Lo, "SOUND NOVEL-TCOOL", 17))
|
|
{
|
|
lorommapmode2 = 1;
|
|
}
|
|
|
|
// Setup memmapping
|
|
SetAddressingModes();
|
|
GenerateBank0Table();
|
|
chip_detect();
|
|
|
|
disablespcclr = (memcmp(ROM+Hi, "\0x42\0x53\0x20\0x5A", 4)) ? 0 : 1;
|
|
|
|
if ((romtype == 1) && (!SDD1Enable))
|
|
{ // Non-SDD1 LoROM SRAM mapping, banks F0 - F3
|
|
map_mem(0xF0, &srambank, 4);
|
|
}
|
|
|
|
// Setup DSP-X stuff
|
|
DSP1Type = 0;
|
|
|
|
if (DSP1Enable || DSP2Enable || DSP3Enable)
|
|
{
|
|
if (DSP2Enable)
|
|
{
|
|
asm_call(InitDSP2);
|
|
}
|
|
|
|
InitDSP();
|
|
|
|
DSP1Type = (romtype == 2) ? 2 : 1;
|
|
}
|
|
|
|
if (DSP4Enable)
|
|
{
|
|
InitDSP4();
|
|
|
|
// DSP-4 mapping, banks 30 - 3F
|
|
map_mem(0x30, &dsp4bank, 0x10);
|
|
}
|
|
|
|
if (SFXEnable)
|
|
{
|
|
// Setup SuperFX stuff
|
|
if (Sup48mbit)
|
|
{
|
|
//SuperFX mapping, banks 70 - 73
|
|
map_mem(0x70, &sfxbank, 1);
|
|
map_mem(0x71, &sfxbankb, 1);
|
|
map_mem(0x72, &sfxbankc, 1);
|
|
map_mem(0x73, &sfxbankd, 1);
|
|
|
|
//SRAM mapping, banks 78 - 79
|
|
map_mem(0x78, &sramsbank, 2);
|
|
|
|
SfxR1 = 0;
|
|
SfxR2 = 0;
|
|
memset(sfxramdata, 0, 262144); // clear 256kB SFX ram
|
|
|
|
if (SramExists)
|
|
{
|
|
memcpy(sfxramdata, sram, 65536); // proper SFX sram area
|
|
}
|
|
|
|
asm_call(InitFxTables);
|
|
}
|
|
else
|
|
{
|
|
yesoutofmemory = 1;
|
|
}
|
|
}
|
|
|
|
if (SETAEnable)
|
|
{
|
|
// Setup SETA 010/011 stuff
|
|
|
|
// Really banks 68h-6Fh:0000-7FFF are all mapped the same by the chip but
|
|
// F1 ROC II only uses bank 68h
|
|
map_mem(0x68, &setabank, 1);
|
|
|
|
// Control register (and some status?) is in banks 60h-67h:0000-3FFF
|
|
map_mem(0x60, &setabanka, 1);
|
|
|
|
SetaCmdEnable = 0x00000080; // 60:0000
|
|
memset(setaramdata, 0, 4096); // clear 4kB SETA ram
|
|
|
|
// proper SETA sram area
|
|
if (SramExists)
|
|
{
|
|
memcpy(setaramdata, sram, 4096);
|
|
}
|
|
}
|
|
|
|
// General stuff all mixed together [... wouldn't it be cool to clean that]
|
|
SfxSFR = 0;
|
|
SfxSCMR &= 0xFFFFFF00;
|
|
asm_call(initregr);
|
|
asm_call(initregw);
|
|
|
|
if (SA1Enable)
|
|
{
|
|
SA1RAMArea = ROM + 4096*1024;
|
|
|
|
GenerateBank0TableSA1();
|
|
SetAddressingModesSA1();
|
|
|
|
if (CHIPBATT) // proper SA-1 sram area
|
|
{
|
|
memset(SA1RAMArea, 0, 131072);
|
|
if (SramExists) { memcpy(SA1RAMArea, sram, 131072); }
|
|
}
|
|
}
|
|
|
|
if (DSP1Type == 1)
|
|
{
|
|
map_mem(0x30, &dsp1bank, 0x10);
|
|
map_mem(0xB0, &dsp1bank, 0x10);
|
|
map_mem(0xE0, &dsp1bank, 0x10);
|
|
|
|
if (DSP2Enable)
|
|
{
|
|
map_mem(0x3F, &dsp2bank, 1);
|
|
}
|
|
}
|
|
|
|
wramdata = wramdataa;
|
|
|
|
asm_call(SPC7110Load);
|
|
}
|
|
|
|
extern unsigned short copv, brkv, abortv, nmiv, nmiv2, irqv, irqv2, resetv;
|
|
extern unsigned short copv8, brkv8, abortv8, nmiv8, irqv8;
|
|
|
|
void SetIRQVectors()
|
|
{ // get vectors (NMI & reset)
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
if (!(ROM[infoloc+21] & 0xF0)) // if not fastrom
|
|
{
|
|
opexec358 = opexec268;
|
|
opexec358cph = opexec268cph;
|
|
cycpb358 = cycpb268;
|
|
}
|
|
|
|
if (!memcmp(ROM+infoloc+36+24, "\0xFF\0xFF", 2)) // if reset error
|
|
{
|
|
memcpy(ROM+infoloc+36+6, "\0x9C\0xFF", 2);
|
|
memcpy(ROM+infoloc+36+24, "\0x80\0xFF", 2);
|
|
}
|
|
|
|
memcpy(&copv, ROM+infoloc+0x24, 2);
|
|
memcpy(&brkv, ROM+infoloc+0x26, 2);
|
|
memcpy(&abortv, ROM+infoloc+0x28, 2);
|
|
memcpy(&nmiv, ROM+infoloc+0x2A, 2);
|
|
memcpy(&nmiv2, ROM+infoloc+0x2A, 2);
|
|
memcpy(&irqv, ROM+infoloc+0x2E, 2);
|
|
memcpy(&irqv2, ROM+infoloc+0x2E, 2);
|
|
|
|
// 8-bit and reset
|
|
memcpy(&copv8, ROM+infoloc+0x34, 2);
|
|
memcpy(&abortv8, ROM+infoloc+0x38, 2);
|
|
memcpy(&nmiv8, ROM+infoloc+0x3A, 2);
|
|
memcpy(&resetv, ROM+infoloc+0x3C, 2);
|
|
memcpy(&brkv8, ROM+infoloc+0x3E, 2);
|
|
memcpy(&irqv8, ROM+infoloc+0x3E, 2);
|
|
|
|
if (yesoutofmemory) // failed ?
|
|
{
|
|
resetv = 0x8000;
|
|
memcpy(ROM+0x0000, "\0x80\0xFE", 2);
|
|
memcpy(ROM+0x8000, "\0x80\0xFE", 2);
|
|
}
|
|
}
|
|
|
|
void SetupROM()
|
|
{
|
|
unsigned char *ROM = (unsigned char *)romdata;
|
|
|
|
CheckROMType();
|
|
SetIRQVectors();
|
|
|
|
#ifdef __MSDOS__
|
|
asm_call(DOSClearScreen);
|
|
|
|
if (!cbitmode) // 8-bit mode uses a palette
|
|
{
|
|
asm_call(dosmakepal);
|
|
}
|
|
#endif
|
|
|
|
// get ROM and SRAM sizes
|
|
curromsize = ROM[infoloc+0x17];
|
|
|
|
SetupSramSize();
|
|
calculate_state_sizes();
|
|
InitRewindVars();
|
|
|
|
// get timing (pal/ntsc)
|
|
ForcePal = ForceROMTiming;
|
|
|
|
switch (ForcePal)
|
|
{
|
|
case 1:
|
|
romispal = 0;
|
|
break;
|
|
case 2:
|
|
romispal = (!BSEnable);
|
|
break;
|
|
default:
|
|
romispal = ((!BSEnable) && (ROM[infoloc+0x19] > 1) && (ROM[infoloc+0x19] < 0xD));
|
|
}
|
|
|
|
if (romispal)
|
|
{
|
|
totlines = 314;
|
|
MsgCount = 100;
|
|
}
|
|
else
|
|
{
|
|
totlines = 263;
|
|
MsgCount = 120;
|
|
}
|
|
}
|
|
|
|
void powercycle(bool sramload)
|
|
{
|
|
memset(sram, 0xFF, 32768);
|
|
clearSPCRAM();
|
|
|
|
nmiprevaddrl = 0;
|
|
nmiprevaddrh = 0;
|
|
nmirept = 0;
|
|
nmiprevline = 224;
|
|
nmistatus = 0;
|
|
spcnumread = 0;
|
|
spchalted = ~0;
|
|
NextLineCache = 0;
|
|
curexecstate = 1;
|
|
|
|
if (sramload) { loadSRAM(fnames+1); }
|
|
SetupROM();
|
|
asm_call(initsnes);
|
|
|
|
sramsavedis = 0;
|
|
|
|
memcpy(&sndrot, regsbackup, 3019);
|
|
|
|
if (yesoutofmemory == 1) { asm_call(outofmemfix); }
|
|
|
|
asm_call(GUIDoReset);
|
|
}
|