diff options
Diffstat (limited to 'src/devices/bus/megadrive/cart/xboy.cpp')
| -rw-r--r-- | src/devices/bus/megadrive/cart/xboy.cpp | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/src/devices/bus/megadrive/cart/xboy.cpp b/src/devices/bus/megadrive/cart/xboy.cpp new file mode 100644 index 00000000000..389eeb848f9 --- /dev/null +++ b/src/devices/bus/megadrive/cart/xboy.cpp @@ -0,0 +1,216 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +X Boy published/developed cart mappers + +**************************************************************************************************/ + + +#include "emu.h" +#include "xboy.h" + +#include "bus/generic/slot.h" + + +/* + * The King of Fighters '99 + * https://segaretro.org/King_of_Fighters_98%27 + * + * Earlier protection variant + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_KOF98, megadrive_unl_kof98_device, "megadrive_unl_kof98", "Megadrive The King of Fighters '98 cart") + +megadrive_unl_kof98_device::megadrive_unl_kof98_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_KOF98, tag, owner, clock) +{ +} + +void megadrive_unl_kof98_device::cart_map(address_map &map) +{ + map(0x00'0000, 0x3f'ffff).bankr(m_rom); + // everytime, trashes stack otherwise + map(0x48'0000, 0x4b'ffff).lr16(NAME([] () { return 0xaa00; })); + // when selecting Arcade or VS., pointer to reach above + map(0x4c'0000, 0x4f'ffff).lr16(NAME([] () { return 0xf000; })); +} + + +/* + * A Bug's Life + * https://segaretro.org/A_Bug%27s_Life_(Mega_Drive) + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_BUGSLIFE, megadrive_unl_bugslife_device, "megadrive_unl_bugslife", "Megadrive A Bug's Life cart") + +megadrive_unl_bugslife_device::megadrive_unl_bugslife_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_BUGSLIFE, tag, owner, clock) +{ +} + +void megadrive_unl_bugslife_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x28; })); + // those two are patched by SW + map(0x02, 0x03).lr16(NAME([] () { return 0x01; })); + map(0x3e, 0x3f).lr16(NAME([] () { return 0x1f; })); +} + +/* + * Pokemon Monster + * https://segaretro.org/Pocket_Monster + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_POKEMONA, megadrive_unl_pokemona_device, "megadrive_unl_pokemona", "Megadrive Pokemon Monster alt cart") + +megadrive_unl_pokemona_device::megadrive_unl_pokemona_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_POKEMONA, tag, owner, clock) +{ +} + +void megadrive_unl_pokemona_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x14; })); + // those two are patched by SW + map(0x02, 0x03).lr16(NAME([] () { return 0x01; })); + map(0x3e, 0x3f).lr16(NAME([] () { return 0x1f; })); +} + +/* + * The King of Fighters '99 + * https://segaretro.org/The_King_of_Fighters_%2799_(Mega_Drive) + * + * Writes "Secondary memory access failure" if $a13000 returns & 0xf != 0 + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_KOF99, megadrive_unl_kof99_device, "megadrive_unl_kof99", "Megadrive The King of Fighters '99 cart") + +megadrive_unl_kof99_device::megadrive_unl_kof99_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_KOF99, tag, owner, clock) +{ +} + +void megadrive_unl_kof99_device::time_io_map(address_map &map) +{ + map(0x00, 0x01).lr16(NAME([] () { return 0x00; })); + map(0x02, 0x03).lr16(NAME([] () { return 0x01; })); + map(0x3e, 0x3f).lr16(NAME([] () { return 0x1f; })); +} + +/* + * pokestad Pokemon Stadium + * https://segaretro.org/Pokemon_Stadium + * + * lionkin3 Lion King 3 + * mulan Hua Mu Lan - Mulan + * pokemon2 Pocket Monsters 2 + * souledge Soul Edge vs Samurai Spirits + * sdkong99/skkong99 Super Donkey Kong 99 + * topf Top Fighter 2000 MK VIII + * https://segaretro.org/Top_Fighter_2000_MK_VIII + * + * gunfight Gunfight 3 in 1 + * https://segaretro.org/Gunfight_3_in_1 + * + * Obfuscated bankswitch mechanism + a bitswap based protection device. + * + * TODO: + * - pokestad is the only game that doesn't access protection, verify on HW if it has it anyway. + * + */ + +DEFINE_DEVICE_TYPE(MEGADRIVE_UNL_TOPF, megadrive_unl_topf_device, "megadrive_unl_topf", "Megadrive Top Fighter cart") + +megadrive_unl_topf_device::megadrive_unl_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : megadrive_rom_device(mconfig, MEGADRIVE_UNL_TOPF, tag, owner, clock) + , m_rom_bank(*this, "rom_bank_%u", 0U) + , m_rom_view(*this, "rom_view") +{ +} + +void megadrive_unl_topf_device::device_start() +{ + megadrive_rom_device::device_start(); + memory_region *const romregion(cart_rom_region()); + const u32 page_size = 0x00'8000; + device_generic_cart_interface::map_non_power_of_two( + unsigned(romregion->bytes() / page_size), + [this, base = &romregion->as_u8()] (unsigned entry, unsigned page) + { + for (int i = 0; i < 32; i++) + m_rom_bank[i]->configure_entry(entry, &base[page * page_size]); + }); + + + save_item(NAME(m_prot_latch)); + save_item(NAME(m_prot_mode)); +} + +void megadrive_unl_topf_device::device_reset() +{ + m_prot_latch = 0; + m_prot_mode = 0; + m_rom_view.select(0); +} + +void megadrive_unl_topf_device::prot_latch_w(u8 data) +{ + m_prot_latch = data; +} + +void megadrive_unl_topf_device::prot_mode_w(u8 data) +{ + m_prot_mode = data & 3; +} + +u8 megadrive_unl_topf_device::prot_data_r() +{ + u8 res = 0; + switch(m_prot_mode) + { + case 0: res = (m_prot_latch << 1); break; + case 1: res = (m_prot_latch >> 1); break; + case 2: res = bitswap<8>(m_prot_latch, 3, 2, 1, 0, 7, 6, 5, 4); break; + case 3: res = bitswap<8>(m_prot_latch, 0, 1, 2, 3, 4, 5, 6, 7); break; + } + + return res; +} + +void megadrive_unl_topf_device::cart_map(address_map &map) +{ + // TODO: just 0x0f'ffff ? + map(0x00'0000, 0x1f'ffff).view(m_rom_view); + m_rom_view[0](0x00'0000, 0x1f'ffff).bankr(m_rom); + for (int bank = 0; bank < 16; bank++) + { + u32 bank_base = bank * 0x1'0000; + m_rom_view[1](0x00'0000 | bank_base, 0x00'7fff | bank_base).bankr(m_rom_bank[bank * 2 + 0]); + m_rom_view[1](0x00'8000 | bank_base, 0x00'ffff | bank_base).bankr(m_rom_bank[bank * 2 + 1]); + } + + map(0x60'0001, 0x60'0001).mirror(0x0f'fff8).w(FUNC(megadrive_unl_topf_device::prot_latch_w)); + map(0x60'0003, 0x60'0003).mirror(0x0f'fff8).w(FUNC(megadrive_unl_topf_device::prot_mode_w)); + map(0x60'0005, 0x60'0005).mirror(0x0f'fff8).r(FUNC(megadrive_unl_topf_device::prot_data_r)); + + map(0x70'0000, 0x70'0000).mirror(0x0f'ffff).lw8(NAME([this] (u8 data) { + if (data) + { + m_rom_view.select(1); + for (int i = 0; i < 16; i++) + { + m_rom_bank[i * 2 + 0]->set_entry((i * 2 | data) & 0x3f); + m_rom_bank[i * 2 + 1]->set_entry((i * 2 | (data | 1)) & 0x3f); + } + } + else + { + m_rom_view.select(0); + } + })); +} |
