summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess
diff options
context:
space:
mode:
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
commit5c2b6036df886a416ea727ecb72da2827b43bd93 (patch)
tree9ec8010ac4ec5bc6bbdb4a600a6d4e02afa7219c /src/mess
parent57aaa4f9a68826c3d3f0ef8d9270885513ca37ec (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.c5
-rw-r--r--src/mess/machine/nes.c5
-rw-r--r--src/mess/machine/nes_karastudio.c217
-rw-r--r--src/mess/machine/nes_karastudio.h118
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;
};