diff options
author | Fabio Priuli <etabeta78@users.noreply.github.com> | 2014-02-19 05:48:54 +0000 |
---|---|---|
committer | Fabio Priuli <etabeta78@users.noreply.github.com> | 2014-02-19 05:48:54 +0000 |
commit | 5c2b6036df886a416ea727ecb72da2827b43bd93 (patch) | |
tree | 9ec8010ac4ec5bc6bbdb4a600a6d4e02afa7219c /src/mess | |
parent | 57aaa4f9a68826c3d3f0ef8d9270885513ca37ec (diff) |
(MESS) nes: Properly implemented the Bandai Karaoke Studio expansion
slot. The two Senyou Cassettes (Top Hit 20 Vol 1 & Vol 2) have now to be
loaded with the following commands "mess nes -cart karaoke -cart2 top20v1"
(or top20v2). This is accurate to the hardware, because these expansions
had to be manually inserted into the body of the main Karaoke Studio cart
before playing. [Fabio Priuli]
Diffstat (limited to 'src/mess')
-rw-r--r-- | src/mess/drivers/nes.c | 5 | ||||
-rw-r--r-- | src/mess/machine/nes.c | 5 | ||||
-rw-r--r-- | src/mess/machine/nes_karastudio.c | 217 | ||||
-rw-r--r-- | src/mess/machine/nes_karastudio.h | 118 |
4 files changed, 333 insertions, 12 deletions
diff --git a/src/mess/drivers/nes.c b/src/mess/drivers/nes.c index 807b25f20e9..ba8a7ec19f5 100644 --- a/src/mess/drivers/nes.c +++ b/src/mess/drivers/nes.c @@ -1070,8 +1070,9 @@ static MACHINE_CONFIG_START( nes, nes_state ) MCFG_NES_CARTRIDGE_ADD("nes_slot", nes_crt_interface, nes_cart, NULL) MCFG_SOFTWARE_LIST_ADD("cart_list", "nes") - MCFG_SOFTWARE_LIST_ADD("ntb_list", "nes_ntbrom") // Sunsoft Nantettate! Baseball mini-carts - MCFG_SOFTWARE_LIST_ADD("datach_list", "nes_datach") // Bandai Datach Joint ROM System mini-carts + MCFG_SOFTWARE_LIST_ADD("ntb_list", "nes_ntbrom") // Sunsoft Nantettate! Baseball mini-carts + MCFG_SOFTWARE_LIST_ADD("kstudio_list", "nes_kstudio") // Bandai Karaoke Studio expansion carts + MCFG_SOFTWARE_LIST_ADD("datach_list", "nes_datach") // Bandai Datach Joint ROM System mini-carts MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( nespal, nes ) diff --git a/src/mess/machine/nes.c b/src/mess/machine/nes.c index 3c7c8e8ea26..d3d2461df6c 100644 --- a/src/mess/machine/nes.c +++ b/src/mess/machine/nes.c @@ -159,8 +159,9 @@ void nes_state::machine_start() m_ppu->set_latch(ppu2c0x_latch_delegate(FUNC(device_nes_cart_interface::ppu_latch),m_cartslot->m_cart)); // install additional handlers (read_h, read_ex, write_ex) - if (m_cartslot->get_pcb_id() == STD_NROM368 || m_cartslot->get_pcb_id() == GG_NROM || m_cartslot->get_pcb_id() == SUNSOFT_DCS || m_cartslot->get_pcb_id() == BANDAI_DATACH - || m_cartslot->get_pcb_id() == AVE_MAXI15 || m_cartslot->get_pcb_id() == KAISER_KS7022 || m_cartslot->get_pcb_id() == KAISER_KS7031 || m_cartslot->get_pcb_id() == BMC_VT5201 + if (m_cartslot->get_pcb_id() == STD_NROM368 || m_cartslot->get_pcb_id() == GG_NROM || m_cartslot->get_pcb_id() == SUNSOFT_DCS + || m_cartslot->get_pcb_id() == BANDAI_DATACH || m_cartslot->get_pcb_id() == BANDAI_KARAOKE || m_cartslot->get_pcb_id() == AVE_MAXI15 + || m_cartslot->get_pcb_id() == KAISER_KS7022 || m_cartslot->get_pcb_id() == KAISER_KS7031 || m_cartslot->get_pcb_id() == BMC_VT5201 || m_cartslot->get_pcb_id() == UNL_LH32 || m_cartslot->get_pcb_id() == UNL_LH10 || m_cartslot->get_pcb_id() == UNL_2708 || m_cartslot->get_pcb_id() == UNL_43272 || m_cartslot->get_pcb_id() == BMC_G63IN1 || m_cartslot->get_pcb_id() == BMC_8157 || m_cartslot->get_pcb_id() == BMC_GOLD150 || m_cartslot->get_pcb_id() == BMC_CH001 diff --git a/src/mess/machine/nes_karastudio.c b/src/mess/machine/nes_karastudio.c index 46877416b77..5335d8a9c7e 100644 --- a/src/mess/machine/nes_karastudio.c +++ b/src/mess/machine/nes_karastudio.c @@ -8,10 +8,23 @@ 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: - - emulate the actual expansion slot for the Senyou Cassettes + - 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 ***********************************************************************************************************/ @@ -28,16 +41,157 @@ #define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) +//----------------------------------------- +// +// Karaoke Studio Cartslot implementation +// +//----------------------------------------- //------------------------------------------------- -// constructor +// 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), + m_rom_size(0) +{ +} + +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(char *swlist, char *swname, rom_entry *start_entry) +{ + load_software_part_region(this, swlist, swname, start_entry ); + return TRUE; +} + +const char * nes_kstudio_slot_device::get_default_card_software(const machine_config &config, emu_options &options) +{ + return software_get_default_slot(config, options, this, "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") { } @@ -46,6 +200,7 @@ nes_karaokestudio_device::nes_karaokestudio_device(const machine_config &mconfig void nes_karaokestudio_device::device_start() { common_start(); + save_item(NAME(m_exp_active)); } void nes_karaokestudio_device::pcb_reset() @@ -54,6 +209,7 @@ void nes_karaokestudio_device::pcb_reset() prg16_89ab(0); prg16_cdef((m_prg_chunks - 1) ^ 0x08); chr8(0, m_chr_source); + m_exp_active = 0; } @@ -81,20 +237,47 @@ READ8_MEMBER(nes_karaokestudio_device::read_m) 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), so we load the expansion after the main PRG and handle banking as follows - data ^= 8; - - prg16_89ab(data); + // 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) @@ -107,3 +290,23 @@ 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("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 ); +} + diff --git a/src/mess/machine/nes_karastudio.h b/src/mess/machine/nes_karastudio.h index b42642732f3..9043dc5c38a 100644 --- a/src/mess/machine/nes_karastudio.h +++ b/src/mess/machine/nes_karastudio.h @@ -4,6 +4,117 @@ #include "machine/nes_nxrom.h" +//----------------------------------------- +// +// Karaoke Studio Cartslot implementation +// +//----------------------------------------- + +// ======================> kstudio_cart_interface + +class kstudio_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + kstudio_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~kstudio_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + + UINT8 *get_cart_base() { return m_rom; } + void write_prg_bank(UINT8 bank) { m_bank = bank; } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + // ROM is accessed via two 16K banks, but only the first one can be switched + UINT8 m_bank; +}; + +// ======================> nes_kstudio_slot_device + +class nes_kstudio_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + nes_kstudio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nes_kstudio_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { update_names(); } + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(char *swlist, char *swname, rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "ks_cart"; } + virtual const char *file_extensions() const { return "bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual const char * get_default_card_software(const machine_config &config, emu_options &options); + + virtual DECLARE_READ8_MEMBER(read); + void write_prg_bank(UINT8 bank) { if (m_cart) m_cart->write_prg_bank(bank); } + + kstudio_cart_interface* m_cart; +}; + +// device type definition +extern const device_type NES_KSEXPANSION_SLOT; + + +#define MCFG_KSTUDIO_MINICART_ADD(_tag, _slot_intf) \ + MCFG_DEVICE_ADD(_tag, NES_KSEXPANSION_SLOT, 0) \ +MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, false) + + +//----------------------------------------------- +// +// Karaoke Studio Expansion cart implementation +// +//----------------------------------------------- + +// ======================> nes_kstudio_rom_device + +class nes_kstudio_rom_device : public device_t, + public kstudio_cart_interface +{ +public: + // construction/destruction + nes_kstudio_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual UINT8* get_cart_base(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + +// device type definition +extern const device_type NES_KSEXPANSION_ROM; + + +//------------------------------------------- +// +// Karaoke Studio Base Cart implementation +// +//------------------------------------------- + // ======================> nes_karaokestudio_device class nes_karaokestudio_device : public nes_nrom_device @@ -15,11 +126,16 @@ public: // device-level overrides virtual void device_start(); virtual ioport_constructor device_input_ports() const; - virtual DECLARE_WRITE8_MEMBER(write_h); + virtual machine_config_constructor device_mconfig_additions() const; virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); virtual void pcb_reset(); +protected: + int m_exp_active; + required_device<nes_kstudio_slot_device> m_subslot; required_ioport m_mic_ipt; }; |