mame/src/devices/bus/msx/cart/konami.cpp
wilbertpol 52b97dd330
msx/slot/cartridge.cpp: Stop copying software memory region contents. (#10629)
* bus/msx/cart: Replaced fatal errors with image_init_result and a descriptive message.
2022-12-05 01:12:47 +11:00

670 lines
29 KiB
C++

// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
#include "emu.h"
#include "konami.h"
#include "speaker.h"
DEFINE_DEVICE_TYPE(MSX_CART_KONAMI, msx_cart_konami_device, "msx_cart_konami", "MSX Cartridge - KONAMI")
DEFINE_DEVICE_TYPE(MSX_CART_KONAMI_SCC, msx_cart_konami_scc_device, "msx_cart_konami_scc", "MSX Cartridge - KONAMI+SCC")
DEFINE_DEVICE_TYPE(MSX_CART_GAMEMASTER2, msx_cart_gamemaster2_device, "msx_cart_gamemaster2", "MSX Cartridge - GAMEMASTER2")
DEFINE_DEVICE_TYPE(MSX_CART_SYNTHESIZER, msx_cart_synthesizer_device, "msx_cart_synthesizer", "MSX Cartridge - Synthesizer")
DEFINE_DEVICE_TYPE(MSX_CART_SOUND_SNATCHER, msx_cart_konami_sound_snatcher_device, "msx_cart_sound_snatcher", "MSX Cartridge - Sound Snatcher")
DEFINE_DEVICE_TYPE(MSX_CART_SOUND_SDSNATCHER, msx_cart_konami_sound_sdsnatcher_device, "msx_cart_sound_sdsnatcher", "MSX Cartridge - Sound SD Snatcher")
DEFINE_DEVICE_TYPE(MSX_CART_KEYBOARD_MASTER, msx_cart_keyboard_master_device, "msx_cart_keyboard_master", "MSX Cartridge - Keyboard Master")
DEFINE_DEVICE_TYPE(MSX_CART_EC701, msx_cart_ec701_device, "msx_cart_ec701", "MSX Cartridge - Konami EC-701")
msx_cart_konami_device::msx_cart_konami_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, MSX_CART_KONAMI, tag, owner, clock)
, msx_cart_interface(mconfig, *this)
, m_rombank(*this, "rombank%u", 0U)
, m_bank_mask(0)
{
}
void msx_cart_konami_device::device_reset()
{
for (int i = 0; i < 4; i++)
m_rombank[i]->set_entry(i);
}
image_init_result msx_cart_konami_device::initialize_cartridge(std::string &message)
{
if (!cart_rom_region())
{
message = "msx_cart_konami_device: Required region 'rom' was not found.";
return image_init_result::FAIL;
}
const u32 size = cart_rom_region()->bytes();
const u16 banks = size / 0x2000;
if (size > 256 * 0x2000 || size < 4 * 0x2000 || size != banks * 0x2000 || (~(banks - 1) % banks))
{
message = "msx_cart_konami_device: Region 'rom' has unsupported size.";
return image_init_result::FAIL;
}
m_bank_mask = banks - 1;
for (int i = 0; i < 4; i++)
m_rombank[i]->configure_entries(0, banks, cart_rom_region()->base(), 0x2000);
page(0)->install_read_bank(0x0000, 0x1fff, m_rombank[0]);
page(0)->install_read_bank(0x2000, 0x3fff, m_rombank[1]);
page(1)->install_read_bank(0x4000, 0x5fff, m_rombank[0]);
page(1)->install_write_handler(0x4000, 0x47ff, 0, 0x1000, 0, write8smo_delegate(*this, FUNC(msx_cart_konami_device::bank_w<0>)));
page(1)->install_read_bank(0x6000, 0x7fff, m_rombank[1]);
page(1)->install_write_handler(0x6000, 0x67ff, 0, 0x1000, 0, write8smo_delegate(*this, FUNC(msx_cart_konami_device::bank_w<1>)));
page(2)->install_read_bank(0x8000, 0x9fff, m_rombank[2]);
page(2)->install_write_handler(0x8000, 0x87ff, 0, 0x1000, 0, write8smo_delegate(*this, FUNC(msx_cart_konami_device::bank_w<2>)));
page(2)->install_read_bank(0xa000, 0xbfff, m_rombank[3]);
page(2)->install_write_handler(0xa000, 0xa7ff, 0, 0x1000, 0, write8smo_delegate(*this, FUNC(msx_cart_konami_device::bank_w<3>)));
page(3)->install_read_bank(0xc000, 0xdfff, m_rombank[2]);
page(3)->install_read_bank(0xe000, 0xffff, m_rombank[3]);
return image_init_result::PASS;
}
template <int Bank>
void msx_cart_konami_device::bank_w(u8 data)
{
m_rombank[Bank]->set_entry(data & m_bank_mask);
}
msx_cart_konami_scc_device::msx_cart_konami_scc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, MSX_CART_KONAMI_SCC, tag, owner, clock)
, msx_cart_interface(mconfig, *this)
, m_k051649(*this, "k051649")
, m_rombank(*this, "rombank%u", 0U)
, m_scc_view(*this, "scc_view")
, m_bank_mask(0)
{
}
void msx_cart_konami_scc_device::device_add_mconfig(machine_config &config)
{
// This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'.
SPEAKER(config, "mono").front_center();
K051649(config, m_k051649, XTAL(10'738'635)/3).add_route(ALL_OUTPUTS, "mono", 0.15);
}
void msx_cart_konami_scc_device::device_reset()
{
m_scc_view.select(0);
for (int i = 0; i < 4; i++)
m_rombank[i]->set_entry(i);
}
image_init_result msx_cart_konami_scc_device::initialize_cartridge(std::string &message)
{
if (!cart_rom_region())
{
message = "msx_cart_konami_scc_device: Required region 'rom' was not found.";
return image_init_result::FAIL;
}
const u32 size = cart_rom_region()->bytes();
const u16 banks = size / 0x2000;
if (size > 256 * 0x2000 || size < 0x8000 || size != banks * 0x2000 || (~(banks - 1) % banks))
{
message = "msx_cart_konami_scc_device: Region 'rom' has unsupported size.";
return image_init_result::FAIL;
}
m_bank_mask = banks - 1;
for (int i = 0; i < 4; i++)
m_rombank[i]->configure_entries(0, banks, cart_rom_region()->base(), 0x2000);
page(0)->install_read_bank(0x0000, 0x1fff, m_rombank[2]);
page(0)->install_read_bank(0x2000, 0x3fff, m_rombank[3]);
page(1)->install_read_bank(0x4000, 0x5fff, m_rombank[0]);
page(1)->install_write_handler(0x5000, 0x57ff, write8smo_delegate(*this, FUNC(msx_cart_konami_scc_device::bank_w<0>)));
page(1)->install_read_bank(0x6000, 0x7fff, m_rombank[1]);
page(1)->install_write_handler(0x7000, 0x77ff, write8smo_delegate(*this, FUNC(msx_cart_konami_scc_device::bank_w<1>)));
page(2)->install_view(0x8000, 0x9fff, m_scc_view);
m_scc_view[0].install_read_bank(0x8000, 0x9fff, m_rombank[2]);
m_scc_view[0].install_write_handler(0x9000, 0x97ff, write8smo_delegate(*this, FUNC(msx_cart_konami_scc_device::bank_w<2>)));
m_scc_view[1].install_read_bank(0x8000, 0x9fff, m_rombank[2]);
m_scc_view[1].install_write_handler(0x9000, 0x97ff, write8smo_delegate(*this, FUNC(msx_cart_konami_scc_device::bank_w<2>)));
m_scc_view[1].install_read_handler(0x9800, 0x987f, 0, 0x0700, 0, read8sm_delegate(m_k051649, FUNC(k051649_device::k051649_waveform_r)));
m_scc_view[1].install_write_handler(0x9800, 0x987f, 0, 0x0700, 0, write8sm_delegate(m_k051649, FUNC(k051649_device::k051649_waveform_w)));
m_scc_view[1].install_write_handler(0x9880, 0x9889, 0, 0x0710, 0, write8sm_delegate(m_k051649, FUNC(k051649_device::k051649_frequency_w)));
m_scc_view[1].install_write_handler(0x988a, 0x988e, 0, 0x0710, 0, write8sm_delegate(m_k051649, FUNC(k051649_device::k051649_volume_w)));
m_scc_view[1].install_write_handler(0x988f, 0x988f, 0, 0x0710, 0, write8smo_delegate(m_k051649, FUNC(k051649_device::k051649_keyonoff_w)));
m_scc_view[1].install_read_handler(0x98c0, 0x98c0, 0, 0x071f, 0, read8smo_delegate(m_k051649, FUNC(k051649_device::k051649_test_r)));
m_scc_view[1].install_write_handler(0x98c0, 0x98c0, 0, 0x071f, 0, write8smo_delegate(m_k051649, FUNC(k051649_device::k051649_test_w)));
page(2)->install_read_bank(0x8000, 0x9fff, m_rombank[2]);
page(2)->install_write_handler(0x9000, 0x97ff, write8smo_delegate(*this, FUNC(msx_cart_konami_scc_device::bank_w<2>)));
page(2)->install_read_bank(0xa000, 0xbfff, m_rombank[3]);
page(2)->install_write_handler(0xb000, 0xb7ff, write8smo_delegate(*this, FUNC(msx_cart_konami_scc_device::bank_w<3>)));
page(3)->install_read_bank(0xc000, 0xdfff, m_rombank[0]);
page(3)->install_read_bank(0xe000, 0xffff, m_rombank[1]);
return image_init_result::PASS;
}
template <int Bank>
void msx_cart_konami_scc_device::bank_w(u8 data)
{
m_rombank[Bank]->set_entry(data & m_bank_mask);
if (Bank == 2)
{
m_scc_view.select(((data & 0x3f) == 0x3f) ? 1 : 0);
}
}
msx_cart_gamemaster2_device::msx_cart_gamemaster2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, MSX_CART_GAMEMASTER2, tag, owner, clock)
, msx_cart_interface(mconfig, *this)
, m_rombank(*this, "rombank%u", 0U)
, m_rambank(*this, "rambank%u", 0U)
, m_view0(*this, "view0")
, m_view1(*this, "view1")
, m_view2(*this, "view2")
{
}
void msx_cart_gamemaster2_device::device_reset()
{
m_rombank[0]->set_entry(1);
m_rombank[1]->set_entry(1);
m_rombank[2]->set_entry(2);
m_view0.select(0);
m_view1.select(0);
m_view2.select(0);
}
image_init_result msx_cart_gamemaster2_device::initialize_cartridge(std::string &message)
{
if (!cart_rom_region())
{
message = "msx_cart_gamemaster2_device: Required region 'rom' was not found.";
return image_init_result::FAIL;
}
if (!cart_sram_region())
{
message = "msx_cart_gamemaster2_device: Required region 'sram' was not found.";
return image_init_result::FAIL;
}
const u32 size = cart_rom_region()->bytes();
const u16 banks = size / 0x2000;
if (size != 0x20000)
{
message = "msx_cart_gamemaster2_device: Region 'rom' has unsupported size.";
return image_init_result::FAIL;
}
if (cart_sram_region()->bytes() != 0x2000)
{
message = "msx_cart_gamemaster2_device: Region 'sram' has unsupported size.";
return image_init_result::FAIL;
}
for (int i = 0; i < 3; i++)
{
m_rombank[i]->configure_entries(0, banks, cart_rom_region()->base(), 0x2000);
m_rambank[i]->configure_entries(0, 2, cart_sram_region()->base(), 0x1000);
}
page(1)->install_rom(0x4000, 0x5fff, cart_rom_region()->base());
page(1)->install_view(0x6000, 0x7fff, m_view0);
m_view0[0].install_read_bank(0x6000, 0x7fff, m_rombank[0]);
m_view0[0].install_write_handler(0x6000, 0x6fff, write8smo_delegate(*this, FUNC(msx_cart_gamemaster2_device::bank_w<0>)));
m_view0[1].install_read_bank(0x6000, 0x6fff, 0x1000, m_rambank[0]);
m_view0[1].install_write_handler(0x6000, 0x6fff, write8smo_delegate(*this, FUNC(msx_cart_gamemaster2_device::bank_w<0>)));
page(2)->install_view(0x8000, 0x9fff, m_view1);
m_view1[0].install_read_bank(0x8000, 0x9fff, m_rombank[1]);
m_view1[0].install_write_handler(0x8000, 0x8fff, write8smo_delegate(*this, FUNC(msx_cart_gamemaster2_device::bank_w<1>)));
m_view1[1].install_read_bank(0x8000, 0x8fff, 0x1000, m_rambank[1]);
m_view1[1].install_write_handler(0x8000, 0x8fff, write8smo_delegate(*this, FUNC(msx_cart_gamemaster2_device::bank_w<1>)));
page(2)->install_view(0xa000, 0xbfff, m_view2);
m_view2[0].install_read_bank(0xa000, 0xbfff, m_rombank[2]);
m_view2[0].install_write_handler(0xa000, 0xafff, write8smo_delegate(*this, FUNC(msx_cart_gamemaster2_device::bank_w<2>)));
m_view2[1].install_read_bank(0xa000, 0xafff, m_rambank[2]);
m_view2[1].install_write_handler(0xa000, 0xafff, write8smo_delegate(*this, FUNC(msx_cart_gamemaster2_device::bank_w<2>)));
m_view2[1].install_readwrite_bank(0xb000, 0xbfff, m_rambank[2]);
return image_init_result::PASS;
}
template <int Bank>
void msx_cart_gamemaster2_device::bank_w(u8 data)
{
m_rombank[Bank]->set_entry(data & 0x0f);
m_rambank[Bank]->set_entry(BIT(data, 5) ? 1 : 0);
if (Bank == 0)
m_view0.select(BIT(data, 4) ? 1 : 0);
if (Bank == 1)
m_view1.select(BIT(data, 4) ? 1 : 0);
if (Bank == 2)
m_view2.select(BIT(data, 4) ? 1 : 0);
}
msx_cart_synthesizer_device::msx_cart_synthesizer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, MSX_CART_SYNTHESIZER, tag, owner, clock)
, msx_cart_interface(mconfig, *this)
, m_dac(*this, "dac")
{
}
void msx_cart_synthesizer_device::device_add_mconfig(machine_config &config)
{
// This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'.
SPEAKER(config, "speaker").front_center();
DAC_8BIT_R2R(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.3); // unknown DAC
}
image_init_result msx_cart_synthesizer_device::initialize_cartridge(std::string &message)
{
if (!cart_rom_region())
{
message = "msx_cart_synthesizer_device: Required region 'rom' was not found.";
return image_init_result::FAIL;
}
if (cart_rom_region()->bytes() != 0x8000)
{
message = "msx_cart_synthesizer_device: Region 'rom' has unsupported size.";
return image_init_result::FAIL;
}
page(1)->install_rom(0x4000, 0x7fff, cart_rom_region()->base());
page(1)->install_write_handler(0x4000, 0x4000, 0, 0x3fef, 0, write8smo_delegate(m_dac, FUNC(dac_byte_interface::write)));
page(2)->install_rom(0x8000, 0xbfff, cart_rom_region()->base() + 0x4000);
return image_init_result::PASS;
}
msx_cart_konami_sound_device::msx_cart_konami_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 min_rambank, u8 max_rambank)
: device_t(mconfig, type, tag, owner, clock)
, msx_cart_interface(mconfig, *this)
, m_k052539(*this, "k052539")
, m_rambank(*this, "rambank%u", 0U)
, m_view0(*this, "view0")
, m_view1(*this, "view1")
, m_view2(*this, "view2")
, m_view3(*this, "view3")
, m_min_rambank(min_rambank)
, m_max_rambank(max_rambank)
, m_selected_bank{0, 0, 0, 0}
, m_control(0)
{
}
void msx_cart_konami_sound_device::device_add_mconfig(machine_config &config)
{
// This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'.
SPEAKER(config, "mono").front_center();
K051649(config, m_k052539, XTAL(10'738'635)/3).add_route(ALL_OUTPUTS, "mono", 0.15);
}
void msx_cart_konami_sound_device::device_start()
{
save_item(NAME(m_selected_bank));
save_item(NAME(m_control));
}
void msx_cart_konami_sound_device::device_reset()
{
m_control = 0;
for (int i = 0; i < 4; i++)
{
m_selected_bank[i] = i;
}
switch_bank<0>();
switch_bank<1>();
switch_bank<2>();
switch_bank<3>();
}
image_init_result msx_cart_konami_sound_device::initialize_cartridge(std::string &message)
{
for (int i = 0; i < 4; i++)
{
m_rambank[i]->configure_entries(0, 8, cart_ram_region()->base(), 0x2000);
}
// TODO Mirrors at 0000-3fff and c000-ffff
page(1)->install_view(0x4000, 0x5fff, m_view0);
m_view0[VIEW_READ].install_read_bank(0x4000, 0x5fff, m_rambank[0]);
m_view0[VIEW_READ].install_write_handler(0x5000, 0x57ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<0>)));
m_view0[VIEW_RAM].install_readwrite_bank(0x4000, 0x5fff, m_rambank[0]);
m_view0[VIEW_INVALID].install_write_handler(0x5000, 0x57ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<0>)));
m_view0[VIEW_INVALID | VIEW_RAM];
page(1)->install_view(0x6000, 0x7fff, m_view1);
m_view1[VIEW_READ].install_read_bank(0x6000, 0x7fff, m_rambank[1]);
m_view1[VIEW_READ].install_write_handler(0x7000, 0x77ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<1>)));
m_view1[VIEW_RAM].install_readwrite_bank(0x6000, 0x7fff, m_rambank[1]);
m_view1[VIEW_INVALID].install_write_handler(0x7000, 0x77ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<1>)));
m_view1[VIEW_INVALID | VIEW_RAM];
page(2)->install_view(0x8000, 0x9fff, m_view2);
m_view2[VIEW_READ].install_read_bank(0x8000, 0x9fff, m_rambank[2]);
m_view2[VIEW_READ].install_write_handler(0x9000, 0x97ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<2>)));
m_view2[VIEW_RAM].install_readwrite_bank(0x8000, 0x9fff, m_rambank[2]);
m_view2[VIEW_INVALID].install_write_handler(0x9000, 0x97ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<2>)));
m_view2[VIEW_INVALID | VIEW_RAM];
m_view2[VIEW_SCC | VIEW_READ].install_read_bank(0x8000, 0x9fff, m_rambank[2]);
m_view2[VIEW_SCC | VIEW_READ].install_write_handler(0x9000, 0x97ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<2>)));
m_view2[VIEW_SCC | VIEW_READ].install_read_handler(0x9800, 0x987f, 0, 0x0700, 0, read8sm_delegate(m_k052539, FUNC(k051649_device::k051649_waveform_r)));
m_view2[VIEW_SCC | VIEW_READ].install_write_handler(0x9800, 0x987f, 0, 0x0700, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_waveform_w)));
m_view2[VIEW_SCC | VIEW_READ].install_write_handler(0x9880, 0x9889, 0, 0x0710, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_frequency_w)));
m_view2[VIEW_SCC | VIEW_READ].install_write_handler(0x988a, 0x988e, 0, 0x0710, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_volume_w)));
m_view2[VIEW_SCC | VIEW_READ].install_write_handler(0x988f, 0x988f, 0, 0x0710, 0, write8smo_delegate(m_k052539, FUNC(k051649_device::k051649_keyonoff_w)));
m_view2[VIEW_SCC | VIEW_READ].install_read_handler(0x98c0, 0x98c0, 0, 0x071f, 0, read8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_r)));
m_view2[VIEW_SCC | VIEW_READ].install_write_handler(0x98c0, 0x98c0, 0, 0x071f, 0, write8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_w)));
m_view2[VIEW_SCC | VIEW_RAM].install_readwrite_bank(0x8000, 0x9fff, m_rambank[2]);
m_view2[VIEW_SCC | VIEW_RAM].install_read_handler(0x9800, 0x987f, 0, 0x0700, 0, read8sm_delegate(m_k052539, FUNC(k051649_device::k051649_waveform_r)));
m_view2[VIEW_SCC | VIEW_RAM].install_read_handler(0x98c0, 0x98c0, 0, 0x071f, 0, read8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_r)));
m_view2[VIEW_SCC | VIEW_INVALID].install_write_handler(0x9000, 0x97ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<2>)));
m_view2[VIEW_SCC | VIEW_INVALID].install_read_handler(0x9800, 0x987f, 0, 0x0700, 0, read8sm_delegate(m_k052539, FUNC(k051649_device::k051649_waveform_r)));
m_view2[VIEW_SCC | VIEW_INVALID].install_write_handler(0x9800, 0x987f, 0, 0x0700, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_waveform_w)));
m_view2[VIEW_SCC | VIEW_INVALID].install_write_handler(0x9880, 0x9889, 0, 0x0710, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_frequency_w)));
m_view2[VIEW_SCC | VIEW_INVALID].install_write_handler(0x988a, 0x988e, 0, 0x0710, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_volume_w)));
m_view2[VIEW_SCC | VIEW_INVALID].install_write_handler(0x988f, 0x988f, 0, 0x0710, 0, write8smo_delegate(m_k052539, FUNC(k051649_device::k051649_keyonoff_w)));
m_view2[VIEW_SCC | VIEW_INVALID].install_read_handler(0x98c0, 0x98c0, 0, 0x071f, 0, read8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_r)));
m_view2[VIEW_SCC | VIEW_INVALID].install_write_handler(0x98c0, 0x98c0, 0, 0x071f, 0, write8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_w)));
m_view2[VIEW_SCC | VIEW_INVALID | VIEW_RAM];
m_view2[VIEW_SCC | VIEW_INVALID | VIEW_RAM].install_read_handler(0x9800, 0x987f, 0, 0x0700, 0, read8sm_delegate(m_k052539, FUNC(k051649_device::k051649_waveform_r)));
m_view2[VIEW_SCC | VIEW_INVALID | VIEW_RAM].install_read_handler(0x98c0, 0x98c0, 0, 0x071f, 0, read8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_r)));
page(2)->install_view(0xa000, 0xbfff, m_view3);
m_view3[VIEW_READ].install_read_bank(0xa000, 0xbfff, m_rambank[3]);
m_view3[VIEW_READ].install_write_handler(0xb000, 0xb7ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<3>)));
m_view3[VIEW_RAM].install_readwrite_bank(0xa000, 0xbfff, m_rambank[3]);
m_view3[VIEW_INVALID].install_write_handler(0xb000, 0xb7ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<3>)));
m_view3[VIEW_INVALID | VIEW_RAM];
m_view3[VIEW_SCC | VIEW_READ].install_read_bank(0xa000, 0xbfff, m_rambank[3]);
m_view3[VIEW_SCC | VIEW_READ].install_write_handler(0xb000, 0xb7ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<3>)));
m_view3[VIEW_SCC | VIEW_READ].install_read_handler(0xb800, 0xb89f, 0, 0x0700, 0, read8sm_delegate(m_k052539, FUNC(k051649_device::k052539_waveform_r)));
m_view3[VIEW_SCC | VIEW_READ].install_write_handler(0xb800, 0xb89f, 0, 0x0700, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k052539_waveform_w)));
m_view3[VIEW_SCC | VIEW_READ].install_write_handler(0xb8a0, 0xb8a9, 0, 0x0710, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_frequency_w)));
m_view3[VIEW_SCC | VIEW_READ].install_write_handler(0xb8aa, 0xb8ae, 0, 0x0710, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_volume_w)));
m_view3[VIEW_SCC | VIEW_READ].install_write_handler(0xb8af, 0xb8af, 0, 0x0710, 0, write8smo_delegate(m_k052539, FUNC(k051649_device::k051649_keyonoff_w)));
m_view3[VIEW_SCC | VIEW_READ].install_read_handler(0xb8c0, 0xb8c0, 0, 0x071f, 0, read8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_r)));
m_view3[VIEW_SCC | VIEW_READ].install_write_handler(0xb8c0, 0xb8c0, 0, 0x071f, 0, write8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_w)));
m_view3[VIEW_SCC | VIEW_RAM].install_readwrite_bank(0xa000, 0xbfff, m_rambank[3]);
m_view3[VIEW_SCC | VIEW_RAM].install_read_handler(0xb800, 0xb89f, 0, 0x0700, 0, read8sm_delegate(m_k052539, FUNC(k051649_device::k052539_waveform_r)));
m_view3[VIEW_SCC | VIEW_RAM].install_read_handler(0xb8c0, 0xb8c0, 0, 0x071f, 0, read8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_r)));
m_view3[VIEW_SCC | VIEW_INVALID].install_write_handler(0xb000, 0xb7ff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::bank_w<3>)));
m_view3[VIEW_SCC | VIEW_INVALID].install_read_handler(0xb800, 0xb89f, 0, 0x0700, 0, read8sm_delegate(m_k052539, FUNC(k051649_device::k052539_waveform_r)));
m_view3[VIEW_SCC | VIEW_INVALID].install_write_handler(0xb800, 0xb89f, 0, 0x0700, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k052539_waveform_w)));
m_view3[VIEW_SCC | VIEW_INVALID].install_write_handler(0xb8a0, 0xb8a9, 0, 0x0710, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_frequency_w)));
m_view3[VIEW_SCC | VIEW_INVALID].install_write_handler(0xb8aa, 0xb8ae, 0, 0x0710, 0, write8sm_delegate(m_k052539, FUNC(k051649_device::k051649_volume_w)));
m_view3[VIEW_SCC | VIEW_INVALID].install_write_handler(0xb8af, 0xb8af, 0, 0x0710, 0, write8smo_delegate(m_k052539, FUNC(k051649_device::k051649_keyonoff_w)));
m_view3[VIEW_SCC | VIEW_INVALID].install_read_handler(0xb8c0, 0xb8c0, 0, 0x071f, 0, read8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_r)));
m_view3[VIEW_SCC | VIEW_INVALID].install_write_handler(0xb8c0, 0xb8c0, 0, 0x071f, 0, write8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_w)));
m_view3[VIEW_SCC | VIEW_INVALID | VIEW_RAM];
m_view3[VIEW_SCC | VIEW_INVALID| VIEW_RAM].install_read_handler(0xb800, 0xb89f, 0, 0x0700, 0, read8sm_delegate(m_k052539, FUNC(k051649_device::k052539_waveform_r)));
m_view3[VIEW_SCC | VIEW_INVALID| VIEW_RAM].install_read_handler(0xb8c0, 0xb8c0, 0, 0x071f, 0, read8smo_delegate(m_k052539, FUNC(k051649_device::k051649_test_r)));
page(2)->install_write_handler(0xbffe, 0xbfff, write8smo_delegate(*this, FUNC(msx_cart_konami_sound_device::control_w)));
return image_init_result::PASS;
}
void msx_cart_konami_sound_device::control_w(u8 data)
{
m_control = data;
switch_bank<0>();
switch_bank<1>();
switch_bank<2>();
switch_bank<3>();
}
template <int Bank>
void msx_cart_konami_sound_device::switch_bank()
{
u8 view = VIEW_READ;
if ((m_selected_bank[Bank] & 0x0f) >= m_min_rambank && (m_selected_bank[Bank] & 0x0f) <= m_max_rambank)
m_rambank[Bank]->set_entry(m_selected_bank[Bank] & 0x07);
else
view |= VIEW_INVALID;
if (BIT(m_control, 4))
view |= VIEW_RAM;
else
{
if (Bank < 2 && BIT(m_control, Bank))
view |= VIEW_RAM;
else if (Bank == 2 && BIT(m_control, Bank) && BIT(m_control, 5))
view |= VIEW_RAM;
}
if (Bank == 2 && !BIT(m_control, 5) && (m_selected_bank[2] & 0x3f) == 0x3f)
view |= VIEW_SCC;
if (Bank == 3 && BIT(m_control, 5) && BIT(m_selected_bank[3], 7))
view |= VIEW_SCC;
if (Bank == 0)
m_view0.select(view);
if (Bank == 1)
m_view1.select(view);
if (Bank == 2)
m_view2.select(view);
if (Bank == 3)
m_view3.select(view);
}
template <int Bank>
void msx_cart_konami_sound_device::bank_w(u8 data)
{
m_selected_bank[Bank] = data;
switch_bank<Bank>();
}
// The Snatcher Sound cartridge has 64KB RAM available by selecting ram banks 0-7
msx_cart_konami_sound_snatcher_device::msx_cart_konami_sound_snatcher_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: msx_cart_konami_sound_device(mconfig, MSX_CART_SOUND_SNATCHER, tag, owner, clock, 0, 7)
{
}
image_init_result msx_cart_konami_sound_snatcher_device::initialize_cartridge(std::string &message)
{
if (!cart_ram_region())
{
message = "msx_cart_konami_sound_snatcher_device: Required region 'ram' was not found.";
return image_init_result::FAIL;
}
if (cart_ram_region()->bytes() != 0x10000)
{
message = "msx_cart_konami_sound_snatcher_device: Region 'ram' has unsupported size.";
return image_init_result::FAIL;
}
return msx_cart_konami_sound_device::initialize_cartridge(message);
}
// The SD Snatcher Sound cartrdige has 64KB RAM available by selecting ram banks 8-15
msx_cart_konami_sound_sdsnatcher_device::msx_cart_konami_sound_sdsnatcher_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: msx_cart_konami_sound_device(mconfig, MSX_CART_SOUND_SDSNATCHER, tag, owner, clock, 8, 15)
{
}
image_init_result msx_cart_konami_sound_sdsnatcher_device::initialize_cartridge(std::string &message)
{
if (!cart_ram_region())
{
message = "msx_cart_konami_sound_sdsnatcher_device: Required region 'ram' was not found.";
return image_init_result::FAIL;
}
if (cart_ram_region()->bytes() != 0x10000)
{
message = "msx_cart_konami_sound_sdsnatcher_device: Region 'ram' has unsupported size.";
return image_init_result::FAIL;
}
return msx_cart_konami_sound_device::initialize_cartridge(message);
}
msx_cart_keyboard_master_device::msx_cart_keyboard_master_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, MSX_CART_KEYBOARD_MASTER, tag, owner, clock)
, msx_cart_interface(mconfig, *this)
, m_vlm5030(*this, "vlm5030")
{
}
void msx_cart_keyboard_master_device::vlm_map(address_map &map)
{
map(0x0000, 0xffff).r(FUNC(msx_cart_keyboard_master_device::read_vlm));
}
void msx_cart_keyboard_master_device::device_add_mconfig(machine_config &config)
{
// This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'.
SPEAKER(config, "mono").front_center();
VLM5030(config, m_vlm5030, XTAL(3'579'545));
m_vlm5030->add_route(ALL_OUTPUTS, "mono", 0.40);
m_vlm5030->set_addrmap(0, &msx_cart_keyboard_master_device::vlm_map);
}
void msx_cart_keyboard_master_device::device_start()
{
// Install IO read/write handlers
io_space().install_write_handler(0x00, 0x00, write8smo_delegate(*m_vlm5030, FUNC(vlm5030_device::data_w)));
io_space().install_write_handler(0x20, 0x20, write8smo_delegate(*this, FUNC(msx_cart_keyboard_master_device::io_20_w)));
io_space().install_read_handler(0x00, 0x00, read8smo_delegate(*this, FUNC(msx_cart_keyboard_master_device::io_00_r)));
}
image_init_result msx_cart_keyboard_master_device::initialize_cartridge(std::string &message)
{
if (!cart_rom_region())
{
message = "msx_cart_keyboard_master_device: Required region 'rom' was not found.";
return image_init_result::FAIL;
}
if (!cart_vlm5030_region())
{
message = "msx_cart_keyboard_master_device: Required region 'vlm5030' was not found.";
return image_init_result::FAIL;
}
if (cart_rom_region()->bytes() != 0x4000)
{
message = "msx_cart_keyboard_master_device: Region 'rom' has unsupported size.";
return image_init_result::FAIL;
}
page(1)->install_rom(0x4000, 0x7fff, cart_rom_region()->base());
return image_init_result::PASS;
}
uint8_t msx_cart_keyboard_master_device::read_vlm(offs_t offset)
{
if (offset < cart_vlm5030_region()->bytes())
return cart_vlm5030_region()->base()[offset];
else
return 0xff;
}
void msx_cart_keyboard_master_device::io_20_w(uint8_t data)
{
m_vlm5030->rst(BIT(data, 0) ? 1 : 0);
m_vlm5030->vcu(BIT(data, 2) ? 1 : 0);
m_vlm5030->st(BIT(data, 1) ? 1 : 0);
}
uint8_t msx_cart_keyboard_master_device::io_00_r()
{
return m_vlm5030->bsy() ? 0x10 : 0x00;
}
msx_cart_ec701_device::msx_cart_ec701_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, MSX_CART_EC701, tag, owner, clock)
, msx_cart_interface(mconfig, *this)
, m_rombank(*this, "rombank")
, m_view(*this, "view")
{
}
void msx_cart_ec701_device::device_reset()
{
m_view.select(0);
}
image_init_result msx_cart_ec701_device::initialize_cartridge(std::string &message)
{
if (!cart_rom_region())
{
message = "msx_cart_ec701_device: Required region 'rom' was not found.";
return image_init_result::FAIL;
}
m_rombank->configure_entries(0, 24, cart_rom_region()->base() + 0x20000, 0x4000);
page(1)->install_view(0x4000, 0x7fff, m_view);
m_view[0].install_rom(0x4000, 0x7fff, cart_rom_region()->base());
m_view[1].install_read_bank(0x4000, 0x7fff, m_rombank);
m_view[2].nop_read(0x4000, 0x7fff);
page(2)->install_rom(0x8000, 0xbfff, cart_rom_region()->base() + 0x4000);
page(2)->install_write_handler(0xbff8, 0xbfff, write8smo_delegate(*this, FUNC(msx_cart_ec701_device::bank_w)));
return image_init_result::PASS;
}
void msx_cart_ec701_device::bank_w(u8 data)
{
data = ~data;
switch (data & 0x38)
{
case 0x00: // ic1
m_view.select(0);
break;
case 0x20: // ic2
m_view.select(1);
m_rombank->set_entry(data & 0x07);
break;
case 0x28: // ic3
m_view.select(1);
m_rombank->set_entry(0x08 + (data & 0x07));
break;
case 0x30: // ic4
m_view.select(1);
m_rombank->set_entry(0x10 + (data & 0x07));
break;
default:
m_view.select(2);
break;
}
}