diff options
Diffstat (limited to 'src/devices/bus/nes/karastudio.c')
-rw-r--r-- | src/devices/bus/nes/karastudio.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/src/devices/bus/nes/karastudio.c b/src/devices/bus/nes/karastudio.c new file mode 100644 index 00000000000..002bdf6eea3 --- /dev/null +++ b/src/devices/bus/nes/karastudio.c @@ -0,0 +1,309 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai Karaoke Studio + + + Here we emulate the following PCBs Bandai Karaoke Studio [mapper 188] + + The Karaoke Studio cart consist of a large connector which fits the FC cart slot, with a microphone + connected. The game data is in the connector itself. The microphone has two buttons on it, and the + game uses these only to navigate through the menus (the two buttons are not read through the controller + port, which is not accessible from the cart, but from $6000-$7fff). Part of the connector body can be + removed to be replaced by an expansion cart containing new songs (we emulate this by adding a -cart2 slot). + + + TODO: + - verify expansion slot emulation for the Senyou Cassettes: + not much documentation exists about the expansion carts (except for few paragraphs + at Enri's FC webpage), so I implemented it based on "common sense" + * expansion carts do not contain the required game data => main PRG must be in the main cart + so to remain connected even when an expansion is inserted (differently from Datach, where + the base unit contains no PRG) + * bankswicth writes with bit3=0 (to access expansion) when no expansion is present should do + nothing + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "karastudio.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//----------------------------------------- +// +// Karaoke Studio Cartslot implementation +// +//----------------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +kstudio_cart_interface::kstudio_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL) +{ +} + +kstudio_cart_interface::~kstudio_cart_interface() +{ +} + +READ8_MEMBER(kstudio_cart_interface::read) +{ + return m_rom[(m_bank * 0x4000) + (offset & 0x3fff)]; +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_KSEXPANSION_SLOT = &device_creator<nes_kstudio_slot_device>; + +nes_kstudio_slot_device::nes_kstudio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_KSEXPANSION_SLOT, "NES Karaoke Studio Expansion Slot", tag, owner, clock, "nes_ks_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_kstudio_slot_device::~nes_kstudio_slot_device() +{ +} + + +void nes_kstudio_slot_device::device_start() +{ + m_cart = dynamic_cast<kstudio_cart_interface *>(get_card_device()); +} + +READ8_MEMBER(nes_kstudio_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + +bool nes_kstudio_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + + if (!ROM) + return IMAGE_INIT_FAIL; + + // Existing exapnsion carts are all 128K, so we only load files of this size + if (software_entry() == NULL) + { + if (length() != 0x20000) + return IMAGE_INIT_FAIL; + + fread(&ROM, 0x20000); + } + else + { + if (get_software_region_length("rom") != 0x20000) + return IMAGE_INIT_FAIL; + + memcpy(ROM, get_software_region("rom"), 0x20000); + } + } + + return IMAGE_INIT_PASS; +} + + +bool nes_kstudio_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_kstudio_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "ks_exp"); +} + + +//----------------------------------------------- +// +// Karaoke Studio Expansion cart implementation +// +//----------------------------------------------- + +ROM_START( ks_exp_rom ) + ROM_REGION(0x20000, "exrom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_KSEXPANSION_ROM = &device_creator<nes_kstudio_rom_device>; + +nes_kstudio_rom_device::nes_kstudio_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_KSEXPANSION_ROM, "NES Karaoke Studio Expansion ROM", tag, owner, clock, "nes_ks_rom", __FILE__), + kstudio_cart_interface( mconfig, *this ) +{ +} + +void nes_kstudio_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("exrom")->base(); + save_item(NAME(m_bank)); +} + +void nes_kstudio_rom_device::device_reset() +{ + m_bank = 0; +} + +const rom_entry *nes_kstudio_rom_device::device_rom_region() const +{ + return ROM_NAME( ks_exp_rom ); +} + +UINT8 *nes_kstudio_rom_device::get_cart_base() +{ + return m_rom; +} + + +//------------------------------------------ +// +// Karaoke Studio Base Cart implementation +// +//------------------------------------------ + +const device_type NES_KARAOKESTUDIO = &device_creator<nes_karaokestudio_device>; + + +nes_karaokestudio_device::nes_karaokestudio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KARAOKESTUDIO, "NES Cart Bandai Karaoke Studio PCB", tag, owner, clock, "nes_karaoke", __FILE__), + m_subslot(*this, "exp_slot"), + m_mic_ipt(*this, "MIC") +{ +} + + +void nes_karaokestudio_device::device_start() +{ + common_start(); + save_item(NAME(m_exp_active)); +} + +void nes_karaokestudio_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef((m_prg_chunks - 1) ^ 0x08); + chr8(0, m_chr_source); + m_exp_active = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai Karaoke Studio board emulation + + Games: Karaoke Studio + expansion carts with + additional songs + + Note: we currently do not emulate properly the + expansion slot + + iNES: mapper 188 + + -------------------------------------------------*/ + +READ8_MEMBER(nes_karaokestudio_device::read_m) +{ + LOG_MMC(("karaoke studio read_m, offset: %04x\n", offset)); + return m_mic_ipt->read(); +} + +READ8_MEMBER(nes_karaokestudio_device::read_h) +{ + LOG_MMC(("karaoke studio read_h, offset: %04x\n", offset)); + // this shall be the proper code, but it's a bit slower, so we access directly the subcart below + //return m_subslot->read(space, offset, mem_mask); + + // access expansion cart only if all of the followings are verified + // * we are in $8000-$bfff range + // * there has been a bankswitch write to map the expansion to such range + // * there actually is an expansion cart mounted + if (offset < 0x4000 && m_exp_active && m_subslot->m_cart) + return m_subslot->m_cart->read(space, offset, mem_mask); + else + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_karaokestudio_device::write_h) +{ + LOG_MMC(("karaoke studio write_h, offset: %04x, data: %02x\n", offset, data)); + // bit3 1 = M ROM (main unit), 0=E ROM (expansion) + // HACK(?): currently it is not clear how the unit acknowledges the presence of the expansion + // cart (when expansion is present, code keeps switching both from the expansion rom and from + // the main ROM) + // my guess is that writes with bit3=0 and no expansion just do nothing, but it shall be verified + + if (offset >= 04000) + { + if (BIT(data, 3)) + { + m_exp_active = 0; + prg16_89ab(data & 7); + } + else // expansion cart + { + m_exp_active = 1; + m_subslot->write_prg_bank(data & 7); + } + } +} + + +static INPUT_PORTS_START( karaoke_mic ) + PORT_START("MIC") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A (Mic Select)") PORT_CODE(KEYCODE_X) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B (Mic Start)") PORT_CODE(KEYCODE_Z) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Microphone (?)") PORT_CODE(KEYCODE_C) + PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +ioport_constructor nes_karaokestudio_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( karaoke_mic ); +} + + +//------------------------------------------------- +// CART SLOT +//------------------------------------------------- + +static SLOT_INTERFACE_START(karaoke_studio_cart) + SLOT_INTERFACE_INTERNAL("ks_exp", NES_KSEXPANSION_ROM) +SLOT_INTERFACE_END + + +MACHINE_CONFIG_FRAGMENT( karaoke_studio ) + MCFG_KSTUDIO_MINICART_ADD("exp_slot", karaoke_studio_cart) +MACHINE_CONFIG_END + +machine_config_constructor nes_karaokestudio_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( karaoke_studio ); +} |