Genesis-Plus-GX/source/loadrom.c
2008-08-07 12:26:07 +00:00

437 lines
12 KiB
C

/***************************************************************************************
* Genesis Plus 1.2a
* ROM Loading Support
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* modified by Eke-Eke (compatibility fixes & additional code), GC/Wii port
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
****************************************************************************************/
#include <ctype.h>
#include "shared.h"
/*** ROM Information ***/
#define ROMCONSOLE 256
#define ROMCOPYRIGHT 272
#define ROMDOMESTIC 288
#define ROMWORLD 336
#define ROMTYPE 384
#define ROMPRODUCT 386
#define ROMCHECKSUM 398
#define ROMIOSUPPORT 400
#define ROMROMSTART 416
#define ROMROMEND 420
#define ROMRAMINFO 424
#define ROMRAMSTART 436
#define ROMRAMEND 440
#define ROMMODEMINFO 444
#define ROMMEMO 456
#define ROMCOUNTRY 496
#define P3BUTTONS 1
#define P6BUTTONS 2
#define PKEYBOARD 4
#define PPRINTER 8
#define PBALL 16
#define PFLOPPY 32
#define PACTIVATOR 64
#define PTEAMPLAYER 128
#define PMSYSTEMPAD 256
#define PSERIAL 512
#define PTABLET 1024
#define PPADDLE 2048
#define PCDROM 4096
#define PMOUSE 8192
int peripherals;
uint16 realchecksum;
ROMINFO rominfo;
/***************************************************************************
* Genesis ROM Manufacturers
*
* Based on the document provided at
* http://www.zophar.net/tech/files/Genesis_ROM_Format.txt
***************************************************************************/
COMPANYINFO companyinfo[MAXCOMPANY] = {
{"ACLD", "Ballistic"},
{"RSI", "Razorsoft"},
{"SEGA", "SEGA"},
{"TREC", "Treco"},
{"VRGN", "Virgin Games"},
{"WSTN", "Westone"},
{"10", "Takara"},
{"11", "Taito or Accolade"},
{"12", "Capcom"},
{"13", "Data East"},
{"14", "Namco or Tengen"},
{"15", "Sunsoft"},
{"16", "Bandai"},
{"17", "Dempa"},
{"18", "Technosoft"},
{"19", "Technosoft"},
{"20", "Asmik"},
{"22", "Micronet"},
{"23", "Vic Tokai"},
{"24", "American Sammy"},
{"29", "Kyugo"},
{"32", "Wolfteam"},
{"33", "Kaneko"},
{"35", "Toaplan"},
{"36", "Tecmo"},
{"40", "Toaplan"},
{"42", "UFL Company Limited"},
{"43", "Human"},
{"45", "Game Arts"},
{"47", "Sage's Creation"},
{"48", "Tengen"},
{"49", "Renovation or Telenet"},
{"50", "Electronic Arts"},
{"56", "Razorsoft"},
{"58", "Mentrix"},
{"60", "Victor Musical Industries"},
{"69", "Arena"},
{"70", "Virgin"},
{"73", "Soft Vision"},
{"74", "Palsoft"},
{"76", "Koei"},
{"79", "U.S. Gold"},
{"81", "Acclaim/Flying Edge"},
{"83", "Gametek"},
{"86", "Absolute"},
{"87", "Mindscape"},
{"93", "Sony"},
{"95", "Konami"},
{"97", "Tradewest"},
{"100", "T*HQ Software"},
{"101", "Tecmagik"},
{"112", "Designer Software"},
{"113", "Psygnosis"},
{"119", "Accolade"},
{"120", "Code Masters"},
{"125", "Interplay"},
{"130", "Activision"},
{"132", "Shiny & Playmates"},
{"144", "Atlus"},
{"151", "Infogrames"},
{"161", "Fox Interactive"},
{"177", "Ubisoft"},
{"239", "Disney Interactive"},
{"---", "Unknown"}
};
/***************************************************************************
* Genesis Peripheral Information
*
* Based on the document provided at
* http://www.zophar.net/tech/files/Genesis_ROM_Format.txt
***************************************************************************/
PERIPHERALINFO peripheralinfo[14] = {
{"J", "3-Button Joypad"},
{"6", "6-button Joypad"},
{"K", "Keyboard"},
{"P", "Printer"},
{"B", "Control Ball"},
{"F", "Floppy Drive"},
{"L", "Activator"},
{"4", "Team Player"},
{"0", "MS Joypad"},
{"R", "RS232C Serial"},
{"T", "Tablet"},
{"V", "Paddle"},
{"C", "CD-ROM"},
{"M", "Mega Mouse"}
};
/*
* softdev - New Checksum Calculation
eke-eke: fixed
*/
uint16 GetRealChecksum (uint8 *rom, int length)
{
int i;
uint16 checksum = 0;
for (i = 0; i < length; i += 2)
{
checksum += ((rom[i] << 8) + rom[i + 1]);
}
return checksum;
}
/****************************************************************************
* getcompany
*
* Try to determine which company made this rom
*
* Ok, for some reason there's no standard for this.
* It seems that there can be pretty much anything you like following the
* copyright (C) symbol!
****************************************************************************/
int getcompany ()
{
char *s;
int i;
char company[10];
for (i = 3; i < 8; i++) company[i - 3] = rominfo.copyright[i];
company[5] = 0;
/** OK, first look for a hyphen
* Capcom use T-12 for example
*/
s = strstr (company, "-");
if (s != NULL)
{
s++;
strcpy (company, s);
}
/** Strip any trailing spaces **/
for (i = strlen (company) - 1; i >= 0; i--)
if (company[i] == 32) company[i] = 0;
if (strlen (company) == 0) return MAXCOMPANY - 1;
for (i = 0; i < MAXCOMPANY - 1; i++)
{
if (!(strncmp (company, companyinfo[i].companyid, strlen (company)))) return i;
}
return MAXCOMPANY - 1;
}
/***************************************************************************
* getrominfo
*
* Pass a pointer to the ROM base address.
***************************************************************************/
void getrominfo (char *romheader)
{
int i,j;
memset (&rominfo, 0, sizeof (ROMINFO));
memcpy (&rominfo.consoletype, romheader + ROMCONSOLE, 16);
memcpy (&rominfo.copyright, romheader + ROMCOPYRIGHT, 16);
rominfo.domestic[0] = romheader[ROMDOMESTIC];
j=1;
for (i=1; i<48; i++)
{
if ((rominfo.domestic[j-1] != 32) || (romheader[ROMDOMESTIC + i] != 32))
{
rominfo.domestic[j] = romheader[ROMDOMESTIC + i];
j++;
}
}
rominfo.domestic[j] = 0;
rominfo.international[0] = romheader[ROMWORLD];
j=1;
for (i=1; i<48; i++)
{
if ((rominfo.international[j-1] != 32) || (romheader[ROMWORLD + i] != 32))
{
rominfo.international[j] = romheader[ROMWORLD + i];
j++;
}
}
rominfo.international[j] = 0;
memcpy (&rominfo.ROMType, romheader + ROMTYPE, 2);
memcpy (&rominfo.product, romheader + ROMPRODUCT, 12);
memcpy (&rominfo.checksum, romheader + ROMCHECKSUM, 2);
memcpy (&rominfo.io_support, romheader + ROMIOSUPPORT, 16);
memcpy (&rominfo.romstart, romheader + ROMROMSTART, 4);
memcpy (&rominfo.romend, romheader + ROMROMEND, 4);
memcpy (&rominfo.RAMInfo, romheader + ROMRAMINFO, 12);
memcpy (&rominfo.ramstart, romheader + ROMRAMSTART, 4);
memcpy (&rominfo.ramend, romheader + ROMRAMEND, 4);
memcpy (&rominfo.modem, romheader + ROMMODEMINFO, 12);
memcpy (&rominfo.memo, romheader + ROMMEMO, 40);
memcpy (&rominfo.country, romheader + ROMCOUNTRY, 16);
realchecksum = GetRealChecksum (((uint8 *) cart_rom) + 0x200, genromsize - 0x200);
#ifdef LSB_FIRST
rominfo.checksum = (rominfo.checksum >> 8) | ((rominfo.checksum & 0xff) << 8);
#endif
peripherals = 0;
for (i = 0; i < 14; i++)
for (j=0; j < 14; j++)
if (rominfo.io_support[i] == peripheralinfo[j].pID[0]) peripherals |= (1 << j);
for (i = 0; i < 8; i++)
{
input.padtype[i] = (peripherals & P6BUTTONS) ? DEVICE_6BUTTON : DEVICE_3BUTTON;
#ifdef HW_RVL
if (config.input[i].device == 1) input.padtype[i] = DEVICE_3BUTTON;
#endif
}
}
/* 05/05/2006: new region detection routine (taken from GENS sourcecode) */
void set_region ()
{
/* country codes used to differentiate region */
/* 0001 = japan ntsc (1) */
/* 0010 = japan pal (2) */
/* 0100 = usa (4) */
/* 1000 = europe (8) */
int country = 0;
int i = 0;
char c;
/* reading header to find the country */
if (!strnicmp(rominfo.country, "eur", 3)) country |= 8;
else if (!strnicmp(rominfo.country, "usa", 3)) country |= 4;
else if (!strnicmp(rominfo.country, "jap", 3)) country |= 1;
else for(i = 0; i < 4; i++)
{
c = toupper((int)rominfo.country[i]);
if (c == 'U') country |= 4;
else if (c == 'J') country |= 1;
else if (c == 'E') country |= 8;
else if (c < 16) country |= c;
else if ((c >= '0') && (c <= '9')) country |= c - '0';
else if ((c >= 'A') && (c <= 'F')) country |= c - 'A' + 10;
}
/* automatic detection */
/* setting region */
/* this is used by IO register */
if (country & 4) region_code = REGION_USA;
else if (country & 1) region_code = REGION_JAPAN_NTSC;
else if (country & 8) region_code = REGION_EUROPE;
else if (country & 2) region_code = REGION_JAPAN_PAL;
else region_code = REGION_USA;
/* some games need specific REGION setting */
if (((strstr(rominfo.product,"T-45033") != NULL) && (rominfo.checksum == 0x0F81)) || /* Alisia Dragon (E) */
(strstr(rominfo.product,"T-69046-50") != NULL)) /* On Dal Jang Goon (Korea) */
{
/* need PAL settings */
region_code = REGION_EUROPE;
}
else if ((realchecksum == 0x532e) && (strstr(rominfo.product,"1011-00") != NULL))
{
/* On Dal Jang Goon (Korea) needs JAP region code */
region_code = REGION_JAPAN_NTSC;
}
/* Force region setting */
if (config.region_detect == 1) region_code = REGION_USA;
else if (config.region_detect == 2) region_code = REGION_EUROPE;
else if (config.region_detect == 3) region_code = REGION_JAPAN_NTSC;
else if (config.region_detect == 4) region_code = REGION_JAPAN_PAL;
/* set cpu/vdp speed: PAL or NTSC */
if ((region_code == REGION_EUROPE) || (region_code == REGION_JAPAN_PAL)) vdp_pal = 1;
else vdp_pal = 0;
}
/* SMD (interleaved) rom support */
static uint8 block[0x4000];
void deinterleave_block (uint8 * src)
{
int i;
memcpy (block, src, 0x4000);
for (i = 0; i < 0x2000; i += 1)
{
src[i * 2 + 0] = block[0x2000 + (i)];
src[i * 2 + 1] = block[0x0000 + (i)];
}
}
int load_rom(char *filename)
{
int i, size, offset = 0;
#ifdef NGC
size = genromsize;
#else
uint8 *ptr;
ptr = load_archive(filename, &size);
if(!ptr) return (0);
memcpy(cart_rom, ptr + offset, size);
free(ptr);
#endif
/* detect interleaved roms (.smd format) */
if (strncmp((char *)(cart_rom + 0x100),"SEGA", 4) && ((size / 512) & 1))
{
size -= 512;
offset += 512;
for (i = 0; i < (size / 0x4000); i += 1)
{
deinterleave_block (cart_rom + offset + (i * 0x4000));
}
memcpy(cart_rom, cart_rom + offset, size);
}
/* max. 10 MBytes supported */
if (size > 0xA00000) size = 0xA00000;
genromsize = size;
/* clear unused ROM space */
if (size < 0xA00000) memset (cart_rom + size, 0x00, 0xA00000 - size);
getrominfo((char *)cart_rom); /* get infos from ROM header */
set_region(); /* set game region (PAL/NTSC, JAP/USA/EUR) */
#ifdef LSB_FIRST
/* Byteswap ROM */
uint8 temp;
for(i = 0; i < genromsize; i += 2)
{
temp = cart_rom[i];
cart_rom[i] = cart_rom[i+1];
cart_rom[i+1] = temp;
}
#endif
/* byteswapped RADICA dumps (from Haze) */
if (((strstr(rominfo.product,"-K0101") != NULL) && (rominfo.checksum == 0xf424)) ||
((strstr(rominfo.product,"-K0109") != NULL) && (rominfo.checksum == 0x4f10)))
{
uint8 temp;
for(i = 0; i < genromsize; i += 2)
{
temp = cart_rom[i];
cart_rom[i] = cart_rom[i+1];
cart_rom[i+1] = temp;
}
}
/* console hardware */
if (strstr(rominfo.consoletype, "SEGA PICO") != NULL) system_hw = SYSTEM_PICO;
else if (strstr(rominfo.consoletype, "SEGA MEGADRIVE") != NULL) system_hw = SYSTEM_MEGADRIVE;
else system_hw = SYSTEM_GENESIS;
return(1);
}