/***********************************************************************************************************


 MegaDrive / Genesis cart emulation


 Here we emulate bankswitch / protection / NVRAM found on generic carts with no additional hardware


 ***********************************************************************************************************/

#include "emu.h"
#include "machine/md_rom.h"
#include "cpu/m68000/m68000.h"


//-------------------------------------------------
//  md_rom_device - constructor
//-------------------------------------------------

// BASE CARTS + NVRAM
const device_type MD_STD_ROM = &device_creator<md_std_rom_device>;
const device_type MD_ROM_SRAM = &device_creator<md_rom_sram_device>;
const device_type MD_ROM_FRAM = &device_creator<md_rom_fram_device>;

// BASE CARTS + BANKSWITCH AT RESET
const device_type MD_ROM_CM2IN1 = &device_creator<md_rom_cm2in1_device>;

// BASE CARTS + PROTECTION / BANKSWITCH
const device_type MD_ROM_SSF2 = &device_creator<md_rom_ssf2_device>;
const device_type MD_ROM_BUGSLIFE = &device_creator<md_rom_bugslife_device>;
const device_type MD_ROM_SMOUSE = &device_creator<md_rom_smouse_device>;
const device_type MD_ROM_SMW64 = &device_creator<md_rom_smw64_device>;
const device_type MD_ROM_SMB = &device_creator<md_rom_smb_device>;
const device_type MD_ROM_SMB2 = &device_creator<md_rom_smb2_device>;
const device_type MD_ROM_SBUBL = &device_creator<md_rom_sbubl_device>;
const device_type MD_ROM_RX3 = &device_creator<md_rom_rx3_device>;
const device_type MD_ROM_MJLOV = &device_creator<md_rom_mjlov_device>;
const device_type MD_ROM_KOF98 = &device_creator<md_rom_kof98_device>;
const device_type MD_ROM_KOF99 = &device_creator<md_rom_kof99_device>;
const device_type MD_ROM_SOULB = &device_creator<md_rom_soulb_device>;
const device_type MD_ROM_CHINF3 = &device_creator<md_rom_chinf3_device>;
const device_type MD_ROM_16MJ2 = &device_creator<md_rom_16mj2_device>;
const device_type MD_ROM_ELFWOR = &device_creator<md_rom_elfwor_device>;
const device_type MD_ROM_YASECH = &device_creator<md_rom_yasech_device>;
const device_type MD_ROM_LION2 = &device_creator<md_rom_lion2_device>;
const device_type MD_ROM_LION3 = &device_creator<md_rom_lion3_device>;
const device_type MD_ROM_MCPIR = &device_creator<md_rom_mcpirate_device>;
const device_type MD_ROM_POKEA = &device_creator<md_rom_pokea_device>;
const device_type MD_ROM_POKESTAD = &device_creator<md_rom_pokestad_device>;
const device_type MD_ROM_REALTEC = &device_creator<md_rom_realtec_device>;
const device_type MD_ROM_REDCL = &device_creator<md_rom_redcl_device>;
const device_type MD_ROM_SQUIR = &device_creator<md_rom_squir_device>;
const device_type MD_ROM_TEKKENSP = &device_creator<md_rom_tekkensp_device>;
const device_type MD_ROM_TOPF = &device_creator<md_rom_topf_device>;
const device_type MD_ROM_RADICA = &device_creator<md_rom_radica_device>;
const device_type MD_ROM_BEGGARP = &device_creator<md_rom_beggarp_device>;
const device_type MD_ROM_WUKONG = &device_creator<md_rom_wukong_device>;


md_std_rom_device::md_std_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
					: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
					device_md_cart_interface( mconfig, *this )
{
}

md_std_rom_device::md_std_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: device_t(mconfig, MD_STD_ROM, "MD Standard cart", tag, owner, clock, "md_std_rom", __FILE__),
					device_md_cart_interface( mconfig, *this )
{
}

md_rom_sram_device::md_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SRAM, "MD Standard cart + SRAM", tag, owner, clock, "md_rom_sram", __FILE__)
{
}

md_rom_fram_device::md_rom_fram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_FRAM, "MD Standard cart + FRAM", tag, owner, clock, "md_rom_fram", __FILE__)
{
}

md_rom_ssf2_device::md_rom_ssf2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SSF2, "MD Super SF2", tag, owner, clock, "md_rom_ssf2", __FILE__)
{
}

md_rom_cm2in1_device::md_rom_cm2in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_CM2IN1, "MD Codemasters 2in1", tag, owner, clock, "md_rom_cm2in1", __FILE__)
{
}

md_rom_mcpirate_device::md_rom_mcpirate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_MCPIR, "MD Pirate Multicarts (Various)", tag, owner, clock, "md_rom_mcpirate", __FILE__)
{
}

md_rom_bugslife_device::md_rom_bugslife_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_BUGSLIFE, "MD A Bug's Life", tag, owner, clock, "md_rom_bugslife", __FILE__)
{
}

md_rom_smouse_device::md_rom_smouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SMOUSE, "MD Huan Le Tao Qi Shu / Smart Mouse", tag, owner, clock, "md_rom_smouse", __FILE__)
{
}

md_rom_smb_device::md_rom_smb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SMB, "MD Super Mario Bros.", tag, owner, clock, "md_rom_smb", __FILE__)
{
}

md_rom_smb2_device::md_rom_smb2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SMB2, "MD Super Mario Bros. 2", tag, owner, clock, "md_rom_smb2", __FILE__)
{
}

md_rom_smw64_device::md_rom_smw64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SMW64, "MD Super Mario World 64", tag, owner, clock, "md_rom_smw64", __FILE__)
{
}

md_rom_sbubl_device::md_rom_sbubl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SBUBL, "MD Super Bubble Bobble", tag, owner, clock, "md_rom_sbubl", __FILE__)
{
}

md_rom_rx3_device::md_rom_rx3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_RX3, "MD Rockman X3", tag, owner, clock, "md_rom_rx3", __FILE__)
{
}

md_rom_mjlov_device::md_rom_mjlov_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_MJLOV, "MD Ma Jiang Qing Ren / Mahjong Lover", tag, owner, clock, "md_rom_mjlov", __FILE__)
{
}

md_rom_kof98_device::md_rom_kof98_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_KOF98, "MD KOF 98", tag, owner, clock, "md_rom_kof98", __FILE__)
{
}

md_rom_kof99_device::md_rom_kof99_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_KOF99, "MD KOF 99 (and others)", tag, owner, clock, "md_rom_kof99", __FILE__)
{
}

md_rom_soulb_device::md_rom_soulb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SOULB, "MD Soul Blade", tag, owner, clock, "md_rom_soulb", __FILE__)
{
}

md_rom_chinf3_device::md_rom_chinf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_CHINF3, "MD Chinese Fighter 3", tag, owner, clock, "md_rom_chinf3", __FILE__)
{
}

md_rom_16mj2_device::md_rom_16mj2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_16MJ2, "MD 16 Mahjong Tiles II", tag, owner, clock, "md_rom_16mj2", __FILE__)
{
}

md_rom_elfwor_device::md_rom_elfwor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_ELFWOR, "MD Linghuan Daoshi Super Magician / Elf Wor", tag, owner, clock, "md_rom_elfwor", __FILE__)
{
}

md_rom_yasech_device::md_rom_yasech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_YASECH, "MD Ya Se Chuan Shuo", tag, owner, clock, "md_rom_yasech", __FILE__)
{
}

md_rom_lion2_device::md_rom_lion2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_LION2, "MD Lion King 2", tag, owner, clock, "md_rom_lion2", __FILE__)
{
}

md_rom_lion3_device::md_rom_lion3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_LION3, "MD Lion King 3", tag, owner, clock, "md_rom_lion3", __FILE__)
{
}

md_rom_pokea_device::md_rom_pokea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_POKEA, "MD Pokemon (Alt Protection)", tag, owner, clock, "md_rom_pokea", __FILE__)
{
}

md_rom_pokestad_device::md_rom_pokestad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_POKESTAD, "MD Pokemon Stadium", tag, owner, clock, "md_rom_pokestad", __FILE__)
{
}

md_rom_realtec_device::md_rom_realtec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_REALTEC, "MD Realtec", tag, owner, clock, "md_rom_realtec", __FILE__)
{
}

md_rom_redcl_device::md_rom_redcl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_REDCL, "MD Redcliff", tag, owner, clock, "md_rom_redcl", __FILE__)
{
}

md_rom_squir_device::md_rom_squir_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_SQUIR, "MD Squirrel King", tag, owner, clock, "md_rom_squir", __FILE__)
{
}

md_rom_tekkensp_device::md_rom_tekkensp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_TEKKENSP, "MD Tekken Special", tag, owner, clock, "md_rom_tekkensp", __FILE__)
{
}

md_rom_topf_device::md_rom_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_TOPF, "MD Top Fighter", tag, owner, clock, "md_rom_topf", __FILE__)
{
}

md_rom_radica_device::md_rom_radica_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_RADICA, "MD Radica TV games", tag, owner, clock, "md_rom_radica", __FILE__)
{
}

md_rom_beggarp_device::md_rom_beggarp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_BEGGARP, "MD Beggar Prince", tag, owner, clock, "md_rom_beggarp", __FILE__)
{
}

md_rom_wukong_device::md_rom_wukong_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: md_std_rom_device(mconfig, MD_ROM_WUKONG, "MD Legend of Wukong", tag, owner, clock, "md_rom_wukong", __FILE__)
{
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void md_rom_ssf2_device::device_start()
{
	save_item(NAME(m_bank));
	save_item(NAME(m_lastoff));
	save_item(NAME(m_lastdata));
}

void md_rom_ssf2_device::device_reset()
{
	for (int i = 0; i < 7; i++)
		m_bank[i] = i;
	m_lastoff = -1;
	m_lastdata = -1;
}

void md_rom_cm2in1_device::device_start()
{
	m_base = -1;
	save_item(NAME(m_base));
}

void md_rom_cm2in1_device::device_reset()
{
	m_base++;
	m_base &= 1;
}

void md_rom_mcpirate_device::device_start()
{
	save_item(NAME(m_bank));
}

void md_rom_mcpirate_device::device_reset()
{
	m_bank = 0;
}

void md_rom_chinf3_device::device_start()
{
	m_bank = 0;
	save_item(NAME(m_bank));
}

void md_rom_chinf3_device::device_reset()
{
}

void md_rom_lion2_device::device_start()
{
	save_item(NAME(m_prot1_data));
	save_item(NAME(m_prot2_data));
}

void md_rom_lion2_device::device_reset()
{
	m_prot1_data = 0;
	m_prot2_data = 0;
}

void md_rom_lion3_device::device_start()
{
	save_item(NAME(m_reg));
	save_item(NAME(m_bank));
}

void md_rom_lion3_device::device_reset()
{
	m_reg[0] = 0;
	m_reg[1] = 0;
	m_reg[2] = 0;
	m_bank = 0;
}

void md_rom_pokestad_device::device_start()
{
	save_item(NAME(m_bank));
}

void md_rom_pokestad_device::device_reset()
{
	m_bank = 0;
}

void md_rom_realtec_device::device_start()
{
	save_item(NAME(m_bank_addr));
	save_item(NAME(m_bank_size));
	save_item(NAME(m_old_bank_addr));
}

void md_rom_realtec_device::device_reset()
{
	m_bank_addr = 0;
	m_bank_size = 0;
	m_old_bank_addr = -1;
}

void md_rom_squir_device::device_start()
{
	save_item(NAME(m_latch));
}

void md_rom_squir_device::device_reset()
{
	m_latch = 0;
}

void md_rom_smw64_device::device_start()
{
	save_item(NAME(m_latch0));
	save_item(NAME(m_latch1));
	save_item(NAME(m_reg));
	save_item(NAME(m_ctrl));
}

void md_rom_smw64_device::device_reset()
{
	m_latch0 = 0xf;
	m_latch1 = 0xf;
	memset(m_reg, 0, sizeof(m_reg));
	memset(m_ctrl, 0, sizeof(m_ctrl));
}

void md_rom_tekkensp_device::device_start()
{
	save_item(NAME(m_reg));
}

void md_rom_tekkensp_device::device_reset()
{
	m_reg = 0;
}

void md_rom_topf_device::device_start()
{
	save_item(NAME(m_latch));
	save_item(NAME(m_bank));
}

void md_rom_topf_device::device_reset()
{
	m_latch = 0;
	m_bank[0] = m_bank[1] = m_bank[2] = 0;
}

void md_rom_radica_device::device_start()
{
	save_item(NAME(m_bank));
}

void md_rom_radica_device::device_reset()
{
	m_bank = 0;
}

void md_rom_beggarp_device::device_start()
{
	save_item(NAME(m_mode));
	save_item(NAME(m_lock));
}

void md_rom_beggarp_device::device_reset()
{
	m_mode = 0;
	m_lock = 0;
}

void md_rom_wukong_device::device_start()
{
	save_item(NAME(m_mode));
}

void md_rom_wukong_device::device_reset()
{
	m_mode = 0;
}

/*-------------------------------------------------
 mapper specific handlers
 -------------------------------------------------*/

/*-------------------------------------------------
 CART + SRAM
 -------------------------------------------------*/

READ16_MEMBER(md_rom_sram_device::read)
{
	// since a lot of generic carts ends up here if loaded from fullpath
	// we access nvram only if m_nvram_handlers_installed has been turned on
	if (m_nvram_handlers_installed)
	{
		if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
			return m_nvram[offset - m_nvram_start/2];
	}
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_sram_device::write)
{
	// since a lot of generic carts ends up here if loaded from fullpath
	// we access nvram only if m_nvram_handlers_installed has been turned on
	if (m_nvram_handlers_installed)
	{
		if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly)
			m_nvram[offset - m_nvram_start/2] = data;
	}
}

WRITE16_MEMBER(md_rom_sram_device::write_a13)
{
	if (offset == 0xf0/2)
	{
		/* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */
		m_nvram_active = BIT(data, 0);
		m_nvram_readonly = BIT(data, 1);

		// since a lot of generic carts ends up here if loaded from fullpath
		// we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here!
		if (m_nvram_active && !m_nvram_handlers_installed)
			m_nvram_handlers_installed = 1;
	}
}

/*-------------------------------------------------
 CART + FRAM [almost same as SRAM... merge common parts?]
 -------------------------------------------------*/

READ16_MEMBER(md_rom_fram_device::read)
{
	if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
		return m_nvram[offset - m_nvram_start/2];
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_fram_device::write)
{
	if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
			m_nvram[offset - m_nvram_start/2] = data;
}

WRITE16_MEMBER(md_rom_fram_device::write_a13)
{
	if (offset == 0xf0/2)
		m_nvram_active = BIT(data, 0);
}


READ16_MEMBER(md_rom_fram_device::read_a13)
{
	if (offset == 0xf0/2)
		return m_nvram_active;
	else
		return 0xffff;
}

/*-------------------------------------------------
 SUPER STREET FIGHTERS 2
 -------------------------------------------------*/

READ16_MEMBER(md_rom_ssf2_device::read)
{
	if (offset < 0x400000/2)
		return m_rom[offset];
	else
		return 0xffff;
}

// I'm not very fond of the code below...
WRITE16_MEMBER(md_rom_ssf2_device::write_a13)
{
	if (offset >= 0xf0/2)
	{
		offset -= 0xf0/2;
		if ((m_lastoff != offset) || (m_lastdata != data))
		{
			m_lastoff = offset;
			m_lastdata = data;
			if (offset) // bank 0 is not modified
			{
				UINT16 *ROM = get_rom_base();
				m_bank[offset] = data & 0xf;
				memcpy(ROM + offset * 0x080000/2, ROM + 0x400000/2 + (m_bank[offset] * 0x080000)/2, 0x080000);
			}
		}
	}
}

/*-------------------------------------------------
 CODEMASTERS 2 IN 1 (RESET BASED)
 -------------------------------------------------*/

#define MD_ADDR_CM2IN1(a) (m_base == 0 ? ((a << 1) & 0x1fffff)/2 : (((a << 1) & 0x7ffff) + 0x200000)/2)

READ16_MEMBER(md_rom_cm2in1_device::read)
{
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR_CM2IN1(offset)];
	else
		return 0xffff;
}


/*-------------------------------------------------
 PIRATE MULTICARTS
 -------------------------------------------------*/

READ16_MEMBER(md_rom_mcpirate_device::read)
{
	if (offset < 0x400000/2)
		return m_rom[(((m_bank * 0x10000) + (offset << 1)) & (m_rom_size - 1))/2];
	else
		return read(space, offset - 0x400000/2, 0xffff);
}

WRITE16_MEMBER(md_rom_mcpirate_device::write_a13)
{
	offset <<= 1;
	if (offset < 0x40)
		m_bank = offset;
}

/*-------------------------------------------------
 A BUG'S LIFE
 -------------------------------------------------*/

READ16_MEMBER(md_rom_bugslife_device::read_a13)
{
	if (offset == 0x00/2)   return 0x28;
	if (offset == 0x02/2)   return 0x01;
	if (offset == 0x3e/2)   return 0x1f;
	else    return 0xffff;
}

/*-------------------------------------------------
 CHINESE FIGHTER 3
 -------------------------------------------------*/

READ16_MEMBER(md_rom_chinf3_device::read)
{
	if (offset < 0x100000/2)
	{
		if (!m_bank)
			return m_rom[offset & 0xfffff/2];
		else
			return m_rom[(offset & 0xffff/2) + (m_bank * 0x10000)/2];
	}

	// PROTECTION in 0x400000 - 0x4fffff
	/* not 100% correct, there may be some relationship between the reads here
	 and the writes made at the start of the game.. */
	if (offset >= 0x400000/2 && offset < 0x500000/2)
	{
		UINT32 retdat = 0;
		/*
		 04dc10 chifi3, prot_r? 2800
		 04cefa chifi3, prot_r? 65262
		 */
		if (space.machine().device("maincpu")->safe_pc() == 0x01782) // makes 'VS' screen appear
		{
			retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff;
			retdat <<= 8;
			return retdat;
		}
		else if (space.machine().device("maincpu")->safe_pc() == 0x1c24) // background gfx etc.
		{
			retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff;
			retdat <<= 8;
			return retdat;
		}
		else if (space.machine().device("maincpu")->safe_pc() == 0x10c4a) // unknown
		{
			return space.machine().rand();
		}
		else if (space.machine().device("maincpu")->safe_pc() == 0x10c50) // unknown
		{
			return space.machine().rand();
		}
		else if (space.machine().device("maincpu")->safe_pc() == 0x10c52) // relates to the game speed..
		{
			retdat = space.machine().device("maincpu")->state().state_int(M68K_D4) & 0xff;
			retdat <<= 8;
			return retdat;
		}
		else if (space.machine().device("maincpu")->safe_pc() == 0x061ae)
		{
			retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff;
			retdat <<= 8;
			return retdat;
		}
		else if (space.machine().device("maincpu")->safe_pc() == 0x061b0)
		{
			retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff;
			retdat <<= 8;
			return retdat;
		}
		else
		{
			logerror("%06x chifi3, prot_r? %04x\n", space.machine().device("maincpu")->safe_pc(), offset);
		}
		return 0;
	}

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_chinf3_device::write)
{
	if (offset >= 0x600000/2 && offset < 0x700000/2)
	{
		if (data == 0xf100) // *hit player
			m_bank = 1;
		else if (data == 0xd700) // title screen..
			m_bank = 7;
		else if (data == 0xd300) // character hits floor
			m_bank = 3;
		else if (data == 0x0000)
			m_bank = 0;
		else
			logerror("%06x chifi3, bankw? %04x %04x\n", space.device().safe_pc(), offset, data);
	}
}

/*-------------------------------------------------
 16 MAHJONG II
 -------------------------------------------------*/

READ16_MEMBER(md_rom_16mj2_device::read)
{
	if (offset == 0x400004/2)   return 0xc900;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

/*-------------------------------------------------
 LINGHUAN DAOSHI SUPER MAGICIAN / ELF WOR
 -------------------------------------------------*/

READ16_MEMBER(md_rom_elfwor_device::read)
{
	// It returns (0x55 @ 0x400000 OR 0xc9 @ 0x400004) AND (0x0f @ 0x400002 OR 0x18 @ 0x400006).
	// It is probably best to add handlers for all 4 addresses
	if (offset == 0x400000/2)   return 0x5500;
	if (offset == 0x400002/2)   return 0x0f00;
	if (offset == 0x400004/2)   return 0xc900;
	if (offset == 0x400006/2)   return 0x1800;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

/*-------------------------------------------------
 HUAN LE TAO QI SHU / SMART MOUSE
 -------------------------------------------------*/

READ16_MEMBER(md_rom_smouse_device::read)
{
	if (offset == 0x400000/2)   return 0x5500;
	if (offset == 0x400002/2)   return 0x0f00;
	if (offset == 0x400004/2)   return 0xaa00;
	if (offset == 0x400006/2)   return 0xf000;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

/*-------------------------------------------------
 YA SE CHUAN SHUO
 -------------------------------------------------*/

READ16_MEMBER(md_rom_yasech_device::read)
{
	if (offset == 0x400000/2)   return 0x6300;
	if (offset == 0x400002/2)   return 0x9800;
	if (offset == 0x400004/2)   return 0xc900;
	if (offset == 0x400006/2)   return 0x1800;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

/*-------------------------------------------------
 KOF98
 -------------------------------------------------*/

READ16_MEMBER(md_rom_kof98_device::read)
{
	if (offset == 0x480000/2)   return 0xaa00;
	if (offset == 0x4800e0/2)   return 0xaa00;
	if (offset == 0x4824a0/2)   return 0xaa00;
	if (offset == 0x488880/2)   return 0xaa00;
	if (offset == 0x4a8820/2)   return 0x0a00;
	if (offset == 0x4f8820/2)   return 0x0000;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

/*-------------------------------------------------
 KOF 99
 -------------------------------------------------*/

READ16_MEMBER(md_rom_kof99_device::read_a13)
{
	if (offset == 0x00/2)   return 0x00;    // startup protection check, chinese message if != 0
	if (offset == 0x02/2)   return 0x01;    // write 02 to a13002.. shift right 1?
	if (offset == 0x3e/2)   return 0x1f;    // write 3e to a1303e.. shift right 1?
	else    return 0xffff;
}

/*-------------------------------------------------
 LION KING 2
 -------------------------------------------------*/

READ16_MEMBER(md_rom_lion2_device::read)
{
	if (offset == 0x400002/2)   return m_prot1_data;
	if (offset == 0x400006/2)   return m_prot2_data;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_lion2_device::write)
{
	if (offset == 0x400000/2)   m_prot1_data = data;
	if (offset == 0x400004/2)   m_prot2_data = data;
}

/*-------------------------------------------------
 LION KING 3
 -------------------------------------------------*/

#define MD_LION3_ADDR(a)  (((offset << 1) | (m_bank << 15)) & (m_rom_size - 1))/2

READ16_MEMBER(md_rom_lion3_device::read)
{
	if (offset < 0x100000/2)
		return m_rom[MD_LION3_ADDR(offset)];
	else if (offset >= 0x600000/2 && offset < 0x700000/2)
	{
		switch (offset & 0x7)
		{
			case 0:
				return m_reg[0];
			case 1:
				return m_reg[1];
			case 2:
				return m_reg[2];
			default:
				logerror("protection read, unknown offset %x\n", offset & 0x7);
				break;
		}
		return 0;
	}

	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_lion3_device::write)
{
	if (offset >= 0x600000/2 && offset < 0x700000/2)
	{
//      printf("protection write, offset %d data %d\n", offset & 0x7, data);
		switch (offset & 0x7)
		{
			case 0x0:
				m_reg[0] = data & 0xff;
				break;
			case 0x1:
				m_reg[1] = data & 0xff;
				break;
			default:
				logerror("protection write, unknown offset %d\n", offset & 0x7);
				break;
		}

		// update m_reg[2]
		switch (m_reg[1] & 3)
		{
			case 0x0:
				m_reg[2] = (m_reg[0] << 1);
				break;
			case 0x1:
				m_reg[2] = (m_reg[0] >> 1);
				break;
			case 0x2:
				m_reg[2] = (m_reg[0] >> 4) | ((m_reg[0] & 0x0f) << 4);
				break;
			case 0x3:
			default:
				m_reg[2] =  (BIT(m_reg[0], 7) << 0)
						| (BIT(m_reg[0], 6) << 1)
						| (BIT(m_reg[0], 5) << 2)
						| (BIT(m_reg[0], 4) << 3)
						| (BIT(m_reg[0], 3) << 4)
						| (BIT(m_reg[0], 2) << 5)
						| (BIT(m_reg[0], 1) << 6)
						| (BIT(m_reg[0], 0) << 7);
				break;
		}

	}
	if (offset >= 0x700000/2)
		m_bank = data & 0xff;
}

/*-------------------------------------------------
 MA JIANG QING REN / MAHJONG LOVER
 -------------------------------------------------*/

READ16_MEMBER(md_rom_mjlov_device::read)
{
	if (offset == 0x400000/2)   return 0x9000;
	if (offset == 0x401000/2)   return 0xd300;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}


/*-------------------------------------------------
 SUPER BUBBLE BOBBLE MD
 -------------------------------------------------*/

READ16_MEMBER(md_rom_sbubl_device::read)
{
	if (offset == 0x400000/2)   return 0x5500;
	if (offset == 0x400002/2)   return 0x0f00;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

/*-------------------------------------------------
 SOUL BLADE
 -------------------------------------------------*/

READ16_MEMBER(md_rom_soulb_device::read)
{
	if (offset == 0x400002/2)   return 0x9800;
	if (offset == 0x400004/2)   return 0xc900;
	if (offset == 0x400006/2)   return 0xf000;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

/*-------------------------------------------------
 POKEMON STADIUM / KAIJU
 -------------------------------------------------*/

#define MD_POKESTAD_ADDR(a)  (((offset << 1) | (m_bank << 15)) & (m_rom_size - 1))/2

READ16_MEMBER(md_rom_pokestad_device::read)
{
	if (offset < 0x100000/2)
		return m_rom[MD_POKESTAD_ADDR(offset)];

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_pokestad_device::write)
{
	if (offset >= 0x700000/2 && offset < 0x800000/2)
		m_bank = data & 0x7f;
}

/*-------------------------------------------------
 POKEMON ALT
 -------------------------------------------------*/

READ16_MEMBER(md_rom_pokea_device::read_a13)
{
	if (offset == 0x00/2)   return 0x14;
	if (offset == 0x02/2)   return 0x01;
	if (offset == 0x3e/2)   return 0x1f;
	else    return 0xffff;
}

/*-------------------------------------------------
 REALTEC
 -------------------------------------------------*/

READ16_MEMBER(md_rom_realtec_device::read)
{
	if (offset < (m_bank_size * 0x20000))   // two banks of same (variable) size at the bottom of the rom
		return m_rom[MD_ADDR((offset + (m_bank_addr * 0x20000)/2))];
	return m_rom[MD_ADDR(((offset & 0x1fff/2) + 0x7e000/2))];  // otherwise it accesses the final 8k of the image
}

WRITE16_MEMBER(md_rom_realtec_device::write)
{
	if (offset == 0x400000/2)
	{
		m_old_bank_addr = m_bank_addr;
		m_bank_addr = (m_bank_addr & 0x7) | ((data >> 9) & 0x7) << 3;
	}
	if (offset == 0x402000/2)
	{
		m_bank_addr = 0;
		m_bank_size = (data >> 8) & 0x1f;
	}
	if (offset == 0x404000/2)
	{
		m_old_bank_addr = m_bank_addr;
		m_bank_addr = (m_bank_addr & 0xf8) | ((data >> 8) & 0x3);
	}
}

/*-------------------------------------------------
 RED CLIFF
 -------------------------------------------------*/

READ16_MEMBER(md_rom_redcl_device::read)
{
	if (offset == 0x400000/2)   return 0x55 << 8;
	if (offset == 0x400004/2)   return -0x56 << 8;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

/*-------------------------------------------------
 ROCKMAN X3
 -------------------------------------------------*/

READ16_MEMBER(md_rom_rx3_device::read_a13)
{
	if (offset == 0)
		return 0x0c;
	else
		return 0xffff;
}

/*-------------------------------------------------
 SQUIRREL KING
 -------------------------------------------------*/

READ16_MEMBER(md_rom_squir_device::read)
{
	if ((offset >= 0x400000/2) && (offset < 0x400008/2))
		return m_latch;

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_squir_device::write)
{
	if (offset >= 0x400000/2 && offset < 0x400008/2)
		m_latch = data;
}

/*-------------------------------------------------
 SUPER MARIO BROS
 -------------------------------------------------*/

READ16_MEMBER(md_rom_smb_device::read_a13)
{
	if (offset == 0)
		return 0x0c;
	else
		return 0xffff;
}

/*-------------------------------------------------
 SUPER MARIO BROS 2
 -------------------------------------------------*/

READ16_MEMBER(md_rom_smb2_device::read_a13)
{
	if (offset == 0)
		return 0x0a;
	else
		return 0xffff;
}

/*-------------------------------------------------
 SUPER MARIO WORLD 64
 -------------------------------------------------*/

READ16_MEMBER(md_rom_smw64_device::read)
{
	// 0x000000-0x0fffff: lower 512KB ROM (up to 0x07ffff) + mirror
	// 0x600000-0x6fffff: internal hardware (up to 0x67ffff) + mirror
	// Namely,
	//  * 60xxx = bank1 of the upper 512KB ROM
	//  * 61xxx = bank2 of the upper 512KB ROM
	//  * 62xxx = alternate 4KB chunks of 0x0000 ~ 0xffff
	//  * 63xxx = same as 62xxx
	//  * 64xxx = returns 0x0000
	//  * 65xxx = same as 64xxx
	//  * 66xxx = CTRL/DATA
	//  * 67xxx = CTRL/DATA
	if (offset < 0x100000/2)
		return m_rom[offset & 0x3ffff];

	if ((offset >= 0x600000/2) && (offset < 0x610000/2))
		return m_rom[(m_latch0 * 0x10000)/2 + (offset & 0x7fff)];
	if ((offset >= 0x610000/2) && (offset < 0x620000/2))
		return m_rom[(m_latch1 * 0x10000)/2 + (offset & 0x7fff)];

	if ((offset >= 0x620000/2) && (offset < 0x640000/2))
		return (offset & 0x1000/2) ? 0x0000 : 0xffff;
	if ((offset >= 0x640000/2) && (offset < 0x660000/2))
		return 0x0000;

	if ((offset >= 0x660000/2) && (offset < 0x670000/2))
	{
		offset &= 7;
		switch (offset)
		{
			case 0x0:
			case 0x2:
			case 0x4:
				return m_reg[offset/2]; // DATA1, DATA2, DATA3
			case 0x1:
			case 0x3:
			case 0x5:
				return m_reg[offset/2] + 1; // DATA1+1, DATA2+1, DATA3+1
			case 0x6:
				return m_reg[2] + 2;    // DATA3+2
			case 0x7:
				return m_reg[2] + 3;    // DATA3+3
		}
	}
	if ((offset >= 0x670000/2) && (offset < 0x680000/2))
	{
		UINT16 data = (m_ctrl[1] & 0x80) ? ((m_ctrl[2] & 0x40) ? (m_reg[4] & m_reg[5]) : (m_reg[4] ^ 0xff)) : 0x0000;
		if (offset & 0x1)   // odd offset, return lower 7 bits of the above
			return data & 0x7f;
		else    // even offset, return whole data above, but also update the regs if CTRL3 has 0x80 set
		{
			if (m_ctrl[2] & 0x80)   // update regs if CTRL3 has bit7 set
			{
				if (m_ctrl[2] & 0x20)
					m_reg[2] = (m_reg[5] << 2) & 0xfc;  // DATA3
				else
					m_reg[0] = ((m_reg[4] << 1) ^ m_reg[3]) & 0xfe; // DATA1
			}
			return data;
		}
	}
	return 0xffff;
}

WRITE16_MEMBER(md_rom_smw64_device::write)
{
	// 0x600000-0x6fffff: internal hardware (up to 0x67ffff) + mirror
	// Namely,
	//  * 62xxx/63xxx = unknown/unmapped
	//  * 65xxx/66xxx = unknown/unmapped
	//  * remaining ranges = CTRL/DATA
	if ((offset >= 0x600000/2) && (offset < 0x610000/2))
	{
		if (offset & 1)
		{
			if ((m_ctrl[0] & 7) == 0)
				m_reg[0] = ((m_reg[0] ^ m_reg[3]) ^ data) & 0xfe;   // DATA1
			if ((m_ctrl[0] & 7) == 1)
				m_reg[1] = data & 0xfe; // DATA2
			if ((m_ctrl[0] & 7) == 7)
				m_latch1 = 8 + ((data & 0x1c) >> 2);    // ROM BANKSWITCH $61
			m_reg[3] = data;    // DATA4
		}
		else
			m_ctrl[0] = data;   // CTRL1
	}
	if ((offset >= 0x610000/2) && (offset < 0x620000/2))
	{
		if (offset & 1)
			m_ctrl[1] = data;   // CTRL2
	}
	if ((offset >= 0x640000/2) && (offset < 0x650000/2))
	{
		if (offset & 1)
			m_reg[5] = data;    // DATA6
		else
			m_reg[4] = data;    // DATA5
	}
	if ((offset >= 0x670000/2) && (offset < 0x680000/2))
	{
		if (!(offset & 1))
		{
			m_ctrl[2] = data;   // CTRL3
			if (m_ctrl[1] & 0x80)
				m_latch0 = 8 + ((data & 0x1c) >> 2);    // ROM BANKSWITCH $60
		}
	}
}

/*-------------------------------------------------
 TEKKEN SPECIAL
 -------------------------------------------------*/

READ16_MEMBER(md_rom_tekkensp_device::read)
{
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else if ((offset & 0x07) == 1 && m_reg)
		return (m_reg - 1) << 8;
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_tekkensp_device::write)
{
	if (offset < 0x400000/2)
		return;

	// thanks to EkeEke for the documentation
	switch (offset & 0x07)
	{
		case 0x00:
			// data output reset ? (game writes $FF before & after protection check)
			m_reg = 0;
			break;
		case 0x01:
			// read only ?
			break;
		case 0x06:
			// data output mode bit 0 ? (game writes $01)
			break;
		case 0x07:
			// data output mode bit 1 ? (never written by game)
			break;
		default:
			if (data & 0x100)   // data input (only connected to D0 ?)
			{
				// 4-bit hardware register ($400004 corresponds to bit0, $400006 to bit1, etc)
				int shift = (offset - 2) & 3;
				m_reg |= (1 << shift);
			}
			break;
	}
}

/*-------------------------------------------------
 TOP FIGHTER
 -------------------------------------------------*/

READ16_MEMBER(md_rom_topf_device::read)
{
	//cpu #0 (PC=0004CBAE): unmapped program memory word read from 006A35D4 & 00FF -- wants regD7
	if (offset == 0x645b44/2)
	{
		//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;
	}
	if (offset == 0x6bd294/2)
	{
		/*
		 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 (space.device().safe_pc()==0x1771a2) return 0x50;
		else
		{
			m_latch++;
			logerror("%06x topfig_6BD294_r %04x\n",space.device().safe_pc(), m_latch);
			return m_latch;
		}
	}
	if (offset == 0x6f5344/2)
	{
		if (space.device().safe_pc()==0x4C94E)
			return space.machine().device("maincpu")->state().state_int((M68K_D0)) & 0xff;
		else
		{
			m_latch++;
			logerror("%06x topfig_6F5344_r %04x\n", space.device().safe_pc(), m_latch);
			return m_latch;
		}
	}

	if (offset >= 0x20000/2 && offset < 0x28000/2)
		return m_rom[offset + (m_bank[0] * 0x188000)/2];

	if (offset >= 0x58000/2 && offset < 0x60000/2)
		return m_rom[offset + (m_bank[1] * 0x20000)/2];

	if (offset >= 0x60000/2 && offset < 0x68000/2)
		return m_rom[offset + (m_bank[2] * 0x110000)/2];

	// non-protection accesses
	if (offset < 0x400000/2)
		return m_rom[MD_ADDR(offset)];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_topf_device::write)
{
	if (offset >= 0x700000/2 && offset < 0x800000/2)
	{
		if (data == 0x002a)
			m_bank[2] = 1;  // == 0x2e*0x8000?!
		else if (data==0x0035) // characters ingame
			m_bank[0] = 1;  // == 0x35*0x8000
		else if (data==0x000f) // special moves
			m_bank[1] = 1; // == 0xf*0x8000
		else if (data==0x0000)
		{
			m_bank[0] = 0;
			m_bank[1] = 0;
			m_bank[2] = 0;
		}
		else
			logerror("%06x offset %06x, data %04x\n", space.device().safe_pc(), offset, data);
	}
}

/*-------------------------------------------------
 RADICA TV GAMES [to be split...]
 -------------------------------------------------*/

READ16_MEMBER(md_rom_radica_device::read)
{
	return m_rom[(((m_bank * 0x10000) + (offset << 1)) & (m_rom_size - 1))/2];
}

READ16_MEMBER(md_rom_radica_device::read_a13)
{
	if (offset < 0x80)
		m_bank = offset & 0x3f;
	return 0;
}

/*-------------------------------------------------
 BEGGAR PRINCE
 This game uses cart which is the same as SEGA_SRAM
 + bankswitch mechanism for first 256KB of the image:
 depending on bit7 of the value written at 0xe00/2,
 accesses to 0x00000-0x3ffff go to the first 256KB
 of ROM, or to the second to last 256KB chunk (usually
 mapped to 0x380000-0x3bffff). SRAM is mapped at
 the end of ROM.
 -------------------------------------------------*/

READ16_MEMBER(md_rom_beggarp_device::read)
{
	if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
		return m_nvram[offset & 0x3fff];

	if (offset < 0x040000/2)
		return m_mode ? m_rom[offset + 0x380000/2] : m_rom[offset];
	else if (offset < 0x400000/2)
		return m_rom[offset & 0x1fffff];

	return 0xffff;
}

WRITE16_MEMBER(md_rom_beggarp_device::write)
{
	if (offset >= 0x0e00/2 && offset < 0x0f00/2)
		m_mode = BIT(data, 7);

	if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly)
		m_nvram[offset & 0x3fff] = data;
}

WRITE16_MEMBER(md_rom_beggarp_device::write_a13)
{
	if (offset == 0xf0/2)
	{
		/* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */
		m_nvram_active = BIT(data, 0);
		m_nvram_readonly = BIT(data, 1);

		// since a lot of generic carts ends up here if loaded from fullpath
		// we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here!
		if (m_nvram_active)
			m_nvram_handlers_installed = 1;
	}
}

/*-------------------------------------------------
 LEGEND OF WUKONG
 This game uses cart which is the same as SEGA_SRAM
 + bankswitch mechanism for last 128KB of the image:
 first 2MB of ROM is loaded in 0-0x200000 and
 mirrored in 0x200000-0x400000, but depending on
 bit7 of the value written at 0xe00/2 accesses to
 0x200000-0x21ffff go either to the "physical" address
 (i.e. last 128K of ROM) or to the "memory" address
 (i.e. mirror of first 128K)
 -------------------------------------------------*/

READ16_MEMBER(md_rom_wukong_device::read)
{
	if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active)
		return m_nvram[offset - m_nvram_start/2];

	// here can access both last 128K of the ROM and the first 128K, depending of bit7 of m_mode
	if (offset >= 0x200000/2 && offset < 0x220000/2)
		return !m_mode ? m_rom[offset] : m_rom[offset & 0xffff];
	else if (offset < 0x400000/2)
		return m_rom[offset & 0xfffff];
	else
		return 0xffff;
}

WRITE16_MEMBER(md_rom_wukong_device::write)
{
	if (offset < 0x100000/2)    // it actually writes to 0xe00/2
		m_mode = BIT(data, 7);

	if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly)
		m_nvram[offset - m_nvram_start/2] = data;
}

WRITE16_MEMBER(md_rom_wukong_device::write_a13)
{
	if (offset == 0xf0/2)
	{
		/* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */
		m_nvram_active = BIT(data, 0);
		m_nvram_readonly = BIT(data, 1);

		// since a lot of generic carts ends up here if loaded from fullpath
		// we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here!
		if (m_nvram_active)
			m_nvram_handlers_installed = 1;
	}
}
