From e4e14a06b23481d604ce74e150a00e7489bbfab6 Mon Sep 17 00:00:00 2001 From: Fabio Priuli Date: Wed, 13 Mar 2013 08:05:41 +0000 Subject: [PATCH] (MESS) snes.c: misc work on pirate carts. [Fabio Priuli] - added support for Korean Super 20 Collection multigame cart, even if a few games still have glitches. - added support for bankswitch mechanism used in a few pirate multigame carts. - added support for protection used by Tekken 2 and Street Fighter Alpha EX, based on notes by d4s and nocash. (MESS) snes.xml: added a few pirate multigame carts. Most of these are incomplete dumps, so redumps are needed to promote them to working state, but their existence is now at least documented. [Fabio Priuli] out of whatsnew: I also have fixed sram issue from fullpath in snesnew driver, due to a silly copy&paste mistake. --- hash/snes.xml | 123 ++++++++++-- src/mess/drivers/snes.c | 120 +++++++++--- src/mess/machine/sns_rom.c | 360 +++++++++++++++++++++++++++++++++--- src/mess/machine/sns_rom.h | 169 +++++++++++++++-- src/mess/machine/sns_slot.c | 11 +- src/mess/machine/sns_slot.h | 7 +- 6 files changed, 709 insertions(+), 81 deletions(-) diff --git a/hash/snes.xml b/hash/snes.xml index ba3b17fd3aa..9599970fbaf 100644 --- a/hash/snes.xml +++ b/hash/snes.xml @@ -3918,6 +3918,11 @@ List of pirate cartridges + Bananas de Pijamas (Asia) @@ -3925,7 +3930,7 @@ List of pirate cartridges <unlicensed> - + @@ -3946,7 +3951,12 @@ List of pirate cartridges - + + A Bug's Life (Bra) @@ -3956,7 +3966,7 @@ List of pirate cartridges - + @@ -3964,7 +3974,7 @@ List of pirate cartridges - + A Bug's Life (Bra, Cracked) 199? <unlicensed> @@ -4199,7 +4209,7 @@ List of pirate cartridges - + Soul Blade (Asia) 199? @@ -4210,7 +4220,7 @@ List of pirate cartridges - + @@ -4259,14 +4269,14 @@ List of pirate cartridges - + Street Fighter EX Plus α (Asia) 199? <unlicensed> - + @@ -4322,7 +4332,96 @@ List of pirate cartridges - + + + Super 5 in 1 (Bad Dump) + 199? + <unlicensed> + + + + + + + + + + + + Super 6 in 1 + 199? + <unlicensed> + + + + + + + + + + + + + 1997 New 7 in 1 (Bad Dump) + 199? + <unlicensed> + + + + + + + + + + + + + Super 7-in-1 1997 (Bad Dump) + 199? + <unlicensed> + + + + + + + + + + + + + 8 in 1 and 10 in 1 (Bad Dump) + 199? + <unlicensed> + + + + + + + + + + + + + Super 11 in 1 (Bad Dump) + 199? + <unlicensed> + + + + + + + + + + + Super 20 Collection (Kor) 199? @@ -4330,21 +4429,21 @@ List of pirate cartridges - + - + Tekken 2 (Asia) 199? <unlicensed> - + diff --git a/src/mess/drivers/snes.c b/src/mess/drivers/snes.c index cddcaa6ea9a..b5bf8cffd63 100644 --- a/src/mess/drivers/snes.c +++ b/src/mess/drivers/snes.c @@ -1616,7 +1616,18 @@ READ8_MEMBER( snsnew_state::snes20_hi_r ) else if (m_slotcart->get_type() == SNES_CX4 && (offset < 0x400000 && (offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)) // hack until we emulate the real CPU return CX4_read((offset & 0xffff) - 0x6000); - + else if (m_slotcart->get_type() == SNES_BANANA + && (offset & 0x78000) == 0x8000) + { + return m_slotcart->m_cart->chip_read(space, offset); + } + else if (m_slotcart->get_type() == SNES_BUGS + && (offset & 0x7f000) == 0xf000) + { + printf("read hi addr %X\n", offset); +// return m_slotcart->m_cart->chip_read(space, offset); + } + if (offset < 0x400000) { if (address < 0x2000) @@ -1676,7 +1687,20 @@ WRITE8_MEMBER( snsnew_state::snes20_hi_w ) else if (m_type == SNES_SUFAMITURBO && address >= 0x8000 && ((offset >= 0x600000 && offset < 0x640000) || (offset >= 0x700000 && offset < 0x740000))) { m_slotcart->m_cart->write_h(space, offset, data); return; } - +// else if (m_slotcart->get_type() == SNES_BANANA +// && (offset & 0x8000) == 0x8000) +// { +// printf("write addr hi %X data %X\n", offset, data); +// m_slotcart->m_cart->chip_write(space, offset, data); +// return; +// } + else if (m_slotcart->get_type() == SNES_BUGS + && (offset & 0x7f000) == 0xf000) + { +// printf("write hi addr %X data %X\n", offset, data); + } + + if (offset < 0x400000) { if (address < 0x2000) @@ -1711,7 +1735,14 @@ READ8_MEMBER( snsnew_state::snes20_lo_r ) else if (m_slotcart->get_type() == SNES_CX4 && (offset < 0x400000 && (offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)) // hack until we emulate the real CPU return CX4_read((offset & 0xffff) - 0x6000); - + else if (m_slotcart->get_type() == SNES_BUGS + && (offset & 0x78000) == 0x8000) + { +// printf("read lo addr %X\n", offset); +// return m_slotcart->m_cart->chip_read(space, offset); + } + + if (offset < 0x400000) { if (address < 0x2000) @@ -1759,14 +1790,22 @@ WRITE8_MEMBER( snsnew_state::snes20_lo_w ) if (m_type == SNES_SUFAMITURBO && (offset & 0xffff) >= 0x8000 && ((offset >= 0x600000 && offset < 0x640000) || (offset >= 0x700000 && offset < 0x740000))) { m_slotcart->m_cart->write_l(space, offset, data); return; } + else if (m_slotcart->get_type() == SNES_20COL + && offset >= 0x8000 && offset < 0x9000) + { m_slotcart->m_cart->chip_write(space, offset, data); return; } else if (m_slotcart->get_type() == SNES_BANANA - && (offset & 0x78000) == 0x8000) + && (offset & 0x8000) == 0x8000) { -// printf("lo write %x\n", offset); + printf("write addr lo %X data %X\n", offset, data); m_slotcart->m_cart->chip_write(space, offset, data); return; } - + else if (m_slotcart->get_type() == SNES_BUGS + && (offset & 0x78000) == 0x8000) + { +// printf("write lo addr %X data %X\n", offset, data); + } + // other add-on writes matches the hi handler snes20_hi_w(space, offset, data, 0xff); } @@ -2280,6 +2319,13 @@ static SLOT_INTERFACE_START(snes_cart) SLOT_INTERFACE_INTERNAL("bsxrom", SNS_ROM_BSX) // BS-X base cart - partial support only // pirate carts SLOT_INTERFACE_INTERNAL("lorom_poke", SNS_LOROM_POKEMON) + SLOT_INTERFACE_INTERNAL("lorom_tekken2", SNS_LOROM_TEKKEN2) + SLOT_INTERFACE_INTERNAL("lorom_sbld", SNS_LOROM_SOULBLAD) + SLOT_INTERFACE_INTERNAL("lorom_mcpir1", SNS_LOROM_MCPIR1) + SLOT_INTERFACE_INTERNAL("lorom_mcpir2", SNS_LOROM_MCPIR2) + SLOT_INTERFACE_INTERNAL("lorom_20col", SNS_LOROM_20COL) + SLOT_INTERFACE_INTERNAL("lorom_pija", SNS_LOROM_BANANA) // not working yet + SLOT_INTERFACE_INTERNAL("lorom_bugs", SNS_LOROM_BUGSLIFE) // not working yet SLOT_INTERFACE_END @@ -2294,19 +2340,14 @@ static MACHINE_START( snesnew ) // in progress... switch (state->m_type) { + // LoROM & LoROM + addons case SNES_MODE20: case SNES_BSXLO: case SNES_SUFAMITURBO: - case SNES_BANANA: case SNES_CX4: // this still uses the old simulation instead of emulating the CPU case SNES_ST010: // this requires two diff kinds of chip access, so we handle it in snes20_lo/hi_r/w case SNES_ST011: // this requires two diff kinds of chip access, so we handle it in snes20_lo/hi_r/w break; - case SNES_POKEMON: - machine.device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x800000, 0x80ffff, 0, 0x780000, read8_delegate(FUNC(device_sns_cart_interface::chip_read),state->m_slotcart->m_cart)); - machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0x800000, 0x80ffff, 0, 0x780000, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); -// set_5a22_map(*state->m_maincpu); - break; case SNES_DSP: machine.device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x208000, 0x20ffff, 0, 0x9f0000, read8_delegate(FUNC(device_sns_cart_interface::chip_read),state->m_slotcart->m_cart)); machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0x208000, 0x20ffff, 0, 0x9f0000, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); @@ -2323,6 +2364,22 @@ static MACHINE_START( snesnew ) machine.device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x006000, 0x007fff, 0, 0xbf0000, read8_delegate(FUNC(device_sns_cart_interface::chip_read),state->m_slotcart->m_cart)); machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0x006000, 0x007fff, 0, 0xbf0000, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); break; + case SNES_SFX: + machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snsnew_state::snessfx_lo_r),state), write8_delegate(FUNC(snsnew_state::snessfx_lo_w),state)); + machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snsnew_state::snessfx_hi_r),state), write8_delegate(FUNC(snsnew_state::snessfx_hi_w),state)); + set_5a22_map(*state->m_maincpu); + break; + case SNES_SDD1: + machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snsnew_state::snessdd1_lo_r),state), write8_delegate(FUNC(snsnew_state::snessdd1_lo_w),state)); + machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snsnew_state::snessdd1_hi_r),state), write8_delegate(FUNC(snsnew_state::snessdd1_hi_w),state)); + set_5a22_map(*state->m_maincpu); + break; + case SNES_BSX: + machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snsnew_state::snesbsx_lo_r),state), write8_delegate(FUNC(snsnew_state::snesbsx_lo_w),state)); + machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snsnew_state::snesbsx_hi_r),state), write8_delegate(FUNC(snsnew_state::snesbsx_hi_w),state)); + set_5a22_map(*state->m_maincpu); + break; + // HiROM & HiROM + addons case SNES_MODE21: case SNES_BSXHI: machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snsnew_state::snes21_lo_r),state), write8_delegate(FUNC(snsnew_state::snes21_lo_w),state)); @@ -2343,26 +2400,39 @@ static MACHINE_START( snesnew ) machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0x002801, 0x002801, 0, 0xbf0000, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); set_5a22_map(*state->m_maincpu); break; - case SNES_SFX: - machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snsnew_state::snessfx_lo_r),state), write8_delegate(FUNC(snsnew_state::snessfx_lo_w),state)); - machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snsnew_state::snessfx_hi_r),state), write8_delegate(FUNC(snsnew_state::snessfx_hi_w),state)); - set_5a22_map(*state->m_maincpu); - break; case SNES_SPC7110: case SNES_SPC7110_RTC: machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snsnew_state::snes7110_lo_r),state), write8_delegate(FUNC(snsnew_state::snes7110_lo_w),state)); machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snsnew_state::snes7110_hi_r),state), write8_delegate(FUNC(snsnew_state::snes7110_hi_w),state)); set_5a22_map(*state->m_maincpu); break; - case SNES_SDD1: - machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snsnew_state::snessdd1_lo_r),state), write8_delegate(FUNC(snsnew_state::snessdd1_lo_w),state)); - machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snsnew_state::snessdd1_hi_r),state), write8_delegate(FUNC(snsnew_state::snessdd1_hi_w),state)); - set_5a22_map(*state->m_maincpu); + // pirate 'mappers' + case SNES_POKEMON: + machine.device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x800000, 0x80ffff, 0, 0x780000, read8_delegate(FUNC(device_sns_cart_interface::chip_read),state->m_slotcart->m_cart)); + machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0x800000, 0x80ffff, 0, 0x780000, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); break; - case SNES_BSX: - machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snsnew_state::snesbsx_lo_r),state), write8_delegate(FUNC(snsnew_state::snesbsx_lo_w),state)); - machine.device("maincpu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snsnew_state::snesbsx_hi_r),state), write8_delegate(FUNC(snsnew_state::snesbsx_hi_w),state)); - set_5a22_map(*state->m_maincpu); + case SNES_TEKKEN2: + machine.device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x808000, 0x8087ff, 0, 0x3f0000, read8_delegate(FUNC(device_sns_cart_interface::chip_read),state->m_slotcart->m_cart)); + machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0x808000, 0x8087ff, 0, 0x3f0000, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); + break; + case SNES_MCPIR1: + case SNES_MCPIR2: + machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0xffff00, 0xffffff, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); + break; + case SNES_20COL: + // why is this not working? investigate... + machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0x008000, 0x008fff, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); + break; + case SNES_SOULBLAD: + // reads from xxx0-xxx3in range [80-bf] return a fixed sequence of 4bits; reads in range [c0-ff] return open bus + machine.device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x808000, 0x808003, 0, 0x3f7ff0, read8_delegate(FUNC(device_sns_cart_interface::chip_read),state->m_slotcart->m_cart)); + machine.device("maincpu")->memory().space(AS_PROGRAM).install_legacy_read_handler(0xc00000, 0xffffff, FUNC(snes_open_bus_r)); + break; + case SNES_BUGS: + case SNES_BANANA: +// machine.device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x808000, 0x80ffff, 0, 0x780000, read8_delegate(FUNC(device_sns_cart_interface::chip_read),state->m_slotcart->m_cart)); +// machine.device("maincpu")->memory().space(AS_PROGRAM).install_write_handler(0x808000, 0x80ffff, 0, 0x780000, write8_delegate(FUNC(device_sns_cart_interface::chip_write),state->m_slotcart->m_cart)); +// set_5a22_map(*state->m_maincpu); break; } } diff --git a/src/mess/machine/sns_rom.c b/src/mess/machine/sns_rom.c index 1bcc7208709..084de845738 100644 --- a/src/mess/machine/sns_rom.c +++ b/src/mess/machine/sns_rom.c @@ -20,6 +20,14 @@ const device_type SNS_LOROM = &device_creator; const device_type SNS_LOROM_OBC1 = &device_creator; // LoROM pirate carts with protection const device_type SNS_LOROM_POKEMON = &device_creator; +const device_type SNS_LOROM_TEKKEN2 = &device_creator; +const device_type SNS_LOROM_SOULBLAD = &device_creator; +const device_type SNS_LOROM_BANANA = &device_creator; +const device_type SNS_LOROM_BUGSLIFE = &device_creator; +// LoROM pirate multicarts +const device_type SNS_LOROM_MCPIR1 = &device_creator; +const device_type SNS_LOROM_MCPIR2 = &device_creator; +const device_type SNS_LOROM_20COL = &device_creator; sns_rom_device::sns_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) @@ -34,31 +42,60 @@ sns_rom_device::sns_rom_device(const machine_config &mconfig, const char *tag, d { } -sns_rom_pokemon_device::sns_rom_pokemon_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : sns_rom_device(mconfig, SNS_LOROM_POKEMON, "SNES Pirate Carts with Protection", tag, owner, clock) -{ -} - sns_rom_obc1_device::sns_rom_obc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : sns_rom_device(mconfig, SNS_LOROM_OBC1, "SNES Cart (LoROM) + OBC-1", tag, owner, clock) { } + +// Pirate LoROM 'mappers' +sns_rom_pokemon_device::sns_rom_pokemon_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_POKEMON, "SNES Pirate Carts with Protection", tag, owner, clock) +{ +} + +sns_rom_tekken2_device::sns_rom_tekken2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_TEKKEN2, "SNES Pirate Carts with Protection", tag, owner, clock) +{ +} + +sns_rom_soulblad_device::sns_rom_soulblad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_SOULBLAD, "SNES Pirate Carts with Protection", tag, owner, clock) +{ +} + +sns_rom_banana_device::sns_rom_banana_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_BANANA, "SNES Pirate Carts with Protection", tag, owner, clock) +{ +} + +sns_rom_bugs_device::sns_rom_bugs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_BUGSLIFE, "SNES Pirate Carts with Protection", tag, owner, clock) +{ +} + +// Multigame LoROM 'mappers' +sns_rom_mcpirate1_device::sns_rom_mcpirate1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_MCPIR1, "SNES Pirate Multigame Carts Type 1", tag, owner, clock) +{ +} + +sns_rom_mcpirate2_device::sns_rom_mcpirate2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_MCPIR2, "SNES Pirate Multigame Carts Type 2", tag, owner, clock) +{ +} + +sns_rom_20col_device::sns_rom_20col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_20COL, "SNES Super 20 Collection", tag, owner, clock) +{ +} + + void sns_rom_device::device_start() { } -void sns_rom_pokemon_device::device_start() -{ - save_item(NAME(m_latch)); -} - -void sns_rom_pokemon_device::device_reset() -{ - m_latch = 0; -} - void sns_rom_obc1_device::device_start() { save_item(NAME(m_ram)); @@ -77,6 +114,65 @@ void sns_rom_obc1_device::device_reset() } +void sns_rom_pokemon_device::device_start() +{ + save_item(NAME(m_latch)); +} + +void sns_rom_pokemon_device::device_reset() +{ + m_latch = 0; +} + +void sns_rom_tekken2_device::device_start() +{ + save_item(NAME(m_prot)); +} + +void sns_rom_tekken2_device::device_reset() +{ + m_prot = 0; +} + +void sns_rom_bugs_device::device_start() +{ + save_item(NAME(m_latch)); +} + +void sns_rom_bugs_device::device_reset() +{ + memset(m_latch, 0, sizeof(m_latch)); +} + + + +void sns_rom_mcpirate1_device::device_start() +{ + save_item(NAME(m_base_bank)); +} + +void sns_rom_mcpirate1_device::device_reset() +{ + m_base_bank = 0; +} + +void sns_rom_mcpirate2_device::device_start() +{ + save_item(NAME(m_base_bank)); +} + +void sns_rom_mcpirate2_device::device_reset() +{ + m_base_bank = 0; +} + +void sns_rom_20col_device::device_start() +{ + m_base_bank = 4; + save_item(NAME(m_base_bank)); +} + + /*------------------------------------------------- mapper specific handlers -------------------------------------------------*/ @@ -94,19 +190,6 @@ READ8_MEMBER(sns_rom_device::read_h) -// Lo-ROM + Protection device - -READ8_MEMBER( sns_rom_pokemon_device::chip_read ) -{ - return BITSWAP8(m_latch,0,6,7,1,2,3,4,5); -} - -WRITE8_MEMBER( sns_rom_pokemon_device::chip_write ) -{ - m_latch = data; -} - - // Lo-ROM + OBC-1 (used by Metal Combat - Falcon's Revenge) // same as above but additional read/write handling for the add-on chip @@ -207,3 +290,224 @@ WRITE8_MEMBER( sns_rom_obc1_device::chip_write ) break; } } + + + +// Lo-ROM + Protection devices used in pirate carts + + +// Pokemon (and many others): a byte is written and a permutation of its bits must be returned. +// Address range for read/write depends on the game (check snes.xml) +READ8_MEMBER( sns_rom_pokemon_device::chip_read ) +{ + return BITSWAP8(m_latch,0,6,7,1,2,3,4,5); +} + +WRITE8_MEMBER( sns_rom_pokemon_device::chip_write ) +{ + m_latch = data; +} + + +// Tekken 2: It accesses the protection in a very strange way, always reading/writing the same data $f0 times, +// because each access must be repeated a couple of times to be registered (typically around 7-30 times) +// They probably used a microcontroller here. +// The protection itself is accessed in banks $80-$bf. Accessing (read/write, doesn't matter) adress lines +// A8,A9,A10 in these banks in a certain sequence makes the mc return a 4bit value. [d4s] +// Details on a possible algorythm behind the sequence of accesses were provided by nocash. Thanks! +void sns_rom_tekken2_device::update_prot(UINT32 offset) +{ + // accesses to [80-bf][8000-87ff] ranges update the protection value + offset &= 0x7ff; + + switch (offset & 0x700) + { + case 0x000: + m_prot = 0; + break; + case 0x100: + // used for read access + break; + case 0x200: // BIT 0 + m_prot |= 1; + break; + case 0x300: // BIT 1 + m_prot |= 2; + break; + case 0x400: // BIT 2 + m_prot |= 4; + break; + case 0x500: // BIT 3 + m_prot |= 8; + break; + case 0x600: // DIRECTION + m_prot |= 0x10; + break; + case 0x700: // FUNCTION + m_prot |= 0x20; + break; + } +} + +READ8_MEMBER( sns_rom_tekken2_device::chip_read ) +{ + update_prot(offset); + + if ((offset & 0x700) == 0x100) + { + if (BIT(m_prot, 5)) // FUNCTION = 1 means Shift + { + if (BIT(m_prot, 4)) // DIRECTION = 1 means Right + return (m_prot & 0x0f) >> 1; + else // DIRECTION = 0 means Left + return (m_prot & 0x0f) << 1; + } + else // FUNCTION = 0 means Add/Sub + { + if (BIT(m_prot, 4)) // DIRECTION = 1 means Minus + return (m_prot & 0x0f) - 1; + else // DIRECTION = 0 means Plus + return (m_prot & 0x0f) + 1; + } + } + + return 0xff; // should be open_bus +} + +WRITE8_MEMBER( sns_rom_tekken2_device::chip_write ) +{ + update_prot(offset); +} + + +// Soul Blade: Adresses $xxx0-$xxx3 in banks $80-$bf always read $55, $0f, $aa, $f0. +// Banks $c0-$ff return open bus. +READ8_MEMBER( sns_rom_soulblad_device::chip_read ) +{ + UINT8 value = 0; + offset &= 3; + switch (offset) + { + case 0: + default: + value = 0x55; + break; + case 1: + value = 0x0f; + break; + case 2: + value = 0xaa; + break; + case 3: + value = 0xf0; + break; + } + return value; +} + +// Multicart pirate banking emulation +// LoROM games, writes to [ff][ff00-ffff] control bankswitch +// The actual banks depends on the last 8bits of the address accessed. + +// Type 1: bits0-4 of the address are used as base bank (256KB chunks) +READ8_MEMBER(sns_rom_mcpirate1_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_mcpirate1_device::read_h) +{ + int bank = (offset / 0x10000) + (m_base_bank * 8); + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + +WRITE8_MEMBER( sns_rom_mcpirate1_device::chip_write ) +{ + m_base_bank = offset & 0x1f; +// printf("offset %X data %X bank %X\n", offset, data, m_base_bank); +} + +// Type 2: bits0-3 & bit5 of the address are used as base bank (256KB chunks) +READ8_MEMBER(sns_rom_mcpirate2_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_mcpirate2_device::read_h) +{ + int bank = (offset / 0x10000) + (m_base_bank * 8); + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + +WRITE8_MEMBER( sns_rom_mcpirate2_device::chip_write ) +{ + m_base_bank = (offset & 0x0f) | ((offset & 0x20) >> 1); +// printf("offset %X data %X bank %X\n", offset, data, m_base_bank); +} + +// Korean 20 in 1 collection with NES games +// base bank is selected (in 32KB chunks) by bits 0-4 of data written at 0x808000 +READ8_MEMBER(sns_rom_20col_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_20col_device::read_h) +{ + int bank = (offset / 0x10000); + return m_rom[(rom_bank_map[bank] + m_base_bank) * 0x8000 + (offset & 0x7fff)]; +} + +WRITE8_MEMBER( sns_rom_20col_device::chip_write ) +{ + // [#] game - written bank value + // [01] spartan x - c6 + // [02] smb - c8 + // [03] antarcitc adv - 8e + // [04] twinbee - ca + // [05] battle city - 8f + // [06] circus charlie - 90 + // [07] galaga - 91 + // [08] yie ar kungfu - 92 + // [09] star force - 93 + // [10] road fighter - 94 + // [11] pinball - 95 + // [12] bomberman - 96 + // [13] new tetris?? - 0 + // [14] arkanoid - cc + // [15] balloon fight - 97 + // [16] donkey kong - 98 + // [17] donkey kong 3 - 99 + // [18] donkey kong jr - 9a + // [19] mario bros - 9b + // [20] popeye - 9c + m_base_bank = data & 0x1f; +// printf("offset %X data %X bank %X\n", offset, data, m_base_bank); +} + + + +// Work in progress (probably very wrong) + +READ8_MEMBER( sns_rom_banana_device::chip_read ) +{ + return BITSWAP8(m_latch[0xf],0,6,7,1,2,3,4,5); +} + +WRITE8_MEMBER( sns_rom_banana_device::chip_write ) +{ +// printf("write addr %X data %X\n", offset, data); + m_latch[0xf] = data; +} + +READ8_MEMBER( sns_rom_bugs_device::chip_read ) +{ + return BITSWAP8(m_latch[offset & 0xff],0,6,7,1,2,3,4,5); +} + +WRITE8_MEMBER( sns_rom_bugs_device::chip_write ) +{ + m_latch[offset & 0xff] = data; +} + + diff --git a/src/mess/machine/sns_rom.h b/src/mess/machine/sns_rom.h index 6b136e1c839..2cded87bfbe 100644 --- a/src/mess/machine/sns_rom.h +++ b/src/mess/machine/sns_rom.h @@ -23,6 +23,31 @@ public: virtual DECLARE_READ8_MEMBER(read_h); }; +// ======================> sns_rom_obc1_device + +class sns_rom_obc1_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_obc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete() { m_shortname = "sns_rom_obc1"; } + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + int m_address; + int m_offset; + int m_shift; + UINT8 m_ram[0x2000]; +}; + + + // ======================> sns_rom_pokemon_device class sns_rom_pokemon_device : public sns_rom_device @@ -42,27 +67,140 @@ public: UINT8 m_latch; }; -// ======================> sns_rom_obc1_device +// ======================> sns_rom_tekken2_device -class sns_rom_obc1_device : public sns_rom_device +class sns_rom_tekken2_device : public sns_rom_device { public: // construction/destruction - sns_rom_obc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - + sns_rom_tekken2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // device-level overrides virtual void device_start(); virtual void device_reset(); - virtual void device_config_complete() { m_shortname = "sns_rom_obc1"; } + virtual void device_config_complete() { m_shortname = "sns_rom_tekken2"; } + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device + virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device - // additional reading and writing - virtual DECLARE_READ8_MEMBER(chip_read); - virtual DECLARE_WRITE8_MEMBER(chip_write); + void update_prot(UINT32 offset); - int m_address; - int m_offset; - int m_shift; - UINT8 m_ram[0x2000]; + // bit0-3 prot value, bit4 direction, bit5 function + // reads must return (prot value) +1/-1/<<1/>>1 depending on bit4 & bit5 + UINT8 m_prot; +}; + +// ======================> sns_rom_soulblad_device + +class sns_rom_soulblad_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_soulblad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_config_complete() { m_shortname = "sns_rom_soulblad"; } + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device +}; + +// ======================> sns_rom_mcpirate1_device + +class sns_rom_mcpirate1_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_mcpirate1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete() { m_shortname = "sns_rom_mcpirate1"; } + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device + UINT8 m_base_bank; +}; + +// ======================> sns_rom_mcpirate2_device + +class sns_rom_mcpirate2_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_mcpirate2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete() { m_shortname = "sns_rom_mcpirate2"; } + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device + UINT8 m_base_bank; +}; + +// ======================> sns_rom_20col_device + +class sns_rom_20col_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_20col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { m_shortname = "sns_rom_20col"; } + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device + UINT8 m_base_bank; +}; + +// ======================> sns_rom_banana_device + +class sns_rom_banana_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_banana_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides +// virtual void device_start(); +// virtual void device_reset(); + virtual void device_config_complete() { m_shortname = "sns_rom_banana"; } + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device + virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device + UINT8 m_latch[16]; +}; + +// ======================> sns_rom_bugs_device + +class sns_rom_bugs_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_bugs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete() { m_shortname = "sns_rom_bugslife"; } + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device + virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device + UINT8 m_latch[0x800]; }; @@ -70,5 +208,12 @@ public: extern const device_type SNS_LOROM; extern const device_type SNS_LOROM_OBC1; extern const device_type SNS_LOROM_POKEMON; +extern const device_type SNS_LOROM_TEKKEN2; +extern const device_type SNS_LOROM_SOULBLAD; +extern const device_type SNS_LOROM_MCPIR1; +extern const device_type SNS_LOROM_MCPIR2; +extern const device_type SNS_LOROM_20COL; +extern const device_type SNS_LOROM_BANANA; +extern const device_type SNS_LOROM_BUGSLIFE; #endif diff --git a/src/mess/machine/sns_slot.c b/src/mess/machine/sns_slot.c index edb9b77f2a0..7bde75736dc 100644 --- a/src/mess/machine/sns_slot.c +++ b/src/mess/machine/sns_slot.c @@ -259,8 +259,13 @@ static const sns_slot slot_list[] = { SNES_STROM, "strom"}, // pirate carts { SNES_POKEMON, "lorom_poke"}, - { SNES_BANANA, "lorom_paja"}, // wip - { SNES_SOULBLAD, "lorom_sbld"} // wip + { SNES_TEKKEN2, "lorom_tekken2"}, + { SNES_SOULBLAD, "lorom_sbld"}, + { SNES_MCPIR1, "lorom_mcpir1"}, + { SNES_MCPIR2, "lorom_mcpir2"}, + { SNES_20COL, "lorom_20col"}, + { SNES_BANANA, "lorom_pija"}, // wip + { SNES_BUGS, "lorom_bugs"} // wip }; static int sns_get_pcb_id(const char *slot) @@ -695,7 +700,7 @@ void base_sns_cart_slot_device::setup_nvram() if (sram_size) { UINT32 max = (hilo_mode == 0x007fc0) ? 0x80000 : 0x20000; // MODE20 vs MODE21 - size = 1024 << (ROM[0x00ffbd] & 0x07); + size = 1024 << sram_size; if (size > max) size = max; } diff --git a/src/mess/machine/sns_slot.h b/src/mess/machine/sns_slot.h index 77c4b1d6a8d..a350ee81456 100644 --- a/src/mess/machine/sns_slot.h +++ b/src/mess/machine/sns_slot.h @@ -37,8 +37,13 @@ enum SNES_STROM, // pirate carts SNES_POKEMON, + SNES_TEKKEN2, + SNES_SOULBLAD, + SNES_MCPIR1, + SNES_MCPIR2, + SNES_20COL, SNES_BANANA, // wip - SNES_SOULBLAD // wip + SNES_BUGS // wip };