/***************************************************************************
megadriv.c
Machine file to handle emulation of the Sega Mega Drive & Genesis in MESS.
i2c games mapping table:
game name | SDA_IN | SDA_OUT | SCL | SIZE_MASK | PAGE_MASK |
----------------------------------|------------|------------|------------|----------------|-----------|
NBA Jam | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x00ff (24C02) | 0x03 | xx
NBA Jam TE | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x00ff (24C02) | 0x03 | xx
NBA Jam TE (32x) | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x00ff (24C02) | 0x03 |
NFL Quarterback Club | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x00ff (24C02) | 0x03 | xx
NFL Quarterback Club 96 | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x07ff (24C16) | 0x07 | xx
College Slam | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x1fff (24C64) | 0x07 | xx
Frank Thomas Big Hurt Baseball | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x1fff (24C64) | 0x07 | xx
NHLPA Hockey 93 | 0x200001-7 | 0x200001-7 | 0x200001-6 | 0x007f (24C01) | 0x03 | xx
Rings of Power | 0x200001-7 | 0x200001-7 | 0x200001-6 | 0x007f (24C01) | 0x03 | xx
Evander Holyfield's Boxing | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx
Greatest Heavyweights of the Ring | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx
Wonder Boy V | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx
Sports Talk Baseball | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx
Megaman - the Wily Wars | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx **
Micro Machines 2 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x03ff (24C08) | 0x0f |
Micro Machines Military | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x03ff (24C08) | 0x0f |
Micro Machines 96 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x07ff (24C16) | 0x0f |
Brian Lara Cricket 96 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x1fff (24C64) | 0x??* |
----------------------------------|------------|------------|------------|----------------|-----------|
* Notes: check these
** original Rockman Mega World (J) set uses normal backup RAM
2008-09: Moved here cart code and custom mapper handlers. Hopefully,
it will make painless the future merging with HazeMD
2008-10: Fixed SRAM, matching as much as possible HazeMD. Some game is
not detected, however. E.g. Sonic 3. Also some games seem false
positives (e.g. Wonderboy 5: according to its headers it should
have 1byte of SRAM). Better detection routines would be welcome.
2009-06: Changed SRAM code, fixing more games, including Sonic 3. The
false positives seem only some of the games using EEPROM. Todo
list in mess/drivers/genesis.c includes EEPROM emulation.
***************************************************************************/
#include "emu.h"
#include "imageutl.h"
#include "cpu/m68000/m68000.h"
#include "imagedev/cartslot.h"
#include "includes/megadriv.h"
/* PCB */
enum
{
SEGA_STD = 0,
SEGA_SRAM, SEGA_FRAM,
CM_JCART, CM_JCART_SEPROM, /* Codemasters PCB (J-Carts and SEPROM) */
SSF2, /* Super Street Fighter 2 */
GAME_KANDUME, /* Game no Kandume Otokuyou */
BEGGAR, /* Xin Qigai Wangzi uses different sram start address and has no valid header */
// EEPROM
SEGA_EEPROM, /* Wonder Boy V / Evander Holyfield's Boxing / Greatest Heavyweights of the Ring / Sports Talk Baseball / Megaman */
NBA_JAM, /* NBA Jam */
NBA_JAM_TE, /* NBA Jam TE / NFL Quarterback Club */
NFL_QB_96, /* NFL Quarterback Club '96 */
C_SLAM, /* College Slam / Frank Thomas Big Hurt Baseball */
EA_NHLPA, /* NHLPA Hockey 93 / Rings of Power */
CODE_MASTERS, /* Micro Machines 2 / Military / 96 / Brian Lara Cricket 96 */
MC_SUP19IN1, /* Super 19 in 1 */
MC_SUP15IN1, /* Super 15 in 1 */
MC_12IN1, /* 12 in 1 and a few more multicarts */
BUGSLIFE, /* A Bug's Life */
CHINFIGHT3, /* Chinese Fighters 3 */
ELFWOR, /* Linghuan Daoshi Super Magician */
KOF98, /* King of Fighters '98 */
KOF99, /* King of Fighters '99 */
LIONK2, /* Lion King 2 */
LIONK3, /* Lion King 3 */
SKINGKONG, /* Super King Kong 99 */
SDK99, /* Super Donkey Kong 99 */
MJLOVER, /* Mahjong Lover */
MULAN, /* Hua Mu Lan - Mulan */
POKEMON, /* Pocket Monster */
POKEMON2, /* Pocket Monster 2 */
KAIJU, /* Pokemon Stadium */
RADICA, /* Radica TV games.. these probably should be a seperate driver since they are a seperate 'console' */
REALTEC, /* Whac a Critter/Mallet legend, Defend the Earth, Funnyworld/Ballonboy */
REDCLIFF, /* Romance of the Three Kingdoms - Battle of Red Cliffs, already decoded from .mdx format */
REDCL_EN, /* The encoded version... */
ROCKMANX3, /* Rockman X3 */
SMB, /* Super Mario Bros. */
SMB2, /* Super Mario Bros. 2 */
SMOUSE, /* Smart Mouse */
SOULBLAD, /* Soul Blade */
SQUIRRELK, /* Squirrel King */
SBUBBOB, /* Super Bubble Bobble */
TOPFIGHTER /* Top Fighter 2000 MK VIII */
};
typedef struct _md_pcb md_pcb;
struct _md_pcb
{
const char *pcb_name;
int pcb_id;
};
// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
static const md_pcb pcb_list[] =
{
{"SEGA-EEPROM", SEGA_EEPROM},
{"SEGA-SRAM", SEGA_SRAM},
{"SEGA-FRAM", SEGA_FRAM},
{"CM-JCART", CM_JCART},
{"CM-JCART-SEPROM", CM_JCART_SEPROM},
{"CM-SEPROM", CODE_MASTERS},
{"SSF2", SSF2},
{"GAMEKANDUME", GAME_KANDUME},
{"BEGGAR", BEGGAR},
{"NBAJAM", NBA_JAM},
{"NBAJAMTE", NBA_JAM_TE},
{"NFLQB96", NFL_QB_96},
{"CSLAM", C_SLAM},
{"NHLPA", EA_NHLPA},
{"LIONK3", LIONK3},
{"SDK99", SDK99},
{"SKINGKONG", SKINGKONG},
{"REDCLIFF", REDCL_EN},
{"RADICA", RADICA},
{"KOF98", KOF98},
{"KOF99", KOF99},
{"SOULBLAD", SOULBLAD},
{"MJLOVER", MJLOVER},
{"SQUIRRELK", SQUIRRELK},
{"SMOUSE", SMOUSE},
{"SMB", SMB},
{"SMB2", SMB2},
{"KAIJU", KAIJU},
{"CHINFIGHT3", CHINFIGHT3},
{"LIONK2", LIONK2},
{"BUGSLIFE", BUGSLIFE},
{"ELFWOR", ELFWOR},
{"ROCKMANX3", ROCKMANX3},
{"SBUBBOB", SBUBBOB},
{"REALTEC", REALTEC},
{"MC_SUP19IN1", MC_SUP19IN1},
{"MC_SUP15IN1", MC_SUP15IN1},
{"MC_12IN1", MC_12IN1},
{"TOPFIGHTER", TOPFIGHTER},
{"POKEMON", POKEMON},
{"POKEMON2", POKEMON},
{"MULAN", MULAN}
};
static int md_get_pcb_id(const char *pcb)
{
int i;
for (i = 0; i < ARRAY_LENGTH(pcb_list); i++)
{
if (!mame_stricmp(pcb_list[i].pcb_name, pcb))
return pcb_list[i].pcb_id;
}
return SEGA_STD;
}
#define MAX_MD_CART_SIZE 0x500000
/* where a fresh copy of rom is stashed for reset and banking setup */
#define VIRGIN_COPY_GEN 0xd00000
/*************************************
*
* Handlers for custom mappers
*
*************************************/
/*************************************
* Super Street Fighter II
*************************************/
static WRITE16_HANDLER( genesis_ssf2_bank_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
UINT8 *ROM = space->machine().region("maincpu")->base();
if ((state->m_md_cart.ssf2_lastoff != offset) || (state->m_md_cart.ssf2_lastdata != data))
{
state->m_md_cart.ssf2_lastoff = offset;
state->m_md_cart.ssf2_lastdata = data;
switch (offset << 1)
{
case 0x00: /* write protect register */ // this is not a write protect, but seems to do nothing useful but reset bank0 after the checksum test (red screen otherwise)
if (data == 2)
{
memcpy(ROM + 0x000000, ROM + 0x400000 + (((data & 0xf) - 2) * 0x080000), 0x080000);
}
break;
case 0x02: /* 0x080000 - 0x0FFFFF */
memcpy(ROM + 0x080000, ROM + 0x400000 + ((data & 0xf) * 0x080000), 0x080000);
break;
case 0x04: /* 0x100000 - 0x17FFFF */
memcpy(ROM + 0x100000, ROM + 0x400000 + ((data & 0xf) * 0x080000), 0x080000);
break;
case 0x06: /* 0x180000 - 0x1FFFFF */
memcpy(ROM + 0x180000, ROM + 0x400000 + ((data & 0xf) * 0x080000), 0x080000);
break;
case 0x08: /* 0x200000 - 0x27FFFF */
memcpy(ROM + 0x200000, ROM + 0x400000 + ((data & 0xf) * 0x080000), 0x080000);
break;
case 0x0a: /* 0x280000 - 0x2FFFFF */
memcpy(ROM + 0x280000, ROM + 0x400000 + ((data & 0xf) * 0x080000), 0x080000);
break;
case 0x0c: /* 0x300000 - 0x37FFFF */
memcpy(ROM + 0x300000, ROM + 0x400000 + ((data & 0xf) * 0x080000), 0x080000);
break;
case 0x0e: /* 0x380000 - 0x3FFFFF */
memcpy(ROM + 0x380000, ROM + 0x400000 + ((data & 0xf) * 0x080000), 0x080000);
break;
}
}
}
/*************************************
* Lion King 3, Super King Kong 99
* & Super Donkey Kong 99
*************************************/
#ifdef UNUSED_FUNCTION
static WRITE16_HANDLER( l3alt_pdat_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.l3alt_pdat = data;
}
static WRITE16_HANDLER( l3alt_pcmd_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.l3alt_pcmd = data;
}
#endif
static READ16_HANDLER( l3alt_prot_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
int retdata = 0;
offset &= 0x07;
switch (offset)
{
case 2:
switch (state->m_md_cart.l3alt_pcmd)
{
case 1:
retdata = state->m_md_cart.l3alt_pdat >> 1;
break;
case 2:
retdata = state->m_md_cart.l3alt_pdat >> 4;
retdata |= (state->m_md_cart.l3alt_pdat & 0x0f) << 4;
break;
default:
/* printf("unk prot case %d\n", l3alt_pcmd); */
retdata = (BIT(state->m_md_cart.l3alt_pdat, 7) << 0);
retdata |= (BIT(state->m_md_cart.l3alt_pdat, 6) << 1);
retdata |= (BIT(state->m_md_cart.l3alt_pdat, 5) << 2);
retdata |= (BIT(state->m_md_cart.l3alt_pdat, 4) << 3);
retdata |= (BIT(state->m_md_cart.l3alt_pdat, 3) << 4);
retdata |= (BIT(state->m_md_cart.l3alt_pdat, 2) << 5);
retdata |= (BIT(state->m_md_cart.l3alt_pdat, 1) << 6);
retdata |= (BIT(state->m_md_cart.l3alt_pdat, 0) << 7);
break;
}
break;
default:
logerror("protection read, unknown offset\n");
break;
}
/* printf("%06x: l3alt_pdat_w %04x l3alt_pcmd_w %04x return %04x\n", activecpu_get_pc(), l3alt_pdat, l3alt_pcmd, retdata); */
return retdata;
}
static WRITE16_HANDLER( l3alt_prot_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
offset &= 0x7;
switch (offset)
{
case 0x0:
state->m_md_cart.l3alt_pdat = data;
break;
case 0x1:
state->m_md_cart.l3alt_pcmd = data;
break;
default:
logerror("protection write, unknown offst\n");
break;
}
}
static WRITE16_HANDLER( l3alt_bank_w )
{
offset &= 0x7;
switch (offset)
{
case 0:
{
UINT8 *ROM = space->machine().region("maincpu")->base();
/* printf("%06x data %04x\n",activecpu_get_pc(), data); */
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN + (data & 0xffff) * 0x8000], 0x8000);
}
break;
default:
logerror("unk bank w\n");
break;
}
}
/*************************************
* Whac a Critter/Mallet Legend,
* Defend the Earth, Funnyworld/Ballonboy
*************************************/
static WRITE16_HANDLER( realtec_402000_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.realtec_bank_addr = 0;
state->m_md_cart.realtec_bank_size = (data >> 8) & 0x1f;
}
static WRITE16_HANDLER( realtec_400000_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
int bankdata = (data >> 9) & 0x7;
UINT8 *ROM = space->machine().region("maincpu")->base();
state->m_md_cart.realtec_old_bank_addr = state->m_md_cart.realtec_bank_addr;
state->m_md_cart.realtec_bank_addr = (state->m_md_cart.realtec_bank_addr & 0x7) | bankdata << 3;
memcpy(ROM, ROM + (state->m_md_cart.realtec_bank_addr * 0x20000) + 0x400000, state->m_md_cart.realtec_bank_size * 0x20000);
memcpy(ROM + state->m_md_cart.realtec_bank_size * 0x20000, ROM + (state->m_md_cart.realtec_bank_addr * 0x20000) + 0x400000, state->m_md_cart.realtec_bank_size * 0x20000);
}
static WRITE16_HANDLER( realtec_404000_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
int bankdata = (data >> 8) & 0x3;
UINT8 *ROM = space->machine().region("maincpu")->base();
state->m_md_cart.realtec_old_bank_addr = state->m_md_cart.realtec_bank_addr;
state->m_md_cart.realtec_bank_addr = (state->m_md_cart.realtec_bank_addr & 0xf8) | bankdata;
if (state->m_md_cart.realtec_old_bank_addr != state->m_md_cart.realtec_bank_addr)
{
memcpy(ROM, ROM + (state->m_md_cart.realtec_bank_addr * 0x20000)+ 0x400000, state->m_md_cart.realtec_bank_size * 0x20000);
memcpy(ROM + state->m_md_cart.realtec_bank_size * 0x20000, ROM + (state->m_md_cart.realtec_bank_addr * 0x20000) + 0x400000, state->m_md_cart.realtec_bank_size * 0x20000);
}
}
/*************************************
* Chinese Fighters 3
*************************************/
static WRITE16_HANDLER( chifi3_bank_w )
{
UINT8 *ROM = space->machine().region("maincpu")->base();
if (data == 0xf100) // *hit player
{
int x;
for (x = 0; x < 0x100000; x += 0x10000)
{
memcpy(ROM + x, ROM + 0x410000, 0x10000);
}
}
else if (data == 0xd700) // title screen..
{
int x;
for (x = 0; x < 0x100000; x += 0x10000)
{
memcpy(ROM + x, ROM + 0x470000, 0x10000);
}
}
else if (data == 0xd300) // character hits floor
{
int x;
for (x = 0; x < 0x100000; x += 0x10000)
{
memcpy(ROM + x, ROM + 0x430000, 0x10000);
}
}
else if (data == 0x0000)
{
int x;
for (x = 0; x < 0x100000; x += 0x10000)
{
memcpy(ROM + x, ROM + 0x400000 + x, 0x10000);
}
}
else
{
logerror("%06x chifi3, bankw? %04x %04x\n", cpu_get_pc(&space->device()), offset, data);
}
}
static READ16_HANDLER( chifi3_prot_r )
{
UINT32 retdat;
/* not 100% correct, there may be some relationship between the reads here
and the writes made at the start of the game.. */
/*
04dc10 chifi3, prot_r? 2800
04cefa chifi3, prot_r? 65262
*/
if (cpu_get_pc(&space->device()) == 0x01782) // makes 'VS' screen appear
{
retdat = cpu_get_reg(&space->device(), M68K_D3) & 0xff;
retdat <<= 8;
return retdat;
}
else if (cpu_get_pc(&space->device()) == 0x1c24) // background gfx etc.
{
retdat = cpu_get_reg(&space->device(), M68K_D3) & 0xff;
retdat <<= 8;
return retdat;
}
else if (cpu_get_pc(&space->device()) == 0x10c4a) // unknown
{
return space->machine().rand();
}
else if (cpu_get_pc(&space->device()) == 0x10c50) // unknown
{
return space->machine().rand();
}
else if (cpu_get_pc(&space->device()) == 0x10c52) // relates to the game speed..
{
retdat = cpu_get_reg(&space->device(), M68K_D4) & 0xff;
retdat <<= 8;
return retdat;
}
else if (cpu_get_pc(&space->device()) == 0x061ae)
{
retdat = cpu_get_reg(&space->device(), M68K_D3) & 0xff;
retdat <<= 8;
return retdat;
}
else if (cpu_get_pc(&space->device()) == 0x061b0)
{
retdat = cpu_get_reg(&space->device(), M68K_D3) & 0xff;
retdat <<= 8;
return retdat;
}
else
{
logerror("%06x chifi3, prot_r? %04x\n", cpu_get_pc(&space->device()), offset);
}
return 0;
}
/*************************************
* Super 19 in 1 & Super 15 in 1
*************************************/
static WRITE16_HANDLER( s19in1_bank )
{
UINT8 *ROM = space->machine().region("maincpu")->base();
memcpy(ROM + 0x000000, ROM + 0x400000 + ((offset << 1) * 0x10000), 0x80000);
}
/*************************************
* Kaiju? (Pokemon Stadium)
*************************************/
static WRITE16_HANDLER( kaiju_bank_w )
{
UINT8 *ROM = space->machine().region("maincpu")->base();
memcpy(ROM + 0x000000, ROM + 0x400000 + (data & 0x7f) * 0x8000, 0x8000);
}
/*************************************
* Soulblade
*************************************/
static READ16_HANDLER( soulb_400006_r )
{
// printf("%06x soulb_400006_r\n",cpu_get_pc(&space->device()));
return 0xf000;
}
static READ16_HANDLER( soulb_400002_r )
{
// printf("%06x soulb_400002_r\n",cpu_get_pc(&space->device()));
return 0x9800;
}
static READ16_HANDLER( soulb_400004_r )
{
// return 0x9800;
// printf("%06x soulb_400004_r\n",cpu_get_pc(&space->device()));
//
return 0xc900;
//aa
//c9
}
/*************************************
* Mahjong Lover
*************************************/
static READ16_HANDLER( mjlovr_prot_1_r )
{
return 0x9000;
}
static READ16_HANDLER( mjlovr_prot_2_r )
{
return 0xd300;
}
/*************************************
* Super Mario Bros
*************************************/
static READ16_HANDLER( smbro_prot_r )
{
return 0xc;
}
/*************************************
* Smart Mouse
*************************************/
static READ16_HANDLER( smous_prot_r )
{
switch (offset)
{
case 0: return 0x5500;
case 1: return 0x0f00;
case 2: return 0xaa00;
case 3: return 0xf000;
}
return -1;
}
/*************************************
* Super Bubble Bobble MD
*************************************/
static READ16_HANDLER( sbub_extra1_r )
{
return 0x5500;
}
static READ16_HANDLER( sbub_extra2_r )
{
return 0x0f00;
}
/*************************************
* King of Fighters 99
*************************************/
static READ16_HANDLER( kof99_A13002_r )
{
// write 02 to a13002.. shift right 1?
return 0x01;
}
static READ16_HANDLER( kof99_00A1303E_r )
{
// write 3e to a1303e.. shift right 1?
return 0x1f;
}
static READ16_HANDLER( kof99_A13000_r )
{
// no write, startup check, chinese message if != 0
return 0x0;
}
/*************************************
* Radica controllers
*************************************/
static READ16_HANDLER( radica_bank_select )
{
int bank = offset & 0x3f;
UINT8 *ROM = space->machine().region("maincpu")->base();
memcpy(ROM, ROM + 0x400000 + (bank * 0x10000), 0x400000);
return 0;
}
/*************************************
* ROTK Red Cliff
*************************************/
static READ16_HANDLER( redclif_prot_r )
{
return -0x56 << 8;
}
static READ16_HANDLER( redclif_prot2_r )
{
return 0x55 << 8;
}
/*************************************
* Squirrel King
*************************************/
static READ16_HANDLER( squirrel_king_extra_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
return state->m_md_cart.squirrel_king_extra;
}
static WRITE16_HANDLER( squirrel_king_extra_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.squirrel_king_extra = data;
}
/*************************************
* Lion King 2
*************************************/
static READ16_HANDLER( lion2_prot1_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
return state->m_md_cart.lion2_prot1_data;
}
static READ16_HANDLER( lion2_prot2_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
return state->m_md_cart.lion2_prot2_data;
}
static WRITE16_HANDLER ( lion2_prot1_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.lion2_prot1_data = data;
}
static WRITE16_HANDLER ( lion2_prot2_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.lion2_prot2_data = data;
}
/*************************************
* Rockman X3
*************************************/
static READ16_HANDLER( rx3_extra_r )
{
return 0xc;
}
/*************************************
* King of Fighters 98
*************************************/
static READ16_HANDLER( kof98_aa_r )
{
return 0xaa00;
}
static READ16_HANDLER( kof98_0a_r )
{
return 0x0a00;
}
static READ16_HANDLER( kof98_00_r )
{
return 0x0000;
}
/*************************************
* Super Mario Bros 2
*************************************/
static READ16_HANDLER( smb2_extra_r )
{
return 0xa;
}
/*************************************
* A Bug's Life
*************************************/
static READ16_HANDLER( bugl_extra_r )
{
return 0x28;
}
/*************************************
* Linghuan Daoshi Super Magician
* (internal game name Elf Wor)
*************************************/
static READ16_HANDLER( elfwor_400000_r )
{
return 0x5500;
}
static READ16_HANDLER( elfwor_400002_r )
{
return 0x0f00;
}
static READ16_HANDLER( elfwor_400004_r )
{
return 0xc900;
}
static READ16_HANDLER( elfwor_400006_r )
{
return 0x1800;
}
/*************************************
* Top Fighter - there is more to
* this.. No display at startup etc..
*************************************/
static READ16_HANDLER( topfig_6BD294_r ) /* colours on title screen */
{
static int x = -1;
/*
cpu #0 (PC=00177192): unmapped program memory word write to 006BD240 = 00A8 & 00FF
cpu #0 (PC=0017719A): unmapped program memory word write to 006BD2D2 = 0098 & 00FF
cpu #0 (PC=001771A2): unmapped program memory word read from 006BD294 & 00FF
*/
if (cpu_get_pc(&space->device())==0x1771a2) return 0x50;
else
{
x++;
logerror("%06x topfig_6BD294_r %04x\n",cpu_get_pc(&space->device()), x);
return x;
}
}
static READ16_HANDLER( topfig_6F5344_r ) // after char select
{
static int x = -1;
if (cpu_get_pc(&space->device())==0x4C94E)
{
return cpu_get_reg(space->machine().device("maincpu"), (M68K_D0)) & 0xff;
}
else
{
x++;
logerror("%06x topfig_6F5344_r %04x\n",cpu_get_pc(&space->device()), x);
return x;
}
}
static WRITE16_HANDLER( topfig_bank_w )
{
UINT8 *ROM = space->machine().region("maincpu")->base();
if (data == 0x002a)
{
memcpy(ROM + 0x060000, ROM + 0x570000, 0x8000); // == 0x2e*0x8000?!
// printf("%06x offset %06x, data %04x\n",cpu_get_pc(&space->device()), offset, data);
}
else if (data==0x0035) // characters ingame
{
memcpy(ROM + 0x020000, ROM + 0x5a8000, 0x8000); // == 0x35*0x8000
}
else if (data==0x000f) // special moves
{
memcpy(ROM + 0x058000, ROM + 0x478000, 0x8000); // == 0xf*0x8000
}
else if (data==0x0000)
{
memcpy(ROM + 0x060000, ROM + 0x460000, 0x8000);
memcpy(ROM + 0x020000, ROM + 0x420000, 0x8000);
memcpy(ROM + 0x058000, ROM + 0x458000, 0x8000);
// printf("%06x offset %06x, data %04x\n",cpu_get_pc(&space->device()), offset, data);
}
else
{
logerror("%06x offset %06x, data %04x\n", cpu_get_pc(&space->device()), offset, data);
}
}
static READ16_HANDLER( topfig_645B44_r )
{
//cpu #0 (PC=0004DE00): unmapped program memory word write to 00689B80 = 004A & 00FF
//cpu #0 (PC=0004DE08): unmapped program memory word write to 00 = 00B5 & 00FF
//cpu #0 (PC=0004DE0C): unmapped program memory word read from 00645B44 & 00FF
return 0x9f;//0x25;
}
//cpu #0 (PC=0004CBAE): unmapped program memory word read from 006A35D4 & 00FF -- wants regD7
/*************************************
* 12 in 1 and other multigame carts
*************************************/
static WRITE16_HANDLER( mc_12in1_bank_w )
{
UINT8 *ROM = space->machine().region("maincpu")->base();
logerror("offset %06x", offset << 17);
memcpy(ROM + 0x000000, ROM + VIRGIN_COPY_GEN + ((offset & 0x3f) << 17), 0x100000);
}
/*************************************
* Stub for TMSS bios bank
*************************************/
static WRITE16_HANDLER( genesis_TMSS_bank_w )
{
/* this probably should do more, like make Genesis V2 'die' if the SEGA string is not written promptly */
}
/*************************************
*
* Handlers for SRAM & EEPROM
*
*************************************/
/*************************************
* SRAM
*************************************/
static READ16_HANDLER( genesis_sram_read )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
UINT8 *ROM;
int rom_offset;
if (state->m_md_cart.sram_active)
return state->m_md_cart.sram[offset];
else
{
ROM = space->machine().region("maincpu")->base();
rom_offset = state->m_md_cart.sram_start + (offset << 1);
return (UINT16) ROM[rom_offset] | (ROM[rom_offset + 1] << 8);
}
}
static WRITE16_HANDLER( genesis_sram_write )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
if (state->m_md_cart.sram_active)
{
if (!state->m_md_cart.sram_readonly)
state->m_md_cart.sram[offset] = data;
}
}
static void install_sram_rw_handlers(running_machine &machine, bool mask_addr)
{
md_cons_state *state = machine.driver_data<md_cons_state>();
device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
// if sram_start/end come from the cart header, they might be incorrect! from softlist, they are fine.
UINT32 mask = mask_addr ? 0x3fffff : 0xffffff;
mame_printf_debug("Allocing %d bytes for sram\n", state->m_md_cart.sram_end - state->m_md_cart.sram_start + 1);
state->m_md_cart.sram = auto_alloc_array(machine, UINT16, (state->m_md_cart.sram_end - state->m_md_cart.sram_start + 1) / sizeof(UINT16));
image->battery_load(state->m_md_cart.sram, state->m_md_cart.sram_end - state->m_md_cart.sram_start + 1, 0xff); // Dino Dini's Soccer needs backup RAM to be 1fill
memcpy(megadriv_backupram, state->m_md_cart.sram, state->m_md_cart.sram_end - state->m_md_cart.sram_start + 1);
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(state->m_md_cart.sram_start & mask, state->m_md_cart.sram_end & mask, FUNC(genesis_sram_read));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(state->m_md_cart.sram_start & mask, state->m_md_cart.sram_end & mask, FUNC(genesis_sram_write));
state->m_md_cart.sram_handlers_installed = 1;
}
static WRITE16_HANDLER( genesis_sram_toggle )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
/* unsure if this is actually supposed to toggle or just switch on?
Yet to encounter game that utilizes */
state->m_md_cart.sram_active = (data & 1) ? 1 : 0;
state->m_md_cart.sram_readonly = (data & 2) ? 1 : 0;
if (state->m_md_cart.sram_active && !state->m_md_cart.sram_handlers_installed)
install_sram_rw_handlers(space->machine(), TRUE);
}
static READ16_HANDLER( sega_6658a_reg_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
return state->m_md_cart.sram_active;
}
static WRITE16_HANDLER( sega_6658a_reg_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
if (data == 1)
state->m_md_cart.sram_active = 1;
if (data == 0)
state->m_md_cart.sram_active = 0;
}
/*************************************
* I2C EEPROM
* bare minimum handlings
* TODO: supports proper device interfacing and parameter change!
*************************************/
static READ16_HANDLER( nba_jam_eeprom_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
// state->m_md_cart.i2c_mem = (i2cmem_sda_read(space->machine().device("i2cmem")) & 1);
return state->m_md_cart.i2c_mem & 1;
}
static WRITE16_HANDLER( nba_jam_eeprom_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.i2c_clk = (data & 0x0002) >> 1;
state->m_md_cart.i2c_mem = (data & 0x0001);
// i2cmem_sda_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_clk);
// i2cmem_scl_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_mem);
}
static READ16_HANDLER( nba_jam_te_eeprom_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
// state->m_md_cart.i2c_mem = (i2cmem_sda_read(space->machine().device("i2cmem")) & 1);
return (state->m_md_cart.i2c_mem & 1);
}
static WRITE16_HANDLER( nba_jam_te_eeprom_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.i2c_clk = ((data & 0x0100) >> 8);
state->m_md_cart.i2c_mem = data & 0x0001;
// i2cmem_sda_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_clk);
// i2cmem_scl_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_mem);
}
static READ16_HANDLER( ea_nhlpa_eeprom_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
// state->m_md_cart.i2c_mem = (i2cmem_sda_read(space->machine().device("i2cmem")) & 1);
return (state->m_md_cart.i2c_mem & 1) << 7;
}
static WRITE16_HANDLER( ea_nhlpa_eeprom_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.i2c_clk = ((data & 0x0040) >> 6);
state->m_md_cart.i2c_mem = ((data & 0x0080) >> 7);
// i2cmem_sda_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_clk);
// i2cmem_scl_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_mem);
}
/* TODO: identical as NBA Jam, used as kludge */
static READ16_HANDLER( wboy_v_eeprom_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
// state->m_md_cart.i2c_mem = (i2cmem_sda_read(space->machine().device("i2cmem")) & 1);
return ~state->m_md_cart.i2c_mem & 1;
}
static WRITE16_HANDLER( wboy_v_eeprom_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.i2c_clk = (data & 0x0002) >> 1;
state->m_md_cart.i2c_mem = (data & 0x0001);
// i2cmem_sda_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_clk);
// i2cmem_scl_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_mem);
}
static READ16_HANDLER( codemasters_eeprom_r )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
// state->m_md_cart.i2c_mem = (i2cmem_sda_read(space->machine().device("i2cmem")) & 1);
return (state->m_md_cart.i2c_mem & 1) << 7;
}
static WRITE16_HANDLER( codemasters_eeprom_w )
{
md_cons_state *state = space->machine().driver_data<md_cons_state>();
state->m_md_cart.i2c_clk = (data & 0x0200) >> 9;
state->m_md_cart.i2c_mem = (data & 0x0100) >> 8;
// i2cmem_sda_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_clk);
// i2cmem_scl_write(space->machine().device("i2cmem"), state->m_md_cart.i2c_mem);
}
/*************************************
*
* Machine driver reset
*
*************************************/
static void setup_megadriv_custom_mappers(running_machine &machine)
{
md_cons_state *state = machine.driver_data<md_cons_state>();
UINT32 mirroraddr;
UINT8 *ROM = machine.region("maincpu")->base();
switch (state->m_md_cart.type)
{
case CM_JCART:
case CM_JCART_SEPROM:
/* Codemasters PCB (J-Carts) */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x38fffe, 0x38ffff, FUNC(jcart_ctrl_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x38fffe, 0x38ffff, FUNC(jcart_ctrl_w));
break;
case SSF2:
memcpy(&ROM[0x800000], &ROM[VIRGIN_COPY_GEN + 0x400000], 0x100000);
memcpy(&ROM[0x400000], &ROM[VIRGIN_COPY_GEN], 0x400000);
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN], 0x400000);
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xa130f0, 0xa130ff, FUNC(genesis_ssf2_bank_w));
break;
case LIONK3:
case SKINGKONG:
state->m_md_cart.l3alt_pdat = state->m_md_cart.l3alt_pcmd = 0;
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN], 0x200000); /* default rom */
memcpy(&ROM[0x200000], &ROM[VIRGIN_COPY_GEN], 0x200000); /* default rom */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x600000, 0x6fffff, FUNC(l3alt_prot_r), FUNC(l3alt_prot_w));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x700000, 0x7fffff, FUNC(l3alt_bank_w));
break;
case SDK99:
state->m_md_cart.l3alt_pdat = state->m_md_cart.l3alt_pcmd = 0;
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN], 0x300000); /* default rom */
memcpy(&ROM[0x300000], &ROM[VIRGIN_COPY_GEN], 0x100000); /* default rom */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x600000, 0x6fffff, FUNC(l3alt_prot_r), FUNC(l3alt_prot_w));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x700000, 0x7fffff, FUNC(l3alt_bank_w));
break;
case REDCLIFF:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400001, FUNC(redclif_prot2_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400004, 0x400005, FUNC(redclif_prot_r));
break;
case REDCL_EN:
for (int x = VIRGIN_COPY_GEN; x < VIRGIN_COPY_GEN + 0x200005; x++)
ROM[x] ^= 0x40;
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN + 4], 0x200000); /* default rom */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400001, FUNC(redclif_prot2_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400004, 0x400005, FUNC(redclif_prot_r));
break;
case RADICA:
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN], 0x400000);
memcpy(&ROM[0x400000], &ROM[VIRGIN_COPY_GEN], 0x400000); // keep a copy for later banking.. making use of huge ROM_REGION allocated to genesis driver
memcpy(&ROM[0x800000], &ROM[VIRGIN_COPY_GEN], 0x400000); // wraparound banking (from hazemd code)
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa13000, 0xa1307f, FUNC(radica_bank_select));
break;
case KOF99:
//memcpy(&ROM[0x000000],&ROM[VIRGIN_COPY_GEN],0x300000);
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa13000, 0xa13001, FUNC(kof99_A13000_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa13002, 0xa13003, FUNC(kof99_A13002_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa1303e, 0xa1303f, FUNC(kof99_00A1303E_r));
break;
case SOULBLAD:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400002, 0x400003, FUNC(soulb_400002_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400004, 0x400005, FUNC(soulb_400004_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400006, 0x400007, FUNC(soulb_400006_r));
break;
case MJLOVER:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400001, FUNC(mjlovr_prot_1_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x401000, 0x401001, FUNC(mjlovr_prot_2_r));
break;
case SQUIRRELK:
state->m_md_cart.squirrel_king_extra = 0;
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400007, FUNC(squirrel_king_extra_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x400000, 0x400007, FUNC(squirrel_king_extra_w));
break;
case SMOUSE:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400007, FUNC(smous_prot_r));
break;
case SMB:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa13000, 0xa13001, FUNC(smbro_prot_r));
break;
case SMB2:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa13000, 0xa13001, FUNC(smb2_extra_r));
break;
case KAIJU:
memcpy(&ROM[0x400000], &ROM[VIRGIN_COPY_GEN], 0x200000);
memcpy(&ROM[0x600000], &ROM[VIRGIN_COPY_GEN], 0x200000);
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN], 0x200000);
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x700000, 0x7fffff, FUNC(kaiju_bank_w));
break;
case CHINFIGHT3:
memcpy(&ROM[0x400000], &ROM[VIRGIN_COPY_GEN], 0x200000);
memcpy(&ROM[0x600000], &ROM[VIRGIN_COPY_GEN], 0x200000);
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN], 0x200000);
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x4fffff, FUNC(chifi3_prot_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x600000, 0x6fffff, FUNC(chifi3_bank_w));
break;
case LIONK2:
state->m_md_cart.lion2_prot1_data = state->m_md_cart.lion2_prot2_data = 0;
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400002, 0x400003, FUNC(lion2_prot1_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400006, 0x400007, FUNC(lion2_prot2_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x400000, 0x400001, FUNC(lion2_prot1_w));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x400004, 0x400005, FUNC(lion2_prot2_w));
break;
case BUGSLIFE:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa13000, 0xa13001, FUNC(bugl_extra_r));
break;
case ELFWOR:
/* It return (0x55 @ 0x400000 OR 0xc9 @ 0x400004) AND (0x0f @ 0x400002 OR 0x18 @ 0x400006). It is probably best to add handlers for all 4 addresses. */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400001, FUNC(elfwor_400000_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400002, 0x400003, FUNC(elfwor_400002_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400004, 0x400005, FUNC(elfwor_400004_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400006, 0x400007, FUNC(elfwor_400006_r));
break;
case ROCKMANX3:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa13000, 0xa13001, FUNC(rx3_extra_r));
break;
case SBUBBOB:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400001, FUNC(sbub_extra1_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400002, 0x400003, FUNC(sbub_extra2_r));
break;
case KOF98:
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x480000, 0x480001, FUNC(kof98_aa_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x4800e0, 0x4800e1, FUNC(kof98_aa_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x4824a0, 0x4824a1, FUNC(kof98_aa_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x488880, 0x488881, FUNC(kof98_aa_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x4a8820, 0x4a8821, FUNC(kof98_0a_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x4f8820, 0x4f8821, FUNC(kof98_00_r));
break;
case REALTEC:
/* Realtec mapper!*/
state->m_md_cart.realtec_bank_addr = state->m_md_cart.realtec_bank_size = 0;
state->m_md_cart.realtec_old_bank_addr = -1;
memcpy(&ROM[0x400000], &ROM[VIRGIN_COPY_GEN], 0x80000);
for (mirroraddr = 0; mirroraddr < 0x400000; mirroraddr += 0x2000)
memcpy(ROM + mirroraddr, ROM + VIRGIN_COPY_GEN + 0x7e000, 0x002000); /* copy last 8kb across the whole rom region */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x400000, 0x400001, FUNC(realtec_400000_w));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x402000, 0x402001, FUNC(realtec_402000_w));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x404000, 0x404001, FUNC(realtec_404000_w));
break;
case MC_SUP19IN1:
memcpy(&ROM[0x400000], &ROM[VIRGIN_COPY_GEN], 0x400000); // allow hard reset to menu
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xa13000, 0xa13039, FUNC(s19in1_bank));
break;
case MC_SUP15IN1:
memcpy(&ROM[0x400000], &ROM[VIRGIN_COPY_GEN], 0x200000); // allow hard reset to menu
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xa13000, 0xa13039, FUNC(s19in1_bank));
break;
case MC_12IN1:
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN], 0x400000); /* default rom */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xa13000, 0xa1303f, FUNC(mc_12in1_bank_w));
break;
case TOPFIGHTER:
memcpy(&ROM[0x000000], &ROM[VIRGIN_COPY_GEN], 0x400000); /* default rom */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x6f5344, 0x6f5345, FUNC(topfig_6F5344_r) );
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x6bd294, 0x6bd295, FUNC(topfig_6BD294_r) );
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x645b44, 0x645b45, FUNC(topfig_645B44_r) );
/* readd */
//machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x689b80, 0x689b81, FUNC(MWA16_NOP));
//machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x6d8b02, 0x6d8b03, FUNC(MWA16_NOP));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x700000, 0x7fffff, FUNC(topfig_bank_w) );
break;
}
/* games whose protection gets patched out */
if (state->m_md_cart.type == POKEMON)
{
/*todo: emulate protection instead
0DD19E:47F8
0DD1A0:FFF0
0DD1A2:4E63
0DD46E:4EF8
0DD470:0300
0DD49C:6002
*/
/*
you need to return 1 @ 0xa13002 and 0???1f @ 0xa1303E (it does word reads).
*/
UINT16 *ROM16 = (UINT16 *)machine.region("maincpu")->base();
ROM16[0x0dd19e/2] = 0x47F8;
ROM16[0x0dd1a0/2] = 0xFFF0;
ROM16[0x0dd1a2/2] = 0x4E63;
ROM16[0x0dd46e/2] = 0x4EF8;
ROM16[0x0dd470/2] = 0x0300;
ROM16[0x0dd49c/2] = 0x6002;
}
if (state->m_md_cart.type == POKEMON2)
{
/*todo: emulate protection instead
006036:E000
002540:6026
001ED0:6026
002476:6022
*/
UINT16 *ROM16 = (UINT16 *)machine.region("maincpu")->base();
ROM16[0x06036/2] = 0xE000;
ROM16[0x02540/2] = 0x6026;
ROM16[0x01ED0/2] = 0x6026;
ROM16[0x02476/2] = 0x6022;
ROM16[0x7E300/2] = 0x60FE;
}
if (state->m_md_cart.type == MULAN)
{
/*todo: emulate protection instead
006036:E000
+more?
*/
// ROM[0x01ED0/2] = 0xE000;
// ROM[0x02540/2] = 0xE000;
UINT16 *ROM16 = (UINT16 *)machine.region("maincpu")->base();
ROM16[0x06036/2] = 0xE000;
}
/* install NOP handler for TMSS */
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xa14000, 0xa14003, FUNC(genesis_TMSS_bank_w));
}
static void setup_megadriv_sram(device_image_interface &image)
{
running_machine &machine = image.device().machine();
md_cons_state *state = machine.driver_data<md_cons_state>();
UINT8 *ROM = machine.region("maincpu")->base();
megadriv_backupram = NULL;
state->m_md_cart.sram = NULL;
state->m_md_cart.sram_start = state->m_md_cart.sram_end = 0;
state->m_md_cart.has_serial_eeprom = 0;
state->m_md_cart.sram_detected = 0;
state->m_md_cart.sram_handlers_installed = 0;
state->m_md_cart.sram_readonly = 0;
state->m_md_cart.sram_active = 0;
/* install SRAM & i2c handlers for the specific type of cart */
switch (state->m_md_cart.type)
{
// These types only come from xml
// TODO: Eventually megadriv_backupram should point to the allocated cart:sram region!
// For now, we only use the region as a placeholder to carry size info...
case SEGA_SRAM:
state->m_md_cart.sram_start = 0x200000;
state->m_md_cart.sram_end = state->m_md_cart.sram_start + image.get_software_region_length("sram") - 1;
state->m_md_cart.sram_detected = 1;
megadriv_backupram = (UINT16*) (ROM + state->m_md_cart.sram_start);
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xa130f0, 0xa130f1, FUNC(genesis_sram_toggle));
if (state->m_md_cart.last_loaded_image_length <= state->m_md_cart.sram_start)
{
state->m_md_cart.sram_active = 1;
install_sram_rw_handlers(machine, FALSE);
}
break;
case BEGGAR:
state->m_md_cart.sram_start = 0x400000;
state->m_md_cart.sram_end = state->m_md_cart.sram_start + 0xffff;
state->m_md_cart.sram_detected = 1;
state->m_md_cart.sram_active = 1;
megadriv_backupram = (UINT16*) (ROM + state->m_md_cart.sram_start);
install_sram_rw_handlers(machine, FALSE);
break;
case SEGA_FRAM:
state->m_md_cart.sram_start = 0x200000;
state->m_md_cart.sram_end = state->m_md_cart.sram_start + image.get_software_region_length("fram") - 1;
state->m_md_cart.sram_detected = 1;
megadriv_backupram = (UINT16*) (ROM + state->m_md_cart.sram_start);
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xa130f0, 0xa130f1, FUNC(sega_6658a_reg_r));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xa130f0, 0xa130f1, FUNC(sega_6658a_reg_w));
install_sram_rw_handlers(machine, FALSE);
break;
// These types might come either from xml or from old-styele loading
case SEGA_EEPROM:
state->m_md_cart.has_serial_eeprom = 1;
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x200000, 0x200001, FUNC(wboy_v_eeprom_r), FUNC(wboy_v_eeprom_w));
break;
case NBA_JAM:
state->m_md_cart.has_serial_eeprom = 1;
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x200000, 0x200001, FUNC(nba_jam_eeprom_r), FUNC(nba_jam_eeprom_w));
break;
case NBA_JAM_TE:
case NFL_QB_96:
case C_SLAM: // same handling but different sizes
state->m_md_cart.has_serial_eeprom = 1;
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x200000, 0x200001, FUNC(nba_jam_te_eeprom_r), FUNC(nba_jam_te_eeprom_w));
break;
case EA_NHLPA:
state->m_md_cart.has_serial_eeprom = 1;
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x200000, 0x200001, FUNC(ea_nhlpa_eeprom_r), FUNC(ea_nhlpa_eeprom_w));
break;
case CODE_MASTERS:
case CM_JCART_SEPROM:
state->m_md_cart.has_serial_eeprom = 1;
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x300000, 0x300001, FUNC(codemasters_eeprom_w));
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x380000, 0x380001, FUNC(codemasters_eeprom_r));
break;
}
// If the cart is not of a special type, we check the header. Unfortunately, there are ROMs without correct info in the header,
// hence we do the mapping anyway, but we activate SRAM later only if the game will access it.
if (!state->m_md_cart.sram_detected && !state->m_md_cart.has_serial_eeprom)
{
/* check if cart has battery save */
if (ROM[0x1b1] == 'R' && ROM[0x1b0] == 'A')
{
/* SRAM info found in header */
state->m_md_cart.sram_start = (ROM[0x1b5] << 24 | ROM[0x1b4] << 16 | ROM[0x1b7] << 8 | ROM[0x1b6]);
state->m_md_cart.sram_end = (ROM[0x1b9] << 24 | ROM[0x1b8] << 16 | ROM[0x1bb] << 8 | ROM[0x1ba]);
if ((state->m_md_cart.sram_start > state->m_md_cart.sram_end) || ((state->m_md_cart.sram_end - state->m_md_cart.sram_start) >= 0x10000)) // we assume at most 64k of SRAM (HazeMD uses at most 64k). is this correct?
state->m_md_cart.sram_end = state->m_md_cart.sram_start + 0x0FFFF;
/* for some games using serial EEPROM, difference between SRAM
end to start is 0 or 1. Currently EEPROM is not emulated. */
if ((state->m_md_cart.sram_end - state->m_md_cart.sram_start) < 2)
state->m_md_cart.has_serial_eeprom = 1;
else
state->m_md_cart.sram_detected = 1;
}
else
{
/* set default SRAM positions, with size = 64k */
state->m_md_cart.sram_start = 0x200000;
state->m_md_cart.sram_end = state->m_md_cart.sram_start + 0xffff;
}
if (state->m_md_cart.sram_start & 1)
state->m_md_cart.sram_start -= 1;
if (!(state->m_md_cart.sram_end & 1))
state->m_md_cart.sram_end += 1;
/* calculate backup RAM location */
megadriv_backupram = (UINT16*) (ROM + (state->m_md_cart.sram_start & 0x3fffff));
if (state->m_md_cart.sram_detected)
logerror("SRAM detected from header: starting location %X - SRAM Length %X\n", state->m_md_cart.sram_start, state->m_md_cart.sram_end - state->m_md_cart.sram_start + 1);
/* Enable SRAM handlers only if the game does not use EEPROM. */
if (!state->m_md_cart.has_serial_eeprom)
{
/* Info from DGen: If SRAM does not overlap main ROM, set it active by
default since a few games can't manage to properly switch it on/off. */
if (state->m_md_cart.last_loaded_image_length <= state->m_md_cart.sram_start)
state->m_md_cart.sram_active = 1;
machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xa130f0, 0xa130f1, FUNC(genesis_sram_toggle));
//printf("res: start %x, end %x, det %d, active %d\n", state->m_md_cart.sram_start, state->m_md_cart.sram_end, state->m_md_cart.sram_detected, state->m_md_cart.sram_active);
/* Sonic 1 included in Sonic Classics doesn't have SRAM and
does lots of ROM access at this range, then only install read/
write handlers if SRAM is active to not slow down emulation. */
if (state->m_md_cart.sram_active)
install_sram_rw_handlers(machine, TRUE);
}
}
}
/*************************************
*
* CART HANDLING
*
*************************************/
/*************************************
* Helper function: Memcmp for both
* endianness
*************************************/
static int allendianmemcmp(const void *s1, const void *s2, size_t n)
{
const unsigned char *realbuf;
#ifdef LSB_FIRST
unsigned char flippedbuf[64];
unsigned int i;
if ((n & 1) || (n > 63)) return -1 ; // don't want odd sized buffers or too large a compare
for (i = 0; i < n; i++) flippedbuf[i] = *((char *)s2 + (i ^ 1));
realbuf = flippedbuf;
#else
realbuf = (unsigned char *)s2;
#endif
return memcmp(s1,realbuf,n);
}
/*************************************
* Helper function: Detect SMD file
*************************************/
/* code taken directly from GoodGEN by Cowering */
static int genesis_is_funky_SMD(unsigned char *buf,unsigned int len)
{
/* aq quiz */
if (!strncmp("UZ(-01 ", (const char *) &buf[0xf0], 8))
return 1;
/* Phelios USA redump */
/* target earth */
/* klax (namcot) */
if (buf[0x2080] == ' ' && buf[0x0080] == 'S' && buf[0x2081] == 'E' && buf[0x0081] == 'G')
return 1;
/* jap baseball 94 */
if (!strncmp("OL R-AEAL", (const char *) &buf[0xf0], 9))
return 1;
/* devilish Mahjong Tower */
if (!strncmp("optrEtranet", (const char *) &buf[0xf3], 11))
return 1;
/* golden axe 2 beta */
if (buf[0x0100] == 0x3c && buf[0x0101] == 0 && buf[0x0102] == 0 && buf[0x0103] == 0x3c)
return 1;
/* omega race */
if (!strncmp("OEARC ", (const char *) &buf[0x90], 8))
return 1;
/* budokan beta */
if ((len >= 0x6708+8) && !strncmp(" NTEBDKN", (const char *) &buf[0x6708], 8))
return 1;
/* cdx pro 1.8 bios */
if (!strncmp("so fCXP", (const char *) &buf[0x2c0], 7))
return 1;
/* ishido (hacked) */
if (!strncmp("sio-Wyo ", (const char *) &buf[0x0090], 8))
return 1;
/* onslaught */
if (!strncmp("SS CAL ", (const char *) &buf[0x0088], 8))
return 1;
/* tram terror pirate */
if ((len >= 0x3648 + 8) && !strncmp("SG NEPIE", (const char *) &buf[0x3648], 8))
return 1;
/* breath of fire 3 chinese */
if (buf[0x0007] == 0x1c && buf[0x0008] == 0x0a && buf[0x0009] == 0xb8 && buf[0x000a] == 0x0a)
return 1;
/*tetris pirate */
if ((len >= 0x1cbe + 5) && !strncmp("@TTI>", (const char *) &buf[0x1cbe], 5))
return 1;
return 0;
}
/* code taken directly from GoodGEN by Cowering */
static int genesis_is_SMD(unsigned char *buf,unsigned int len)
{
if (buf[0x2080] == 'S' && buf[0x80] == 'E' && buf[0x2081] == 'G' && buf[0x81] == 'A')
return 1;
return genesis_is_funky_SMD(buf,len);
}
/*************************************
* Loading a cart image *not* from
* softlist
*************************************/
static int megadrive_load_nonlist(device_image_interface &image)
{
md_cons_state *state = image.device().machine().driver_data<md_cons_state>();
unsigned char *ROM, *rawROM, *tmpROMnew, *tmpROM, *secondhalf;
int relocate, length, ptr, x;
#ifdef LSB_FIRST
unsigned char fliptemp;
#endif
// STEP 1: determine the file type (SMD? MD? BIN?)
rawROM = image.device().machine().region("maincpu")->base();
ROM = rawROM /*+ 512 */;
state->m_md_cart.last_loaded_image_length = -1;
length = image.fread( rawROM + 0x2000, 0x600000);
logerror("image length = 0x%x\n", length);
/* is this a SMD file? */
if (genesis_is_SMD(&rawROM[0x2200], (unsigned)length))
{
tmpROMnew = ROM;
tmpROM = ROM + 0x2000 + 512;
for (ptr = 0; ptr < MAX_MD_CART_SIZE / (8192); ptr += 2)
{
for (x = 0; x < 8192; x++)
{
*tmpROMnew++ = *(tmpROM + ((ptr + 1) * 8192) + x);
*tmpROMnew++ = *(tmpROM + ((ptr + 0) * 8192) + x);
}
}
#ifdef LSB_FIRST
tmpROMnew = ROM;
for (ptr = 0; ptr < length; ptr += 2)
{
fliptemp = tmpROMnew[ptr];
tmpROMnew[ptr] = tmpROMnew[ptr + 1];
tmpROMnew[ptr + 1] = fliptemp;
}
#endif
state->m_md_cart.last_loaded_image_length = length - 512;
memcpy(&ROM[VIRGIN_COPY_GEN], &ROM[0x000000], MAX_MD_CART_SIZE); /* store a copy of data */
relocate = 0;
}
/* is this a MD file? */
else if ((rawROM[0x2080] == 'E') && (rawROM[0x2081] == 'A') &&
(rawROM[0x2082] == 'M' || rawROM[0x2082] == 'G'))
{
tmpROMnew = (unsigned char *)osd_malloc(length);
secondhalf = &tmpROMnew[length >> 1];
if (!tmpROMnew)
{
logerror("Memory allocation failed reading roms!\n");
return IMAGE_INIT_FAIL;
}
memcpy(tmpROMnew, ROM + 0x2000, length);
for (ptr = 0; ptr < length; ptr += 2)
{
ROM[ptr] = secondhalf[ptr >> 1];
ROM[ptr + 1] = tmpROMnew[ptr >> 1];
}
free(tmpROMnew);
#ifdef LSB_FIRST
for (ptr = 0; ptr < length; ptr += 2)
{
fliptemp = ROM[ptr];
ROM[ptr] = ROM[ptr+1];
ROM[ptr+1] = fliptemp;
}
#endif
state->m_md_cart.last_loaded_image_length = length;
memcpy(&ROM[VIRGIN_COPY_GEN], &ROM[0x000000], MAX_MD_CART_SIZE); /* store a copy of data */
relocate = 0;
}
/* BIN it is, then */
else
{
relocate = 0x2000;
state->m_md_cart.last_loaded_image_length = length;
for (ptr = 0; ptr < MAX_MD_CART_SIZE + relocate; ptr += 2) /* mangle bytes for little endian machines */
{
#ifdef LSB_FIRST
int temp = ROM[relocate + ptr];
ROM[ptr] = ROM[relocate + ptr + 1];
ROM[ptr + 1] = temp;
#else
ROM[ptr] = ROM[relocate + ptr];
ROM[ptr + 1] = ROM[relocate + ptr + 1];
#endif
}
memcpy(&ROM[VIRGIN_COPY_GEN], &ROM[0x000000], MAX_MD_CART_SIZE); /* store a copy of data */
}
// STEP 2: determine the cart type (to deal with pirate mappers & eeprom)
/* Default cartridge type */
state->m_md_cart.type = SEGA_STD;
/* Detect carts which need additional handlers */
{
static const unsigned char smouse_sig[] = { 0x4d, 0xf9, 0x00, 0x40, 0x00, 0x02 },
mjlover_sig[] = { 0x13, 0xf9, 0x00, 0x40, 0x00, 0x00 }, // move.b ($400000).l,($FFFF0C).l (partial)
squir_sig[] = { 0x26, 0x79, 0x00, 0xff, 0x00, 0xfa },
bugsl_sig[] = { 0x20, 0x12, 0x13, 0xc0, 0x00, 0xff },
sbub_sig[] = { 0x0c, 0x39, 0x00, 0x55, 0x00, 0x40 }, // cmpi.b #$55,($400000).l
lk3_sig[] = { 0x0c, 0x01, 0x00, 0x30, 0x66, 0xe4 },
sdk_sig[] = { 0x48, 0xe7, 0xff, 0xfe, 0x52, 0x79 },
redcliff_sig[] = { 0x10, 0x39, 0x00, 0x40, 0x00, 0x04 }, // move.b ($400004).l,d0
redcl_en_sig[] = { 0x50, 0x79, 0x40, 0x00, 0x40, 0x44 }, // move.b ($400004).l,d0
smb_sig[] = { 0x20, 0x4d, 0x41, 0x52, 0x49, 0x4f },
smb2_sig[] = { 0x4e, 0xb9, 0x00, 0x0f, 0x25, 0x84 },
kaiju_sig[] = { 0x19, 0x7c, 0x00, 0x01, 0x00, 0x00 },
chifi3_sig[] = { 0xb6, 0x16, 0x66, 0x00, 0x00, 0x4a },
lionk2_sig[] = { 0x26, 0x79, 0x00, 0xff, 0x00, 0xf4 },
rx3_sig[] = { 0x66, 0x00, 0x00, 0x0e, 0x30, 0x3c },
kof98_sig[] = { 0x9b, 0xfc, 0x00, 0x00, 0x4a, 0x00 },
s15in1_sig[] = { 0x22, 0x3c, 0x00, 0xa1, 0x30, 0x00 },
kof99_sig[] = { 0x20, 0x3c, 0x30, 0x00, 0x00, 0xa1 }, // move.l #$300000A1,d0
radica_sig[] = { 0x4e, 0xd0, 0x30, 0x39, 0x00, 0xa1 }, // jmp (a0) move.w ($a130xx),d0
soulb_sig[] = { 0x33, 0xfc, 0x00, 0x0c, 0x00, 0xff }, // move.w #$C,($FF020A).l (what happens if check fails)
s19in1_sig[] = { 0x13, 0xc0, 0x00, 0xa1, 0x30, 0x38 },
rockman_sig[] = { 0xea, 0x80 };
switch (state->m_md_cart.last_loaded_image_length)
{
case 0x80000:
if (!allendianmemcmp(&ROM[0x08c8], &smouse_sig[0], sizeof(smouse_sig)))
state->m_md_cart.type = SMOUSE;
if (!allendianmemcmp((char *)&ROM[0x7e30e], "SEGA", 4) ||
!allendianmemcmp((char *)&ROM[0x7e100], "SEGA", 4) ||
!allendianmemcmp((char *)&ROM[0x7e1e6], "SEGA", 4))
state->m_md_cart.type = REALTEC;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-50396", 10)) // NHLPA Hockey 93
state->m_md_cart.type = EA_NHLPA;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM MK-1215", 10)) // Evander Holyfield
state->m_md_cart.type = SEGA_EEPROM;
break;
case 0xc0000:
if (!allendianmemcmp((char *)&ROM[0x0180], "GM G-4060 ", 8)) // Wonder Boy V
state->m_md_cart.type = SEGA_EEPROM;
break;
case 0x100000:
if (!allendianmemcmp(&ROM[0x01b24], &mjlover_sig[0], sizeof(mjlover_sig)))
state->m_md_cart.type = MJLOVER;
if (!allendianmemcmp(&ROM[0x03b4], &squir_sig[0], sizeof(squir_sig)))
state->m_md_cart.type = SQUIRRELK;
if (!allendianmemcmp(&ROM[0xee0d0], &bugsl_sig[0], sizeof(bugsl_sig)))
state->m_md_cart.type = BUGSLIFE;
if (!allendianmemcmp((char *)&ROM[0x0172], "GAME : ELF WOR", 14))
state->m_md_cart.type = ELFWOR;
if (!allendianmemcmp(&ROM[0x123e4], &sbub_sig[0], sizeof(sbub_sig)))
state->m_md_cart.type = SBUBBOB;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-50176", 10)) // Rings of Power
state->m_md_cart.type = EA_NHLPA;
if (!allendianmemcmp((char *)&ROM[0x0180], "MK 00001211-00", 14)) // Sports Talk Baseball
state->m_md_cart.type = SEGA_EEPROM;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-120096-", 12)) // Micro Machines 2
state->m_md_cart.type = CODE_MASTERS;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-120146-", 12)) // Brian Lara Cricket 96 / Shane Wayne Cricket 96
state->m_md_cart.type = CODE_MASTERS;
if (!allendianmemcmp((char *)&ROM[0x0190], "OJKRPTBVFCA ", 0x10)) // Micro Machines '96 / Military TODO: better way to recognize these?
state->m_md_cart.type = CODE_MASTERS;
break;
case 0x200000:
if (!allendianmemcmp(&ROM[0x18c6], &lk3_sig[0], sizeof(lk3_sig)))
state->m_md_cart.type = LIONK3;
if (!allendianmemcmp(&ROM[0x220], &sdk_sig[0], sizeof(sdk_sig)))
state->m_md_cart.type = SKINGKONG;
if (!allendianmemcmp(&ROM[0xce560], &redcliff_sig[0], sizeof(redcliff_sig)))
state->m_md_cart.type = REDCLIFF;
if (!allendianmemcmp(&ROM[0xc8cb0], &smb_sig[0], sizeof(smb_sig)))
state->m_md_cart.type = SMB;
if (!allendianmemcmp(&ROM[0xf24d6], &smb2_sig[0], sizeof(smb2_sig)))
state->m_md_cart.type = SMB2;
if (!allendianmemcmp(&ROM[0x674e], &kaiju_sig[0], sizeof(kaiju_sig)))
state->m_md_cart.type = KAIJU;
if (!allendianmemcmp(&ROM[0x1780], &chifi3_sig[0], sizeof(chifi3_sig)))
state->m_md_cart.type = CHINFIGHT3;
if (!allendianmemcmp(&ROM[0x03c2], &lionk2_sig[0], sizeof(lionk2_sig)))
state->m_md_cart.type = LIONK2;
if (!allendianmemcmp(&ROM[0xc8b90], &rx3_sig[0], sizeof(rx3_sig)))
state->m_md_cart.type = ROCKMANX3;
if (!allendianmemcmp(&ROM[0x56ae2], &kof98_sig[0], sizeof(kof98_sig)))
state->m_md_cart.type = KOF98;
if (!allendianmemcmp(&ROM[0x17bb2], &s15in1_sig[0], sizeof(s15in1_sig)))
state->m_md_cart.type = MC_SUP15IN1;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-081326 ", 12)) // NBA Jam
state->m_md_cart.type = NBA_JAM;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM MK-1228", 10)) // Greatest Heavyweight of the Ring
state->m_md_cart.type = SEGA_EEPROM;
if ((!allendianmemcmp((char *)&ROM[0x0180], "GM T-12046", 10)) || // Mega Man
(!allendianmemcmp((char *)&ROM[0x0180], "GM T-12053", 10) && !allendianmemcmp(&ROM[0x18e], &rockman_sig[0], sizeof(rockman_sig)))) // / Rock Man (EEPROM version)
state->m_md_cart.type = SEGA_EEPROM;
break;
case 0x200005:
if (!allendianmemcmp(&ROM[0xce564], &redcl_en_sig[0], sizeof(redcliff_sig)))
state->m_md_cart.type = REDCL_EN;
break;
case 0x300000:
if (!allendianmemcmp(&ROM[0x220], &sdk_sig[0], sizeof(sdk_sig)))
state->m_md_cart.type = SDK99;
if (!allendianmemcmp(&ROM[0x1fd0d2], &kof99_sig[0], sizeof(kof99_sig)))
state->m_md_cart.type = KOF99;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-81406", 10)) // NBA Jam TE
state->m_md_cart.type = NBA_JAM_TE;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-081276 ", 12)) // NFL Quarterback Club
state->m_md_cart.type = NBA_JAM_TE;
break;
case 0x400000:
if (!allendianmemcmp(&ROM[0x3c031c], &radica_sig[0], sizeof(radica_sig)) ||
!allendianmemcmp(&ROM[0x3f031c], &radica_sig[0], sizeof(radica_sig))) // ssf+gng + radica vol1
state->m_md_cart.type = RADICA;
if (!allendianmemcmp(&ROM[0x028460], &soulb_sig[0], sizeof(soulb_sig)))
state->m_md_cart.type = SOULBLAD;
if (!allendianmemcmp(&ROM[0x1e700], &s19in1_sig[0], sizeof(s19in1_sig)))
state->m_md_cart.type = MC_SUP19IN1;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-081586-", 12)) // NFL Quarterback Club 96
state->m_md_cart.type = NFL_QB_96;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-081576 ", 12)) // College Slam
state->m_md_cart.type = C_SLAM;
if (!allendianmemcmp((char *)&ROM[0x0180], "GM T-81476", 10)) // Big Hurt Baseball
state->m_md_cart.type = C_SLAM;
break;
case 0x500000:
if (!allendianmemcmp((char *)&ROM[0x0120], "SUPER STREET FIGHTER2 ", 22))
state->m_md_cart.type = SSF2;
break;
default:
break;
}
}
return IMAGE_INIT_PASS;
}
static DEVICE_IMAGE_DISPLAY_INFO(megadriv)
{
const char *compatibility = image.get_feature("compatibility");
const char *chips = image.get_feature("addon");
int md_region = megadrive_region_export + (megadrive_region_pal << 1);
if (chips)
{
if (!mame_stricmp(chips, "SVP") && (image.device().machine().device<cpu_device>("svp") == NULL))
{
mame_printf_warning("This software requires emulation of the SVP CPU to work.\n");
mame_printf_warning("It might not work in the system you are using.\n");
}
}
if (compatibility)
{
if (!mame_stricmp(compatibility, "PAL") && (md_region != 3))
{
mame_printf_warning("This software requires a PAL console to work.\n");
mame_printf_warning("It might not work in the system you are using.\n");
}
if (!mame_stricmp(compatibility, "NTSC-J") && (md_region != 0))
{
mame_printf_warning("This software requires a JPN console to work.\n");
mame_printf_warning("It might not work in the system you are using.\n");
}
if (!mame_stricmp(compatibility, "NTSC-U") && (md_region != 1))
{
mame_printf_warning("This software requires a USA console to work.\n");
mame_printf_warning("It might not work in the system you are using.\n");
}
if (!mame_stricmp(compatibility, "EUR-JPN") && (md_region != 0 && md_region != 3))
{
mame_printf_warning("This software requires a PAL or a JPN console to work.\n");
mame_printf_warning("It might not work in the system you are using.\n");
}
}
}
/*************************************
* Loading a cart image from softlist
*************************************/
static int megadrive_load_list(device_image_interface &image)
{
md_cons_state *state = image.device().machine().driver_data<md_cons_state>();
UINT8 *ROM = image.device().machine().region("maincpu")->base();
UINT32 length = image.get_software_region_length("rom");
const char *pcb_name;
memcpy(ROM, image.get_software_region("rom"), length);
state->m_md_cart.last_loaded_image_length = length;
if ((pcb_name = image.get_feature("pcb_type")) == NULL)
state->m_md_cart.type = SEGA_STD;
else
state->m_md_cart.type = md_get_pcb_id(pcb_name);
memcpy(&ROM[VIRGIN_COPY_GEN], &ROM[0x000000], MAX_MD_CART_SIZE); /* store a copy of data */
return IMAGE_INIT_PASS;
}
static DEVICE_IMAGE_LOAD( genesis_cart )
{
md_cons_state *state = image.device().machine().driver_data<md_cons_state>();
state->m_md_cart.type = SEGA_STD;
int res;
// STEP 1: load the file image and keep a copy for later banking
// STEP 2: identify the cart type
// The two steps are carried out differently if we are loading from a list or not
if (image.software_entry() == NULL)
res = megadrive_load_nonlist(image);
else
res = megadrive_load_list(image);
logerror("cart type: %d\n", state->m_md_cart.type);
if (res == IMAGE_INIT_PASS)
{
// STEP 3: install memory handlers for this type of cart
setup_megadriv_custom_mappers(image.device().machine());
// STEP 4: take care of SRAM.
setup_megadriv_sram(image);
return IMAGE_INIT_PASS;
}
else
return IMAGE_INIT_FAIL;
}
/******* SRAM saving *******/
static void genesis_machine_stop(running_machine &machine)
{
device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
md_cons_state *state = machine.driver_data<md_cons_state>();
/* Write out the battery file if necessary */
if (state->m_md_cart.sram != NULL)
{
mame_printf_debug("Saving sram\n");
image->battery_save(state->m_md_cart.sram, state->m_md_cart.sram_end - state->m_md_cart.sram_start + 1);
}
}
MACHINE_START( md_sram )
{
machine.add_notifier(MACHINE_NOTIFY_EXIT, genesis_machine_stop);
}
/******* 32X image loading *******/
// FIXME: non-softlist loading should keep using ROM_CART_LOAD in the ROM definitions,
// once we better integrate softlist with the old loading procedures
static DEVICE_IMAGE_LOAD( _32x_cart )
{
UINT32 length;
UINT8 *temp_copy;
UINT16 *ROM16;
UINT32 *ROM32;
int i;
if (image.software_entry() == NULL)
{
length = image.length();
temp_copy = auto_alloc_array(image.device().machine(), UINT8, length);
image.fread( temp_copy, length);
}
else
{
length = image.get_software_region_length("rom");
temp_copy = auto_alloc_array(image.device().machine(), UINT8, length);
memcpy(temp_copy, image.get_software_region("rom"), length);
}
/* Copy the cart image in the locations the driver expects */
// Notice that, by using pick_integer, we are sure the code works on both LE and BE machines
ROM16 = (UINT16 *) image.device().machine().region("gamecart")->base();
for (i = 0; i < length; i += 2)
ROM16[i / 2] = pick_integer_be(temp_copy, i, 2);
ROM32 = (UINT32 *) image.device().machine().region("gamecart_sh2")->base();
for (i = 0; i < length; i += 4)
ROM32[i / 4] = pick_integer_be(temp_copy, i, 4);
ROM16 = (UINT16 *) image.device().machine().region("maincpu")->base();
for (i = 0x00; i < length; i += 2)
ROM16[i / 2] = pick_integer_be(temp_copy, i, 2);
auto_free(image.device().machine(), temp_copy);
return IMAGE_INIT_PASS;
}
/******* Cart getinfo *******/
MACHINE_CONFIG_FRAGMENT( genesis_cartslot )
MCFG_CARTSLOT_ADD("cart")
MCFG_CARTSLOT_EXTENSION_LIST("smd,bin,md,gen")
MCFG_CARTSLOT_MANDATORY
MCFG_CARTSLOT_INTERFACE("megadriv_cart")
MCFG_CARTSLOT_LOAD(genesis_cart)
MCFG_CARTSLOT_DISPLAY_INFO(megadriv)
MCFG_SOFTWARE_LIST_ADD("cart_list","megadriv")
MACHINE_CONFIG_END
MACHINE_CONFIG_FRAGMENT( _32x_cartslot )
MCFG_CARTSLOT_ADD("cart")
MCFG_CARTSLOT_EXTENSION_LIST("32x,bin")
MCFG_CARTSLOT_MANDATORY
MCFG_CARTSLOT_INTERFACE("_32x_cart")
MCFG_CARTSLOT_LOAD(_32x_cart)
MCFG_SOFTWARE_LIST_ADD("cart_list","32x")
MACHINE_CONFIG_END
MACHINE_CONFIG_FRAGMENT( pico_cartslot )
MCFG_CARTSLOT_ADD("cart")
MCFG_CARTSLOT_EXTENSION_LIST("bin")
MCFG_CARTSLOT_MANDATORY
MCFG_CARTSLOT_INTERFACE("pico_cart")
MCFG_CARTSLOT_LOAD(genesis_cart)
MCFG_SOFTWARE_LIST_ADD("cart_list","pico")
MACHINE_CONFIG_END