summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Wilbert Pol <wilbert@jdg.info>2014-05-14 19:04:52 +0000
committer Wilbert Pol <wilbert@jdg.info>2014-05-14 19:04:52 +0000
commitc74226bb26acd1afdcc59f20e174d126423f60b9 (patch)
tree67a584a596dc13b820cfdbe411eaf826852475ff /src/emu
parent8ab3ccb194ff9cb37bda434489a82da854b24af6 (diff)
(MESS) msx.c: [Wilbert Pol]
- Reimplemented the cartridge slots as slot devices. - Moved the msx slot layouts to inline machine configuration. - Started adding support for a few more firmware types. - Add turbo support to Panasonic FS-A1FX/FS-A1WX/FS-A1WSX.
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/bus/bus.mak32
-rw-r--r--src/emu/bus/msx_cart/ascii.c442
-rw-r--r--src/emu/bus/msx_cart/ascii.h116
-rw-r--r--src/emu/bus/msx_cart/cartridge.c59
-rw-r--r--src/emu/bus/msx_cart/cartridge.h42
-rw-r--r--src/emu/bus/msx_cart/crossblaim.c81
-rw-r--r--src/emu/bus/msx_cart/crossblaim.h35
-rw-r--r--src/emu/bus/msx_cart/fmpac.c172
-rw-r--r--src/emu/bus/msx_cart/fmpac.h44
-rw-r--r--src/emu/bus/msx_cart/konami.c862
-rw-r--r--src/emu/bus/msx_cart/konami.h169
-rw-r--r--src/emu/bus/msx_cart/korean.c297
-rw-r--r--src/emu/bus/msx_cart/korean.h89
-rw-r--r--src/emu/bus/msx_cart/majutsushi.c114
-rw-r--r--src/emu/bus/msx_cart/majutsushi.h37
-rw-r--r--src/emu/bus/msx_cart/msxdos2.c66
-rw-r--r--src/emu/bus/msx_cart/msxdos2.h33
-rw-r--r--src/emu/bus/msx_cart/nomapper.c49
-rw-r--r--src/emu/bus/msx_cart/nomapper.h28
-rw-r--r--src/emu/bus/msx_cart/rtype.c77
-rw-r--r--src/emu/bus/msx_cart/rtype.h33
-rw-r--r--src/emu/bus/msx_cart/superloderunner.c61
-rw-r--r--src/emu/bus/msx_cart/superloderunner.h33
-rw-r--r--src/emu/bus/msx_slot/bunsetsu.c77
-rw-r--r--src/emu/bus/msx_slot/bunsetsu.h38
-rw-r--r--src/emu/bus/msx_slot/cartridge.c317
-rw-r--r--src/emu/bus/msx_slot/cartridge.h57
-rw-r--r--src/emu/bus/msx_slot/disk.c369
-rw-r--r--src/emu/bus/msx_slot/disk.h97
-rw-r--r--src/emu/bus/msx_slot/fs4600.c162
-rw-r--r--src/emu/bus/msx_slot/fs4600.h45
-rw-r--r--src/emu/bus/msx_slot/music.c69
-rw-r--r--src/emu/bus/msx_slot/music.h43
-rw-r--r--src/emu/bus/msx_slot/panasonic08.c176
-rw-r--r--src/emu/bus/msx_slot/panasonic08.h44
-rw-r--r--src/emu/bus/msx_slot/ram.c36
-rw-r--r--src/emu/bus/msx_slot/ram.h26
-rw-r--r--src/emu/bus/msx_slot/ram_mm.c79
-rw-r--r--src/emu/bus/msx_slot/ram_mm.h44
-rw-r--r--src/emu/bus/msx_slot/rom.c66
-rw-r--r--src/emu/bus/msx_slot/rom.h32
-rw-r--r--src/emu/bus/msx_slot/slot.c35
-rw-r--r--src/emu/bus/msx_slot/slot.h37
43 files changed, 4820 insertions, 0 deletions
diff --git a/src/emu/bus/bus.mak b/src/emu/bus/bus.mak
index 9067f5bca1d..d0436681130 100644
--- a/src/emu/bus/bus.mak
+++ b/src/emu/bus/bus.mak
@@ -389,6 +389,38 @@ endif
#-------------------------------------------------
#
+#@src/emu/bus/msx_slot/slot.h,BUSES += MSX_SLOT
+#-------------------------------------------------
+
+ifneq ($(filter MSX_SLOT,$(BUSES)),)
+OBJDIRS += $(BUSOBJ)/msx_slot
+BUSOBJS += $(BUSOBJ)/msx_slot/bunsetsu.o
+BUSOBJS += $(BUSOBJ)/msx_slot/cartridge.o
+BUSOBJS += $(BUSOBJ)/msx_slot/disk.o
+BUSOBJS += $(BUSOBJ)/msx_slot/fs4600.o
+BUSOBJS += $(BUSOBJ)/msx_slot/music.o
+BUSOBJS += $(BUSOBJ)/msx_slot/panasonic08.o
+BUSOBJS += $(BUSOBJ)/msx_slot/rom.o
+BUSOBJS += $(BUSOBJ)/msx_slot/ram.o
+BUSOBJS += $(BUSOBJ)/msx_slot/ram_mm.o
+BUSOBJS += $(BUSOBJ)/msx_slot/slot.o
+OBJDIRS += $(BUSOBJ)/msx_cart
+BUSOBJS += $(BUSOBJ)/msx_cart/ascii.o
+BUSOBJS += $(BUSOBJ)/msx_cart/cartridge.o
+BUSOBJS += $(BUSOBJ)/msx_cart/crossblaim.o
+BUSOBJS += $(BUSOBJ)/msx_cart/fmpac.o
+BUSOBJS += $(BUSOBJ)/msx_cart/konami.o
+BUSOBJS += $(BUSOBJ)/msx_cart/korean.o
+BUSOBJS += $(BUSOBJ)/msx_cart/majutsushi.o
+BUSOBJS += $(BUSOBJ)/msx_cart/msxdos2.o
+BUSOBJS += $(BUSOBJ)/msx_cart/nomapper.o
+BUSOBJS += $(BUSOBJ)/msx_cart/rtype.o
+BUSOBJS += $(BUSOBJ)/msx_cart/superloderunner.o
+endif
+
+
+#-------------------------------------------------
+#
#@src/emu/bus/kc/kc.h,BUSES += KC
#-------------------------------------------------
diff --git a/src/emu/bus/msx_cart/ascii.c b/src/emu/bus/msx_cart/ascii.c
new file mode 100644
index 00000000000..fa8d7a51d12
--- /dev/null
+++ b/src/emu/bus/msx_cart/ascii.c
@@ -0,0 +1,442 @@
+#include "emu.h"
+#include "ascii.h"
+
+
+const device_type MSX_CART_ASCII8 = &device_creator<msx_cart_ascii8>;
+const device_type MSX_CART_ASCII16 = &device_creator<msx_cart_ascii16>;
+const device_type MSX_CART_ASCII8_SRAM = &device_creator<msx_cart_ascii8_sram>;
+const device_type MSX_CART_ASCII16_SRAM = &device_creator<msx_cart_ascii16_sram>;
+
+
+msx_cart_ascii8::msx_cart_ascii8(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_ASCII8, "MSX Cartridge - ASCII8", tag, owner, clock, "msx_cart_ascii8", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_mask(0)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = 0;
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_ascii8::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_ascii8::restore_banks), this));
+}
+
+
+void msx_cart_ascii8::restore_banks()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_bank_base[i] = get_rom_base() + (m_selected_bank[i] & m_bank_mask ) * 0x2000;
+ }
+}
+
+
+void msx_cart_ascii8::device_reset()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+}
+
+
+void msx_cart_ascii8::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( size > 256 * 0x2000 )
+ {
+ fatalerror("ascii8: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x2000;
+
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ fatalerror("ascii8: Invalid ROM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_ascii8::read_cart)
+{
+ if ( offset >= 0x4000 && offset < 0xC000 )
+ {
+ return m_bank_base[(offset - 0x4000) >> 13][offset & 0x1fff];
+ }
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_ascii8::write_cart)
+{
+ if (offset >= 0x6000 && offset < 0x8000)
+ {
+ UINT8 bank = (offset / 0x800) & 0x03;
+
+ m_selected_bank[bank] = data;
+ m_bank_base[bank] = get_rom_base() + (m_selected_bank[bank] & m_bank_mask ) * 0x2000;
+ }
+}
+
+
+
+msx_cart_ascii16::msx_cart_ascii16(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_ASCII16, "MSX Cartridge - ASCII16", tag, owner, clock, "msx_cart_ascii16", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_mask(0)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_selected_bank[i] = 0;
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_ascii16::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_ascii16::restore_banks), this));
+}
+
+
+void msx_cart_ascii16::restore_banks()
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_bank_base[i] = get_rom_base() + (m_selected_bank[i] & m_bank_mask) * 0x4000;
+ }
+}
+
+
+void msx_cart_ascii16::device_reset()
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+}
+
+
+void msx_cart_ascii16::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( size > 256 * 0x4000 )
+ {
+ fatalerror("ascii16: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x4000;
+
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ fatalerror("ascii16: Invalid ROM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_ascii16::read_cart)
+{
+ if ( offset >= 0x4000 && offset < 0xC000 )
+ {
+ return m_bank_base[offset >> 15][offset & 0x3fff];
+ }
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_ascii16::write_cart)
+{
+ if (offset >= 0x6000 && offset < 0x6800)
+ {
+ m_selected_bank[0] = data;
+ m_bank_base[0] = get_rom_base() + (m_selected_bank[0] & m_bank_mask) * 0x4000;
+ }
+
+ if (offset >= 0x7000 && offset < 0x7800)
+ {
+ m_selected_bank[1] = data;
+ m_bank_base[1] = get_rom_base() + (m_selected_bank[1] & m_bank_mask) * 0x4000;
+ }
+}
+
+
+
+
+
+msx_cart_ascii8_sram::msx_cart_ascii8_sram(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_ASCII8_SRAM, "MSX Cartridge - ASCII8 w/SRAM", tag, owner, clock, "msx_cart_ascii8_sram", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_mask(0)
+ , m_sram_select_mask(0)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = 0;
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_ascii8_sram::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_ascii8_sram::restore_banks), this));
+}
+
+
+void msx_cart_ascii8_sram::setup_bank(UINT8 bank)
+{
+ if (m_selected_bank[bank] & ~(m_sram_select_mask | m_bank_mask))
+ {
+ // Nothing is mapped
+ m_bank_base[bank] = NULL;
+ }
+ else if (m_selected_bank[bank] & m_sram_select_mask)
+ {
+ // SRAM is selected
+ m_bank_base[bank] = get_sram_base();
+ }
+ else
+ {
+ m_bank_base[bank] = get_rom_base() + (m_selected_bank[bank] & m_bank_mask ) * 0x2000;
+ }
+}
+
+
+void msx_cart_ascii8_sram::restore_banks()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ setup_bank(i);
+ }
+}
+
+
+void msx_cart_ascii8_sram::device_reset()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+}
+
+
+void msx_cart_ascii8_sram::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( size > 128 * 0x2000 )
+ {
+ fatalerror("ascii8_sram: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x2000;
+
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ fatalerror("ascii8_sram: Invalid ROM size\n");
+ }
+
+ if (get_sram_size() != 0x2000)
+ {
+ fatalerror("ascii8_sram: Unsupported SRAM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+ m_sram_select_mask = banks;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_ascii8_sram::read_cart)
+{
+ if ( offset >= 0x4000 && offset < 0xC000 )
+ {
+ UINT8 *bank_base = m_bank_base[(offset - 0x4000) >> 13];
+
+ if (bank_base != NULL)
+ {
+ return bank_base[offset & 0x1fff];
+ }
+ }
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_ascii8_sram::write_cart)
+{
+ if (offset >= 0x6000 && offset < 0x8000)
+ {
+ UINT8 bank = (offset / 0x800) & 0x03;
+
+ m_selected_bank[bank] = data;
+ setup_bank(bank);
+ }
+ else if (offset >= 0x8000 && offset < 0xc000)
+ {
+ UINT8 bank = (offset & 0x2000) ? 3 : 2;
+
+ if ((m_selected_bank[bank] & m_sram_select_mask) && !(m_selected_bank[bank] & ~(m_sram_select_mask | m_bank_mask)))
+ {
+ // Write to SRAM
+ m_bank_base[bank][offset & 0x1fff] = data;
+ }
+ }
+}
+
+
+
+msx_cart_ascii16_sram::msx_cart_ascii16_sram(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_ASCII16_SRAM, "MSX Cartridge - ASCII16 w/SRAM", tag, owner, clock, "msx_cart_ascii16_sram", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_mask(0)
+ , m_sram_select_mask(0)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_selected_bank[i] = 0;
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_ascii16_sram::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_ascii16_sram::restore_banks), this));
+}
+
+
+void msx_cart_ascii16_sram::setup_bank(UINT8 bank)
+{
+ if (m_selected_bank[bank] & ~(m_sram_select_mask | m_bank_mask))
+ {
+ // Nothing is mapped
+ m_bank_base[bank] = NULL;
+ }
+ else if (m_selected_bank[bank] & m_sram_select_mask)
+ {
+ // SRAM is selected
+ m_bank_base[bank] = get_sram_base();
+ }
+ else
+ {
+ m_bank_base[bank] = get_rom_base() + (m_selected_bank[bank] & m_bank_mask) * 0x4000;
+ }
+}
+
+
+void msx_cart_ascii16_sram::restore_banks()
+{
+ for (int i = 0; i < 2; i++)
+ {
+ setup_bank(i);
+ }
+}
+
+
+void msx_cart_ascii16_sram::device_reset()
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+}
+
+
+void msx_cart_ascii16_sram::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( size > 128 * 0x4000 )
+ {
+ fatalerror("ascii16_sram: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x4000;
+
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ fatalerror("ascii16_sram: Invalid ROM size\n");
+ }
+
+ if (get_sram_size() != 0x800)
+ {
+ fatalerror("ascii16_sram: Unsupported SRAM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+ m_sram_select_mask = banks;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_ascii16_sram::read_cart)
+{
+ if ( offset >= 0x4000 && offset < 0xC000 )
+ {
+ UINT8 bank = offset >> 15;
+
+ if (m_bank_base[bank] != NULL)
+ {
+ if (m_selected_bank[bank] & m_sram_select_mask)
+ {
+ return m_bank_base[bank][offset & 0x7ff];
+ }
+ else
+ {
+ return m_bank_base[bank][offset & 0x3fff];
+ }
+ }
+ }
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_ascii16_sram::write_cart)
+{
+ if (offset >= 0x6000 && offset < 0x6800)
+ {
+ m_selected_bank[0] = data;
+ setup_bank(0);
+ }
+
+ if (offset >= 0x7000 && offset < 0x7800)
+ {
+ m_selected_bank[1] = data;
+ setup_bank(1);
+ }
+
+ if (offset >= 0x8000 && offset < 0xc000)
+ {
+ if ((m_selected_bank[1] & m_sram_select_mask) && !(m_selected_bank[1] & ~(m_sram_select_mask | m_bank_mask)))
+ {
+ // Write to SRAM
+ m_bank_base[1][offset & 0x7ff] = data;
+ }
+ }
+}
+
diff --git a/src/emu/bus/msx_cart/ascii.h b/src/emu/bus/msx_cart/ascii.h
new file mode 100644
index 00000000000..24ad955e32f
--- /dev/null
+++ b/src/emu/bus/msx_cart/ascii.h
@@ -0,0 +1,116 @@
+#ifndef __MSX_CART_ASCII_H
+#define __MSX_CART_ASCII_H
+
+#include "bus/msx_cart/cartridge.h"
+
+
+extern const device_type MSX_CART_ASCII8;
+extern const device_type MSX_CART_ASCII16;
+extern const device_type MSX_CART_ASCII8_SRAM;
+extern const device_type MSX_CART_ASCII16_SRAM;
+
+
+class msx_cart_ascii8 : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_ascii8(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank[4];
+ UINT8 *m_bank_base[4];
+};
+
+
+class msx_cart_ascii16 : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_ascii16(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank[2];
+ UINT8 *m_bank_base[2];
+};
+
+
+class msx_cart_ascii8_sram : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_ascii8_sram(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank[4];
+ UINT8 *m_bank_base[4];
+ UINT8 m_sram_select_mask;
+
+ void setup_bank(UINT8 bank);
+};
+
+
+class msx_cart_ascii16_sram : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_ascii16_sram(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank[2];
+ UINT8 *m_bank_base[2];
+ UINT8 m_sram_select_mask;
+
+ void setup_bank(UINT8 bank);
+};
+
+
+#endif
+
diff --git a/src/emu/bus/msx_cart/cartridge.c b/src/emu/bus/msx_cart/cartridge.c
new file mode 100644
index 00000000000..6c724982526
--- /dev/null
+++ b/src/emu/bus/msx_cart/cartridge.c
@@ -0,0 +1,59 @@
+
+#include "emu.h"
+#include "cartridge.h"
+#include "ascii.h"
+#include "crossblaim.h"
+#include "fmpac.h"
+#include "konami.h"
+#include "korean.h"
+#include "majutsushi.h"
+#include "msxdos2.h"
+#include "nomapper.h"
+#include "rtype.h"
+#include "superloderunner.h"
+
+
+SLOT_INTERFACE_START(msx_cart)
+ SLOT_INTERFACE_INTERNAL("nomapper", MSX_CART_NOMAPPER)
+ SLOT_INTERFACE_INTERNAL("msxdos2", MSX_CART_MSXDOS2)
+ SLOT_INTERFACE_INTERNAL("konami_scc", MSX_CART_KONAMI_SCC)
+ SLOT_INTERFACE_INTERNAL("konami", MSX_CART_KONAMI)
+ SLOT_INTERFACE_INTERNAL("ascii8", MSX_CART_ASCII8)
+ SLOT_INTERFACE_INTERNAL("ascii16", MSX_CART_ASCII16)
+ SLOT_INTERFACE_INTERNAL("gamemaster2", MSX_CART_GAMEMASTER2)
+ SLOT_INTERFACE_INTERNAL("ascii8_sram", MSX_CART_ASCII8_SRAM)
+ SLOT_INTERFACE_INTERNAL("ascii16_sram", MSX_CART_ASCII16_SRAM)
+ SLOT_INTERFACE_INTERNAL("rtype", MSX_CART_RTYPE)
+ SLOT_INTERFACE_INTERNAL("majutsushi", MSX_CART_MAJUTSUSHI)
+ SLOT_INTERFACE_INTERNAL("fmpac", MSX_CART_FMPAC)
+ SLOT_INTERFACE_INTERNAL("superloderunner", MSX_CART_SUPERLODERUNNER)
+ SLOT_INTERFACE_INTERNAL("synthesizer", MSX_CART_SYNTHESIZER)
+ SLOT_INTERFACE_INTERNAL("cross_blaim", MSX_CART_CROSSBLAIM)
+// SLOT_INTERFACE_INTERNAL("disk_rom", MSX_CART_DISK_ROM)
+ SLOT_INTERFACE_INTERNAL("korean_80in1", MSX_CART_KOREAN_80IN1)
+ SLOT_INTERFACE_INTERNAL("korean_90in1", MSX_CART_KOREAN_90IN1)
+ SLOT_INTERFACE_INTERNAL("korean_126in1", MSX_CART_KOREAN_126IN1)
+ SLOT_INTERFACE_INTERNAL("sound_snatcher", MSX_CART_SOUND_SNATCHER)
+ SLOT_INTERFACE_INTERNAL("sound_sdsnatch", MSX_CART_SOUND_SDSNATCHER)
+SLOT_INTERFACE_END
+
+
+msx_cart_interface::msx_cart_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device)
+{
+}
+
+void msx_cart_interface::rom_alloc(UINT32 size)
+{
+ m_rom.resize(size);
+}
+
+void msx_cart_interface::ram_alloc(UINT32 size)
+{
+ m_ram.resize(size);
+}
+
+void msx_cart_interface::sram_alloc(UINT32 size)
+{
+ m_sram.resize(size);
+}
diff --git a/src/emu/bus/msx_cart/cartridge.h b/src/emu/bus/msx_cart/cartridge.h
new file mode 100644
index 00000000000..bcd51c263a7
--- /dev/null
+++ b/src/emu/bus/msx_cart/cartridge.h
@@ -0,0 +1,42 @@
+#ifndef __MSX_CART_CARTRIDGE_H
+#define __MSX_CART_CARTRIDGE_H
+
+
+SLOT_INTERFACE_EXTERN(msx_cart);
+
+
+class msx_cart_interface : public device_slot_card_interface
+{
+public:
+ msx_cart_interface(const machine_config &mconfig, device_t &device);
+
+ // This is called after loading cartridge contents and allows the cartridge
+ // implementation to perform some additional initialization based on the
+ // cartridge contents.
+ virtual void initialize_cartridge() {}
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_cart) { return 0xff; }
+ virtual DECLARE_WRITE8_MEMBER(write_cart) {}
+
+ // ROM/RAM/SRAM management
+ // Mainly used by the cartridge slot when loading images
+ void rom_alloc(UINT32 size);
+ void ram_alloc(UINT32 size);
+ void sram_alloc(UINT32 size);
+
+ UINT8* get_rom_base() { return m_rom; }
+ UINT8* get_ram_base() { return m_ram; }
+ UINT8* get_sram_base() { return m_sram; }
+ UINT32 get_rom_size() { return m_rom.count(); }
+ UINT32 get_ram_size() { return m_ram.count(); }
+ UINT32 get_sram_size() { return m_sram.count(); }
+
+protected:
+ dynamic_buffer m_rom;
+ dynamic_buffer m_ram;
+ dynamic_buffer m_sram;
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_cart/crossblaim.c b/src/emu/bus/msx_cart/crossblaim.c
new file mode 100644
index 00000000000..304364a84db
--- /dev/null
+++ b/src/emu/bus/msx_cart/crossblaim.c
@@ -0,0 +1,81 @@
+#include "emu.h"
+#include "crossblaim.h"
+
+const device_type MSX_CART_CROSSBLAIM = &device_creator<msx_cart_crossblaim>;
+
+
+msx_cart_crossblaim::msx_cart_crossblaim(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_CROSSBLAIM, "MSX Cartridge - Cross Blaim", tag, owner, clock, "msx_cart_crossblaim", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_selected_bank(1)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_crossblaim::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_crossblaim::restore_banks), this));
+}
+
+
+void msx_cart_crossblaim::setup_bank()
+{
+ m_bank_base[0] = ( m_selected_bank & 2 ) ? NULL : get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000;
+ m_bank_base[2] = get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000;
+ m_bank_base[3] = ( m_selected_bank & 2 ) ? NULL : get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000;
+}
+
+
+void msx_cart_crossblaim::restore_banks()
+{
+ m_bank_base[1] = get_rom_base();
+ setup_bank();
+}
+
+
+void msx_cart_crossblaim::device_reset()
+{
+ m_selected_bank = 1;
+}
+
+
+void msx_cart_crossblaim::initialize_cartridge()
+{
+ if (get_rom_size() != 0x10000)
+ {
+ fatalerror("crossblaim: Invalid ROM size\n");
+ }
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_crossblaim::read_cart)
+{
+ UINT8 *bank_base = m_bank_base[offset >> 14];
+
+ if (bank_base != NULL)
+ {
+ return bank_base[offset & 0x3fff];
+ }
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_crossblaim::write_cart)
+{
+ m_selected_bank = data & 3;
+ if (m_selected_bank == 0)
+ {
+ m_selected_bank = 1;
+ }
+ setup_bank();
+}
+
diff --git a/src/emu/bus/msx_cart/crossblaim.h b/src/emu/bus/msx_cart/crossblaim.h
new file mode 100644
index 00000000000..36251bdb937
--- /dev/null
+++ b/src/emu/bus/msx_cart/crossblaim.h
@@ -0,0 +1,35 @@
+#ifndef __MSX_CART_CROSSBLAIM_H
+#define __MSX_CART_CROSSBLAIM_H
+
+#include "bus/msx_cart/cartridge.h"
+
+
+extern const device_type MSX_CART_CROSSBLAIM;
+
+
+class msx_cart_crossblaim : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_crossblaim(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_selected_bank;
+ UINT8 *m_bank_base[4];
+
+ void setup_bank();
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_cart/fmpac.c b/src/emu/bus/msx_cart/fmpac.c
new file mode 100644
index 00000000000..62703094b22
--- /dev/null
+++ b/src/emu/bus/msx_cart/fmpac.c
@@ -0,0 +1,172 @@
+/**********************************************************************************
+
+When backing up the SRAM from an FM-PAC the file seems to be prefixed
+with: PAC2 BACKUP DATA. We only store the raw sram contents.
+
+**********************************************************************************/
+
+#include "emu.h"
+#include "fmpac.h"
+
+const device_type MSX_CART_FMPAC = &device_creator<msx_cart_fmpac>;
+
+
+msx_cart_fmpac::msx_cart_fmpac(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_FMPAC, "MSX Cartridge - FM-PAC", tag, owner, clock, "msx_cart_fmpac", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_ym2413(*this, "ym2413")
+ , m_selected_bank(0)
+ , m_bank_base(NULL)
+ , m_sram_active(false)
+ , m_opll_active(false)
+ , m_1ffe(0)
+ , m_1fff(0)
+ , m_7ff6(0)
+{
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( fmpac )
+ // 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'.
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("ym2413", YM2413, XTAL_10_738635MHz/3)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40)
+MACHINE_CONFIG_END
+
+
+machine_config_constructor msx_cart_fmpac::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( fmpac );
+}
+
+
+void msx_cart_fmpac::device_start()
+{
+ save_item(NAME(m_selected_bank));
+ save_item(NAME(m_sram_active));
+ save_item(NAME(m_opll_active));
+ save_item(NAME(m_1ffe));
+ save_item(NAME(m_1fff));
+ save_item(NAME(m_7ff6));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_fmpac::restore_banks), this));
+
+ // Install IO read/write handlers
+ address_space &space = machine().device<cpu_device>("maincpu")->space(AS_IO);
+ space.install_write_handler(0x7c, 0x7d, write8_delegate(FUNC(msx_cart_fmpac::write_ym2413), this));
+}
+
+
+void msx_cart_fmpac::restore_banks()
+{
+ m_bank_base = get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000;
+}
+
+
+void msx_cart_fmpac::device_reset()
+{
+ m_selected_bank = 0;
+ m_sram_active = false;
+ m_opll_active = false;
+ m_1ffe = 0;
+ m_1fff = 0;
+ m_7ff6 = 0;
+}
+
+
+void msx_cart_fmpac::initialize_cartridge()
+{
+ if ( get_rom_size() != 0x10000 )
+ {
+ fatalerror("fmpac: Invalid ROM size\n");
+ }
+
+ if ( get_sram_size() != 0x2000 )
+ {
+ fatalerror("fmpac: Invalid SRAM size\n");
+ }
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_fmpac::read_cart)
+{
+ if (offset >= 0x4000 && offset < 0x8000)
+ {
+ if (offset == 0x7ff6)
+ {
+ return m_7ff6;
+ }
+ if (offset == 0x7ff7)
+ {
+ return m_selected_bank & 0x03;
+ }
+ if (m_sram_active)
+ {
+ if (offset & 0x2000)
+ {
+ return 0xff;
+ }
+ return get_sram_base()[offset & 0x1fff];
+ }
+ else
+ {
+ return m_bank_base[offset & 0x3fff];
+ }
+ }
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_fmpac::write_cart)
+{
+ if (offset >= 0x4000 && offset < 0x6000)
+ {
+ if (m_sram_active)
+ {
+ get_sram_base()[offset & 0x1fff] = data;
+ }
+ if (offset == 0x5ffe)
+ {
+ m_1ffe = data;
+ }
+ if (offset == 0x5fff)
+ {
+ m_1fff = data;
+ }
+ m_sram_active = (m_1ffe == 0x4d) && (m_1fff == 0x69);
+ }
+
+ switch (offset)
+ {
+ case 0x7ff4:
+ case 0x7ff5:
+ if (m_opll_active)
+ {
+ m_ym2413->write(space, offset & 1, data);
+ }
+ break;
+
+ case 0x7ff6:
+ m_7ff6 = data & 0x11;
+ m_opll_active = (m_7ff6 & 0x01);
+ break;
+
+ case 0x7ff7:
+ m_selected_bank = data;
+ restore_banks();
+ break;
+ }
+
+}
+
+
+WRITE8_MEMBER(msx_cart_fmpac::write_ym2413)
+{
+ if (m_opll_active)
+ {
+ m_ym2413->write(space, offset & 1, data);
+ }
+}
+
diff --git a/src/emu/bus/msx_cart/fmpac.h b/src/emu/bus/msx_cart/fmpac.h
new file mode 100644
index 00000000000..d6d44d091d8
--- /dev/null
+++ b/src/emu/bus/msx_cart/fmpac.h
@@ -0,0 +1,44 @@
+#ifndef __MSX_CART_FMPAC_H
+#define __MSX_CART_FMPAC_H
+
+#include "bus/msx_cart/cartridge.h"
+#include "sound/2413intf.h"
+
+
+extern const device_type MSX_CART_FMPAC;
+
+
+class msx_cart_fmpac : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_fmpac(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual void initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+ DECLARE_WRITE8_MEMBER(write_ym2413);
+
+private:
+ required_device<ym2413_device> m_ym2413;
+
+ UINT8 m_selected_bank;
+ UINT8 *m_bank_base;
+ bool m_sram_active;
+ bool m_opll_active;
+ UINT8 m_1ffe;
+ UINT8 m_1fff;
+ UINT8 m_7ff6;
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_cart/konami.c b/src/emu/bus/msx_cart/konami.c
new file mode 100644
index 00000000000..ee8115efd07
--- /dev/null
+++ b/src/emu/bus/msx_cart/konami.c
@@ -0,0 +1,862 @@
+#include "emu.h"
+#include "konami.h"
+
+const device_type MSX_CART_KONAMI = &device_creator<msx_cart_konami>;
+const device_type MSX_CART_KONAMI_SCC = &device_creator<msx_cart_konami_scc>;
+const device_type MSX_CART_GAMEMASTER2 = &device_creator<msx_cart_gamemaster2>;
+const device_type MSX_CART_SYNTHESIZER = &device_creator<msx_cart_synthesizer>;
+const device_type MSX_CART_SOUND_SNATCHER = &device_creator<msx_cart_konami_sound_snatcher>;
+const device_type MSX_CART_SOUND_SDSNATCHER = &device_creator<msx_cart_konami_sound_sdsnatcher>;
+
+
+msx_cart_konami::msx_cart_konami(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_KONAMI, "MSX Cartridge - KONAMI", tag, owner, clock, "msx_cart_konami", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_mask(0)
+{
+ for (int i = 0; i < 3; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_konami::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_konami::restore_banks), this));
+}
+
+
+void msx_cart_konami::restore_banks()
+{
+ m_bank_base[0] = get_rom_base();
+ m_bank_base[1] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000;
+ m_bank_base[2] = get_rom_base();
+ m_bank_base[3] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000;
+ m_bank_base[4] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000;
+ m_bank_base[5] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000;
+ m_bank_base[6] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000;
+ m_bank_base[7] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000;
+}
+
+
+void msx_cart_konami::device_reset()
+{
+ for (int i = 0; i < 3; i++)
+ {
+ m_selected_bank[i] = i + 1;
+ }
+}
+
+
+void msx_cart_konami::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( get_rom_size() > 256 * 0x2000 )
+ {
+ fatalerror("konami: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x2000;
+
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ fatalerror("konami: Invalid ROM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_konami::read_cart)
+{
+ return m_bank_base[offset >> 13][offset & 0x1fff];
+}
+
+
+WRITE8_MEMBER(msx_cart_konami::write_cart)
+{
+ switch (offset)
+ {
+ case 0x6000:
+ m_selected_bank[0] = data;
+ m_bank_base[1] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000;
+ m_bank_base[3] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000;
+ break;
+
+ case 0x8000:
+ m_selected_bank[1] = data;
+ m_bank_base[4] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000;
+ m_bank_base[6] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000;
+ break;
+
+ case 0xa000:
+ m_selected_bank[2] = data;
+ m_bank_base[5] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000;
+ m_bank_base[7] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000;
+ break;
+ }
+}
+
+
+
+
+msx_cart_konami_scc::msx_cart_konami_scc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_KONAMI_SCC, "MSX Cartridge - KONAMI+SCC", tag, owner, clock, "msx_cart_konami_scc", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_k051649(*this, "k051649")
+ , m_bank_mask(0)
+ , m_scc_active(false)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( konami_scc )
+ // 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'.
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("k051649", K051649, XTAL_10_738635MHz/3/2)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15)
+MACHINE_CONFIG_END
+
+
+machine_config_constructor msx_cart_konami_scc::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( konami_scc );
+}
+
+
+void msx_cart_konami_scc::device_start()
+{
+ save_item(NAME(m_selected_bank));
+ save_item(NAME(m_scc_active));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_konami_scc::restore_banks), this));
+}
+
+
+void msx_cart_konami_scc::restore_banks()
+{
+ m_bank_base[0] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000;
+ m_bank_base[1] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000;
+ m_bank_base[2] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000;
+ m_bank_base[3] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000;
+ m_bank_base[4] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000;
+ m_bank_base[5] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000;
+ m_bank_base[6] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000;
+ m_bank_base[7] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000;
+}
+
+
+void msx_cart_konami_scc::device_reset()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = i;
+ }
+ m_scc_active = false;
+}
+
+
+void msx_cart_konami_scc::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( get_rom_size() > 256 * 0x2000 )
+ {
+ fatalerror("konami_scc: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x2000;
+
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ fatalerror("konami_scc: Invalid ROM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_konami_scc::read_cart)
+{
+ if ( m_scc_active && offset >= 0x9800 && offset < 0xa000 )
+ {
+ if (offset & 0x80)
+ {
+ if ((offset & 0xff) >= 0xe0)
+ {
+ return m_k051649->k051649_test_r(space, offset & 0xff);
+ }
+ return 0xff;
+ }
+ else
+ {
+ return m_k051649->k051649_waveform_r(space, offset & 0x7f);
+ }
+ }
+
+ return m_bank_base[offset >> 13][offset & 0x1fff];
+}
+
+
+WRITE8_MEMBER(msx_cart_konami_scc::write_cart)
+{
+ switch (offset & 0xf800)
+ {
+ case 0x5000:
+ m_selected_bank[0] = data;
+ m_bank_base[2] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000;
+ m_bank_base[6] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000;
+ break;
+
+ case 0x7000:
+ m_selected_bank[1] = data;
+ m_bank_base[3] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000;
+ m_bank_base[7] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000;
+ break;
+
+ case 0x9000:
+ m_selected_bank[2] = data;
+ m_scc_active = ( ( data & 0x3f ) == 0x3f );
+ m_bank_base[0] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000;
+ m_bank_base[4] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000;
+ break;
+
+ case 0x9800:
+ if ( m_scc_active )
+ {
+ offset &= 0xff;
+
+ if (offset < 0x80)
+ {
+ m_k051649->k051649_waveform_w(space, offset, data);
+ }
+ else if (offset < 0xa0)
+ {
+ offset &= 0x0f;
+ if (offset < 0x0a)
+ {
+ m_k051649->k051649_frequency_w(space, offset, data);
+ }
+ else if (offset < 0x0f)
+ {
+ m_k051649->k051649_volume_w(space, offset - 0xa, data);
+ }
+ else
+ {
+ m_k051649->k051649_keyonoff_w(space, 0, data);
+ }
+ }
+ else if (offset >= 0xe0)
+ {
+ m_k051649->k051649_test_w(space, offset, data);
+ }
+ }
+ break;
+
+ case 0xb000:
+ m_selected_bank[3] = data;
+ m_bank_base[1] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000;
+ m_bank_base[5] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000;
+ break;
+ }
+}
+
+
+
+
+
+
+msx_cart_gamemaster2::msx_cart_gamemaster2(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_GAMEMASTER2, "MSX Cartridge - GAMEMASTER2", tag, owner, clock, "msx_cart_gamemaster2", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+{
+ for (int i = 0; i < 3; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_gamemaster2::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_gamemaster2::restore_banks), this));
+}
+
+
+void msx_cart_gamemaster2::setup_bank(UINT8 bank)
+{
+ switch (bank)
+ {
+ case 0:
+ if (m_selected_bank[0] & 0x10)
+ {
+ m_bank_base[1] = get_sram_base() + ((m_selected_bank[0] & 0x20) ? 0x1000 : 0);
+ m_bank_base[3] = get_sram_base() + ((m_selected_bank[0] & 0x20) ? 0x1000 : 0);
+ }
+ else
+ {
+ m_bank_base[1] = get_rom_base() + ( m_selected_bank[0] & 0x0f ) * 0x2000;
+ m_bank_base[3] = get_rom_base() + ( m_selected_bank[0] & 0x0f ) * 0x2000;
+ }
+ break;
+
+ case 1:
+ if (m_selected_bank[1] & 0x10)
+ {
+ m_bank_base[4] = get_sram_base() + ((m_selected_bank[1] & 0x20) ? 0x1000 : 0);
+ m_bank_base[6] = get_sram_base() + ((m_selected_bank[1] & 0x20) ? 0x1000 : 0);
+ }
+ else
+ {
+ m_bank_base[4] = get_rom_base() + ( m_selected_bank[1] & 0x0f ) * 0x2000;
+ m_bank_base[6] = get_rom_base() + ( m_selected_bank[1] & 0x0f ) * 0x2000;
+ }
+ break;
+
+ case 2:
+ if (m_selected_bank[2] & 0x10)
+ {
+ m_bank_base[5] = get_sram_base() + ((m_selected_bank[2] & 0x20) ? 0x1000 : 0);
+ m_bank_base[7] = get_sram_base() + ((m_selected_bank[2] & 0x20) ? 0x1000 : 0);
+ }
+ else
+ {
+ m_bank_base[5] = get_rom_base() + ( m_selected_bank[2] & 0x0f ) * 0x2000;
+ m_bank_base[7] = get_rom_base() + ( m_selected_bank[2] & 0x0f ) * 0x2000;
+ }
+ break;
+ }
+}
+
+
+void msx_cart_gamemaster2::restore_banks()
+{
+ m_bank_base[0] = get_rom_base();
+ m_bank_base[2] = get_rom_base();
+ setup_bank(0);
+ setup_bank(1);
+ setup_bank(2);
+}
+
+
+void msx_cart_gamemaster2::device_reset()
+{
+ for (int i = 0; i < 3; i++)
+ {
+ m_selected_bank[i] = i + 1;
+ }
+}
+
+
+void msx_cart_gamemaster2::initialize_cartridge()
+{
+ if ( get_rom_size() != 0x20000 )
+ {
+ fatalerror("gamemaster2: Invalid ROM size\n");
+ }
+
+ if (get_sram_size() != 0x2000)
+ {
+ fatalerror("gamemaster2: Invalid SRAM size\n");
+ }
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_gamemaster2::read_cart)
+{
+ UINT8 bank = offset >> 13;
+
+ switch (bank)
+ {
+ case 1:
+ case 3:
+ if (m_selected_bank[0] & 0x10)
+ {
+ return m_bank_base[bank][offset & 0x0fff];
+ }
+ break;
+
+ case 4:
+ case 6:
+ if (m_selected_bank[1] & 0x10)
+ {
+ return m_bank_base[bank][offset & 0x0fff];
+ }
+ break;
+
+ case 5:
+ case 7:
+ if (m_selected_bank[2] & 0x10)
+ {
+ return m_bank_base[bank][offset & 0x0fff];
+ }
+ break;
+ }
+ return m_bank_base[bank][offset & 0x1fff];
+}
+
+
+WRITE8_MEMBER(msx_cart_gamemaster2::write_cart)
+{
+ switch (offset & 0xf000)
+ {
+ case 0x6000:
+ m_selected_bank[0] = data;
+ setup_bank(0);
+ break;
+
+ case 0x8000:
+ m_selected_bank[1] = data;
+ setup_bank(1);
+ break;
+
+ case 0xa000:
+ m_selected_bank[2] = data;
+ setup_bank(2);
+ break;
+
+ case 0xb000:
+ if (m_selected_bank[2] & 0x10)
+ {
+ m_bank_base[5][offset & 0x0fff] = data;
+ }
+ break;
+ }
+}
+
+
+
+
+
+msx_cart_synthesizer::msx_cart_synthesizer(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_SYNTHESIZER, "MSX Cartridge - Synthesizer", tag, owner, clock, "msx_cart_synthesizer", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_base(NULL)
+ , m_dac(*this, "dac")
+{
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( synthesizer )
+ // 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'.
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("dac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20)
+MACHINE_CONFIG_END
+
+
+machine_config_constructor msx_cart_synthesizer::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( synthesizer );
+}
+
+
+void msx_cart_synthesizer::device_start()
+{
+}
+
+
+void msx_cart_synthesizer::initialize_cartridge()
+{
+ if ( get_rom_size() != 0x8000 )
+ {
+ fatalerror("synthesizer: Invalid ROM size\n");
+ }
+
+ m_bank_base = get_rom_base();
+}
+
+
+READ8_MEMBER(msx_cart_synthesizer::read_cart)
+{
+ if (offset >= 0x4000 && offset < 0xc000 )
+ {
+ return m_bank_base[offset - 0x4000];
+ }
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_synthesizer::write_cart)
+{
+ if ((offset & 0xc010) == 0x4000)
+ {
+ m_dac->write_unsigned8(data);
+ }
+}
+
+
+
+
+msx_cart_konami_sound::msx_cart_konami_sound(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
+ : device_t(mconfig, type, name, tag, owner, clock, shortname, source)
+ , msx_cart_interface(mconfig, *this)
+ , m_k052539(*this, "k052539")
+ , m_scc_active(false)
+ , m_sccplus_active(false)
+ , m_scc_mode(0)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ m_bank_base[i] = NULL;
+ }
+ for (int i = 0; i < 16; i++)
+ {
+ m_ram_bank[i] = NULL;
+ }
+ for (int i = 0; i < 4; i++)
+ {
+ m_ram_enabled[i] = false;
+ }
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( konami_sound )
+ // 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'.
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("k052539", K051649, XTAL_10_738635MHz/3/2)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15)
+MACHINE_CONFIG_END
+
+
+machine_config_constructor msx_cart_konami_sound::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( konami_sound );
+}
+
+
+void msx_cart_konami_sound::device_start()
+{
+ save_item(NAME(m_selected_bank));
+ save_item(NAME(m_scc_active));
+ save_item(NAME(m_sccplus_active));
+ save_item(NAME(m_ram_enabled));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_konami_sound::restore_banks), this));
+}
+
+
+void msx_cart_konami_sound::restore_banks()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ setup_bank(i);
+ }
+}
+
+
+void msx_cart_konami_sound::setup_bank(UINT8 bank)
+{
+ switch (bank)
+ {
+ case 0:
+ m_bank_base[2] = m_ram_bank[m_selected_bank[0] & 0x0f];
+ m_bank_base[6] = m_ram_bank[m_selected_bank[0] & 0x0f];
+ break;
+
+ case 1:
+ m_bank_base[3] = m_ram_bank[m_selected_bank[1] & 0x0f];
+ m_bank_base[7] = m_ram_bank[m_selected_bank[1] & 0x0f];
+ break;
+
+ case 2:
+ m_bank_base[0] = m_ram_bank[m_selected_bank[2] & 0x0f];
+ m_bank_base[4] = m_ram_bank[m_selected_bank[2] & 0x0f];
+ break;
+
+ case 3:
+ m_bank_base[1] = m_ram_bank[m_selected_bank[3] & 0x0f];
+ m_bank_base[5] = m_ram_bank[m_selected_bank[3] & 0x0f];
+ break;
+ }
+}
+
+
+void msx_cart_konami_sound::device_reset()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = i;
+ m_ram_enabled[i] = false;
+ }
+ m_scc_active = false;
+ m_sccplus_active = false;
+}
+
+
+void msx_cart_konami_sound::initialize_cartridge()
+{
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_konami_sound::read_cart)
+{
+ if ( m_scc_active && offset >= 0x9800 && offset < 0x9fe0 )
+ {
+ offset &= 0xff;
+ if (offset < 0x80)
+ {
+ return m_k052539->k051649_waveform_r(space, offset);
+ }
+ if (offset < 0xa0)
+ {
+ return 0xff;
+ }
+ if (offset < 0xc0)
+ {
+ return m_k052539->k051649_waveform_r(space, offset & 0x9f);
+ }
+ if (offset < 0xe0)
+ {
+ return m_k052539->k051649_test_r(space, offset & 0xff);
+ }
+ return 0xff;
+ }
+ else if ( m_sccplus_active && offset >= 0xb800 && offset < 0xbfe0)
+ {
+ offset &= 0xff;
+
+ if (offset < 0xa0)
+ {
+ return m_k052539->k052539_waveform_r(space, offset);
+ }
+ if (offset >= 0xc0 && offset < 0xe0)
+ {
+ return m_k052539->k051649_test_r(space, offset);
+ }
+ return 0xff;
+ }
+
+ UINT8 *base = m_bank_base[offset >> 13];
+
+ if (base != NULL)
+ {
+ return base[offset & 0x1fff];
+ }
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_konami_sound::write_cart)
+{
+ switch (offset & 0xe000)
+ {
+ case 0x4000:
+ if (m_ram_enabled[0] && m_bank_base[2] != NULL)
+ {
+ m_bank_base[2][offset & 0x1fff] = data;
+ }
+ if ((offset & 0x1800) == 0x1000)
+ {
+ m_selected_bank[0] = data;
+ setup_bank(0);
+ }
+ break;
+
+ case 0x6000:
+ if (m_ram_enabled[1] && m_bank_base[3] != NULL)
+ {
+ m_bank_base[3][offset & 0x1fff] = data;
+ }
+ if ((offset & 0x1800) == 0x1000)
+ {
+ m_selected_bank[1] = data;
+ setup_bank(1);
+ }
+ break;
+
+ case 0x8000:
+ if (m_ram_enabled[2] && m_bank_base[0] != NULL)
+ {
+ m_bank_base[0][offset & 0x1fff] = data;
+ }
+ switch (offset & 0x1800)
+ {
+ case 0x1000: // 0x9000-0x97ff
+ m_selected_bank[2] = data;
+ m_scc_active = ( ( data & 0x3f ) == 0x3f );
+ setup_bank(2);
+ break;
+
+ case 0x1800: // 0x9800-0x9fff
+ if ( m_scc_active )
+ {
+ offset &= 0xff;
+
+ if (offset < 0x80)
+ {
+ m_k052539->k051649_waveform_w(space, offset, data);
+ }
+ else if (offset < 0xa0)
+ {
+ offset &= 0x0f;
+ if (offset < 0x0a)
+ {
+ m_k052539->k051649_frequency_w(space, offset, data);
+ }
+ else if (offset < 0x0f)
+ {
+ m_k052539->k051649_volume_w(space, offset - 0xa, data);
+ }
+ else
+ {
+ m_k052539->k051649_keyonoff_w(space, 0, data);
+ }
+ }
+ else if (offset >= 0xe0)
+ {
+ m_k052539->k051649_test_w(space, offset, data);
+ }
+ }
+ break;
+ }
+ break;
+
+ case 0xa000:
+ if (m_ram_enabled[3] && m_bank_base[1] != NULL)
+ {
+ m_bank_base[1][offset & 0x1fff] = data;
+ }
+ switch (offset & 0x1800)
+ {
+ // 0xb000-0xb7ff
+ case 0x1000:
+ m_selected_bank[3] = data;
+ setup_bank(3);
+ break;
+
+ // 0xb800-0xbfff
+ case 0x1800:
+ if ((offset & 0x7fe) == 0x7fe)
+ {
+ // 0xbffe-0xbfff
+ /* write to mode register */
+ m_scc_mode = data;
+
+ m_ram_enabled[0] = ((m_scc_mode & 0x10) || (m_scc_mode & 0x01));
+ m_ram_enabled[1] = ((m_scc_mode & 0x10) || (m_scc_mode & 0x02));
+ m_ram_enabled[2] = ((m_scc_mode & 0x10) || ((m_scc_mode & 0x04) && (m_scc_mode & 0x20)));
+ m_ram_enabled[3] = (m_scc_mode & 0x10);
+
+ m_scc_active = ((m_selected_bank[2] & 0x3f) == 0x3f) && !(m_scc_mode & 0x20);
+ m_sccplus_active = (m_selected_bank[3] & 0x80) && (m_scc_mode & 0x20);
+ }
+ else
+ {
+ if (m_sccplus_active)
+ {
+ offset &= 0xff;
+ if (offset < 0xa0)
+ {
+ m_k052539->k052539_waveform_w(space, offset, data);
+ }
+ else if (offset < 0xc0)
+ {
+ offset &= 0x0f;
+ if (offset < 0x0a)
+ {
+ m_k052539->k051649_frequency_w(space, offset, data);
+ }
+ else if (offset < 0x0f)
+ {
+ m_k052539->k051649_volume_w(space, offset - 0x0a, data);
+ }
+ else if (offset == 0x0f)
+ {
+ m_k052539->k051649_keyonoff_w(space, 0, data);
+ }
+ }
+ else if (offset < 0xe0)
+ {
+ m_k052539->k051649_test_w(space, offset, data);
+ }
+ }
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+msx_cart_konami_sound_snatcher::msx_cart_konami_sound_snatcher(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : msx_cart_konami_sound(mconfig, MSX_CART_SOUND_SNATCHER, "MSX Cartridge - Sound Snatcher", tag, owner, clock, "msx_cart_sound_snatcher", __FILE__)
+{
+}
+
+
+void msx_cart_konami_sound_snatcher::initialize_cartridge()
+{
+ msx_cart_konami_sound::initialize_cartridge();
+
+ if (get_ram_size() != 0x10000)
+ {
+ fatalerror("sound_snatcher: Invalid RAM size\n");
+ }
+
+ // The Snatcher Sound cartridge has 64KB RAM available by selecting ram banks 0-7
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_ram_bank[i] = get_ram_base() + i * 0x2000;
+ }
+}
+
+
+msx_cart_konami_sound_sdsnatcher::msx_cart_konami_sound_sdsnatcher(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : msx_cart_konami_sound(mconfig, MSX_CART_SOUND_SDSNATCHER, "MSX Cartridge - Sound SD Snatcher", tag, owner, clock, "msx_cart_sound_sdsnatcher", __FILE__)
+{
+}
+
+
+void msx_cart_konami_sound_sdsnatcher::initialize_cartridge()
+{
+ msx_cart_konami_sound::initialize_cartridge();
+
+ if (get_ram_size() != 0x10000)
+ {
+ fatalerror("sound_sdsnatcher: Invalid RAM size\n");
+ }
+
+ // The SD Snatcher Sound cartrdige has 64KB RAM available by selecting ram banks 8-15
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_ram_bank[8+i] = get_ram_base() + i * 0x2000;
+ }
+
+}
+
diff --git a/src/emu/bus/msx_cart/konami.h b/src/emu/bus/msx_cart/konami.h
new file mode 100644
index 00000000000..18d0429d302
--- /dev/null
+++ b/src/emu/bus/msx_cart/konami.h
@@ -0,0 +1,169 @@
+#ifndef __MSX_CART_KONAMI_H
+#define __MSX_CART_KONAMI_H
+
+#include "bus/msx_cart/cartridge.h"
+#include "sound/k051649.h"
+#include "sound/dac.h"
+
+
+extern const device_type MSX_CART_KONAMI;
+extern const device_type MSX_CART_KONAMI_SCC;
+extern const device_type MSX_CART_GAMEMASTER2;
+extern const device_type MSX_CART_SYNTHESIZER;
+extern const device_type MSX_CART_SOUND_SNATCHER;
+extern const device_type MSX_CART_SOUND_SDSNATCHER;
+
+
+class msx_cart_konami : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_konami(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank[3];
+ UINT8 *m_bank_base[8];
+};
+
+
+class msx_cart_konami_scc : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_konami_scc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual void initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ required_device<k051649_device> m_k051649;
+
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank[4];
+ UINT8 *m_bank_base[8];
+ bool m_scc_active;
+};
+
+
+class msx_cart_gamemaster2 : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_gamemaster2(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_selected_bank[3];
+ UINT8 *m_bank_base[8];
+
+ void setup_bank(UINT8 bank);
+};
+
+
+class msx_cart_synthesizer : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_synthesizer(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual void initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+private:
+ UINT8 *m_bank_base;
+ required_device<dac_device> m_dac;
+};
+
+
+class msx_cart_konami_sound : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_konami_sound(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual void initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+protected:
+ UINT8 *m_ram_bank[16];
+
+private:
+ // This is actually a K052539
+ required_device<k051649_device> m_k052539;
+
+ UINT8 m_selected_bank[4];
+ UINT8 *m_bank_base[8];
+ bool m_scc_active;
+ bool m_sccplus_active;
+ bool m_ram_enabled[4];
+ UINT8 m_scc_mode;
+
+ void setup_bank(UINT8 bank);
+};
+
+
+class msx_cart_konami_sound_snatcher : public msx_cart_konami_sound
+{
+public:
+ msx_cart_konami_sound_snatcher(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void initialize_cartridge();
+};
+
+
+class msx_cart_konami_sound_sdsnatcher : public msx_cart_konami_sound
+{
+public:
+ msx_cart_konami_sound_sdsnatcher(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void initialize_cartridge();
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_cart/korean.c b/src/emu/bus/msx_cart/korean.c
new file mode 100644
index 00000000000..a6688cb3340
--- /dev/null
+++ b/src/emu/bus/msx_cart/korean.c
@@ -0,0 +1,297 @@
+#include "emu.h"
+#include "korean.h"
+
+const device_type MSX_CART_KOREAN_80IN1 = &device_creator<msx_cart_korean_80in1>;
+const device_type MSX_CART_KOREAN_90IN1 = &device_creator<msx_cart_korean_90in1>;
+const device_type MSX_CART_KOREAN_126IN1 = &device_creator<msx_cart_korean_126in1>;
+
+
+msx_cart_korean_80in1::msx_cart_korean_80in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_KOREAN_80IN1, "MSX Cartridge - Korean 80-in-1", tag, owner, clock, "msx_cart_korean_80in1", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_mask(0)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = i;
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_korean_80in1::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_korean_80in1::restore_banks), this));
+}
+
+
+void msx_cart_korean_80in1::setup_bank(UINT8 bank)
+{
+ m_bank_base[bank] = get_rom_base() + ( m_selected_bank[bank] & m_bank_mask ) * 0x2000;
+}
+
+
+void msx_cart_korean_80in1::restore_banks()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ setup_bank(i);
+ }
+}
+
+
+void msx_cart_korean_80in1::device_reset()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = i;
+ }
+}
+
+
+void msx_cart_korean_80in1::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( size > 256 * 0x2000 )
+ {
+ fatalerror("korean_80in1: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x2000;
+
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ fatalerror("korean_80in1: Invalid ROM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_korean_80in1::read_cart)
+{
+ if (offset >= 0x4000 && offset < 0xc000)
+ {
+ return m_bank_base[(offset - 0x4000) >> 13][offset & 0x1fff];
+ }
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_korean_80in1::write_cart)
+{
+ if (offset >= 0x4000 && offset < 0x4004)
+ {
+ UINT8 bank = offset & 3;
+
+ m_selected_bank[bank] = data;
+ setup_bank(bank);
+ }
+}
+
+
+
+
+
+msx_cart_korean_90in1::msx_cart_korean_90in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_KOREAN_90IN1, "MSX Cartridge - Korean 90-in-1", tag, owner, clock, "msx_cart_korean_90in1", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_mask(0)
+ , m_selected_bank(0)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_korean_90in1::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_korean_90in1::restore_banks), this));
+
+ // Install IO read/write handlers
+ address_space &space = machine().device<cpu_device>("maincpu")->space(AS_IO);
+ space.install_write_handler(0x77, 0x77, write8_delegate(FUNC(msx_cart_korean_90in1::banking), this));
+}
+
+
+void msx_cart_korean_90in1::restore_banks()
+{
+ UINT8 *base = get_rom_base();
+
+ switch (m_selected_bank & 0xc0)
+ {
+ case 0x80:
+ base += (m_selected_bank & 0x3e & m_bank_mask) * 0x4000;
+ m_bank_base[0] = base;
+ m_bank_base[1] = base + 0x2000;
+ m_bank_base[2] = base + 0x4000;
+ m_bank_base[3] = base + 0x6000;
+ break;
+
+ case 0xc0:
+ base += (m_selected_bank & m_bank_mask) * 0x4000;
+ m_bank_base[0] = base;
+ m_bank_base[1] = base + 0x2000;
+ m_bank_base[2] = base + 0x2000;
+ m_bank_base[3] = base;
+ break;
+
+ default:
+ base += (m_selected_bank & m_bank_mask) * 0x4000;
+ m_bank_base[0] = base;
+ m_bank_base[1] = base + 0x2000;
+ m_bank_base[2] = base;
+ m_bank_base[3] = base + 0x2000;
+ break;
+ }
+}
+
+
+void msx_cart_korean_90in1::device_reset()
+{
+ m_selected_bank = 0;
+}
+
+
+void msx_cart_korean_90in1::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( size > 64 * 0x4000 )
+ {
+ fatalerror("korean_90in1: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x4000;
+
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ fatalerror("korean_90in1: Invalid ROM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_korean_90in1::read_cart)
+{
+ if (offset >= 0x4000 && offset < 0xc000)
+ {
+ return m_bank_base[(offset - 0x4000) >> 13][offset & 0x1fff];
+ }
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_korean_90in1::banking)
+{
+ m_selected_bank = data;
+ restore_banks();
+}
+
+
+
+
+
+msx_cart_korean_126in1::msx_cart_korean_126in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_KOREAN_126IN1, "MSX Cartridge - Korean 126-in-1", tag, owner, clock, "msx_cart_korean_126in1", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_bank_mask(0)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_selected_bank[i] = i;
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_korean_126in1::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_korean_126in1::restore_banks), this));
+}
+
+
+void msx_cart_korean_126in1::setup_bank(UINT8 bank)
+{
+ m_bank_base[bank] = get_rom_base() + ( m_selected_bank[bank] & m_bank_mask ) * 0x4000;
+}
+
+
+void msx_cart_korean_126in1::restore_banks()
+{
+ for (int i = 0; i < 2; i++)
+ {
+ setup_bank(i);
+ }
+}
+
+
+void msx_cart_korean_126in1::device_reset()
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_selected_bank[i] = i;
+ }
+}
+
+
+void msx_cart_korean_126in1::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ if ( size > 256 * 0x4000 )
+ {
+ fatalerror("korean_126in1: ROM is too big\n");
+ }
+
+ UINT16 banks = size / 0x4000;
+
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ fatalerror("korean_126in1: Invalid ROM size\n");
+ }
+
+ m_bank_mask = banks - 1;
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_korean_126in1::read_cart)
+{
+ if (offset >= 0x4000 && offset < 0xc000)
+ {
+ return m_bank_base[offset >> 15][offset & 0x3fff];
+ }
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_korean_126in1::write_cart)
+{
+ if (offset >= 0x4000 && offset < 0x4002)
+ {
+ UINT8 bank = offset & 1;
+
+ m_selected_bank[bank] = data;
+ setup_bank(bank);
+ }
+}
+
diff --git a/src/emu/bus/msx_cart/korean.h b/src/emu/bus/msx_cart/korean.h
new file mode 100644
index 00000000000..76062632923
--- /dev/null
+++ b/src/emu/bus/msx_cart/korean.h
@@ -0,0 +1,89 @@
+#ifndef __MSX_CART_KOREAN_H
+#define __MSX_CART_KOREAN_H
+
+#include "bus/msx_cart/cartridge.h"
+
+
+extern const device_type MSX_CART_KOREAN_80IN1;
+extern const device_type MSX_CART_KOREAN_90IN1;
+extern const device_type MSX_CART_KOREAN_126IN1;
+
+
+class msx_cart_korean_80in1 : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_korean_80in1(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank[4];
+ UINT8 *m_bank_base[4];
+
+ void setup_bank(UINT8 bank);
+};
+
+
+class msx_cart_korean_90in1 : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_korean_90in1(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+
+ DECLARE_WRITE8_MEMBER(banking);
+
+ void restore_banks();
+
+private:
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank;
+ UINT8 *m_bank_base[4];
+};
+
+
+class msx_cart_korean_126in1 : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_korean_126in1(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_bank_mask;
+ UINT8 m_selected_bank[2];
+ UINT8 *m_bank_base[2];
+
+ void setup_bank(UINT8 bank);
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_cart/majutsushi.c b/src/emu/bus/msx_cart/majutsushi.c
new file mode 100644
index 00000000000..a89ad1f2328
--- /dev/null
+++ b/src/emu/bus/msx_cart/majutsushi.c
@@ -0,0 +1,114 @@
+#include "emu.h"
+#include "majutsushi.h"
+
+const device_type MSX_CART_MAJUTSUSHI = &device_creator<msx_cart_majutsushi>;
+
+
+msx_cart_majutsushi::msx_cart_majutsushi(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_MAJUTSUSHI, "MSX Cartridge - Majutsushi", tag, owner, clock, "msx_cart_majutsushi", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_dac(*this, "dac")
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = 0;
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( majutsushi )
+ // 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'.
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("dac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.10)
+MACHINE_CONFIG_END
+
+
+machine_config_constructor msx_cart_majutsushi::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( majutsushi );
+}
+
+
+void msx_cart_majutsushi::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_majutsushi::restore_banks), this));
+}
+
+
+void msx_cart_majutsushi::restore_banks()
+{
+ m_bank_base[0] = get_rom_base() + ( m_selected_bank[0] & 0x0f ) * 0x2000;
+ m_bank_base[1] = get_rom_base() + ( m_selected_bank[1] & 0x0f ) * 0x2000;
+ m_bank_base[2] = get_rom_base() + ( m_selected_bank[0] & 0x0f ) * 0x2000;
+ m_bank_base[3] = get_rom_base() + ( m_selected_bank[1] & 0x0f ) * 0x2000;
+ m_bank_base[4] = get_rom_base() + ( m_selected_bank[2] & 0x0f ) * 0x2000;
+ m_bank_base[5] = get_rom_base() + ( m_selected_bank[3] & 0x0f ) * 0x2000;
+ m_bank_base[6] = get_rom_base() + ( m_selected_bank[2] & 0x0f ) * 0x2000;
+ m_bank_base[7] = get_rom_base() + ( m_selected_bank[3] & 0x0f ) * 0x2000;
+}
+
+
+void msx_cart_majutsushi::device_reset()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = i;
+ }
+}
+
+
+void msx_cart_majutsushi::initialize_cartridge()
+{
+ if ( get_rom_size() != 0x20000 )
+ {
+ fatalerror("majutsushi: Invalid ROM size\n");
+ }
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_majutsushi::read_cart)
+{
+ return m_bank_base[offset >> 13][offset & 0x1fff];
+}
+
+
+WRITE8_MEMBER(msx_cart_majutsushi::write_cart)
+{
+ switch (offset & 0xe000)
+ {
+ case 0x4000:
+ if (offset & 0x1000)
+ {
+ m_dac->write_unsigned8(data);
+ }
+ break;
+
+ case 0x6000:
+ m_selected_bank[1] = data & 0x0f;
+ m_bank_base[1] = get_rom_base() + m_selected_bank[1] * 0x2000;
+ m_bank_base[3] = get_rom_base() + m_selected_bank[1] * 0x2000;
+ break;
+
+ case 0x8000:
+ m_selected_bank[2] = data & 0x0f;
+ m_bank_base[4] = get_rom_base() + m_selected_bank[2] * 0x2000;
+ m_bank_base[6] = get_rom_base() + m_selected_bank[2] * 0x2000;
+ break;
+
+ case 0xa000:
+ m_selected_bank[3] = data & 0x0f;
+ m_bank_base[5] = get_rom_base() + m_selected_bank[3] * 0x2000;
+ m_bank_base[7] = get_rom_base() + m_selected_bank[3] * 0x2000;
+ break;
+ }
+}
+
diff --git a/src/emu/bus/msx_cart/majutsushi.h b/src/emu/bus/msx_cart/majutsushi.h
new file mode 100644
index 00000000000..95188585169
--- /dev/null
+++ b/src/emu/bus/msx_cart/majutsushi.h
@@ -0,0 +1,37 @@
+#ifndef __MSX_CART_MAJUTSUSHI_H
+#define __MSX_CART_MAJUTSUSHI_H
+
+#include "bus/msx_cart/cartridge.h"
+#include "sound/dac.h"
+
+
+extern const device_type MSX_CART_MAJUTSUSHI;
+
+
+class msx_cart_majutsushi : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_majutsushi(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual void initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ required_device<dac_device> m_dac;
+
+ UINT8 m_selected_bank[4];
+ UINT8 *m_bank_base[8];
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_cart/msxdos2.c b/src/emu/bus/msx_cart/msxdos2.c
new file mode 100644
index 00000000000..10af9d6de28
--- /dev/null
+++ b/src/emu/bus/msx_cart/msxdos2.c
@@ -0,0 +1,66 @@
+#include "emu.h"
+#include "msxdos2.h"
+
+const device_type MSX_CART_MSXDOS2 = &device_creator<msx_cart_msxdos2>;
+
+
+msx_cart_msxdos2::msx_cart_msxdos2(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_MSXDOS2, "MSX Cartridge - MSXDOS2", tag, owner, clock, "msx_cart_msxdos2", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_selected_bank(0)
+ , m_bank_base(NULL)
+{
+}
+
+
+void msx_cart_msxdos2::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_msxdos2::restore_banks), this));
+}
+
+
+void msx_cart_msxdos2::restore_banks()
+{
+ m_bank_base = get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000;
+}
+
+
+void msx_cart_msxdos2::device_reset()
+{
+ m_selected_bank = 0;
+}
+
+
+void msx_cart_msxdos2::initialize_cartridge()
+{
+ if (get_rom_size() != 0x10000)
+ {
+ fatalerror("msxdos2: Invalid ROM size\n");
+ }
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_msxdos2::read_cart)
+{
+ if (offset >= 0x4000 && offset < 0x8000)
+ {
+ return m_bank_base[offset & 0x3fff];
+ }
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_msxdos2::write_cart)
+{
+ if (offset == 0x6000)
+ {
+ m_selected_bank = data;
+ restore_banks();
+ }
+}
+
diff --git a/src/emu/bus/msx_cart/msxdos2.h b/src/emu/bus/msx_cart/msxdos2.h
new file mode 100644
index 00000000000..eeaaf584e4a
--- /dev/null
+++ b/src/emu/bus/msx_cart/msxdos2.h
@@ -0,0 +1,33 @@
+#ifndef __MSX_CART_MSXDOS2_H
+#define __MSX_CART_MSXDOS2_H
+
+#include "bus/msx_cart/cartridge.h"
+
+
+extern const device_type MSX_CART_MSXDOS2;
+
+
+class msx_cart_msxdos2 : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_msxdos2(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_selected_bank;
+ UINT8 *m_bank_base;
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_cart/nomapper.c b/src/emu/bus/msx_cart/nomapper.c
new file mode 100644
index 00000000000..faa91b3d1dc
--- /dev/null
+++ b/src/emu/bus/msx_cart/nomapper.c
@@ -0,0 +1,49 @@
+
+#include "emu.h"
+#include "nomapper.h"
+
+const device_type MSX_CART_NOMAPPER = &device_creator<msx_cart_nomapper>;
+
+
+msx_cart_nomapper::msx_cart_nomapper(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_NOMAPPER, "MSX Cartridge - ROM", tag, owner, clock, "msx_cart_nomapper", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_start_address(0)
+ , m_end_address(0)
+{
+}
+
+void msx_cart_nomapper::device_start()
+{
+}
+
+void msx_cart_nomapper::initialize_cartridge()
+{
+ UINT32 size = get_rom_size();
+
+ m_start_address = 0x4000;
+
+ if (size <= 0x4000)
+ {
+ // Check if this ROM should be in page 2
+
+ UINT8 *rom = get_rom_base();
+
+ if (rom[0] == 'A' && rom[1] == 'B' && (rom[3] & 0x80))
+ {
+ m_start_address = 0x8000;
+ }
+ }
+
+ m_end_address = MIN(m_start_address + size, 0x10000);
+}
+
+READ8_MEMBER(msx_cart_nomapper::read_cart)
+{
+ if ( offset >= m_start_address && offset < m_end_address )
+ {
+ return get_rom_base()[offset - m_start_address];
+ }
+ return 0xff;
+}
+
diff --git a/src/emu/bus/msx_cart/nomapper.h b/src/emu/bus/msx_cart/nomapper.h
new file mode 100644
index 00000000000..c469f776cdc
--- /dev/null
+++ b/src/emu/bus/msx_cart/nomapper.h
@@ -0,0 +1,28 @@
+#ifndef __MSX_CART_NOMAPPER_H
+#define __MSX_CART_NOMAPPER_H
+
+#include "bus/msx_cart/cartridge.h"
+
+
+extern const device_type MSX_CART_NOMAPPER;
+
+
+class msx_cart_nomapper : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_nomapper(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+
+ virtual void initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+
+private:
+ UINT32 m_start_address;
+ UINT32 m_end_address;
+};
+
+#endif
diff --git a/src/emu/bus/msx_cart/rtype.c b/src/emu/bus/msx_cart/rtype.c
new file mode 100644
index 00000000000..25c1ec18f89
--- /dev/null
+++ b/src/emu/bus/msx_cart/rtype.c
@@ -0,0 +1,77 @@
+#include "emu.h"
+#include "rtype.h"
+
+const device_type MSX_CART_RTYPE = &device_creator<msx_cart_rtype>;
+
+
+msx_cart_rtype::msx_cart_rtype(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_RTYPE, "MSX Cartridge - R-Type", tag, owner, clock, "msx_cart_rtype", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_selected_bank(0)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_bank_base[i] = NULL;
+ }
+}
+
+
+void msx_cart_rtype::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_rtype::restore_banks), this));
+}
+
+
+void msx_cart_rtype::restore_banks()
+{
+ m_bank_base[0] = get_rom_base() + 15 * 0x4000;
+ if (m_selected_bank & 0x10)
+ {
+ m_selected_bank &= 0x17;
+ }
+ m_bank_base[1] = get_rom_base() + m_selected_bank * 0x4000;
+}
+
+
+void msx_cart_rtype::device_reset()
+{
+ m_selected_bank = 15;
+}
+
+
+void msx_cart_rtype::initialize_cartridge()
+{
+ if ( get_rom_size() != 0x80000 && get_rom_size() != 0x60000 )
+ {
+ fatalerror("rtype: Invalid ROM size\n");
+ }
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_rtype::read_cart)
+{
+ if (offset >= 0x4000 && offset < 0xc000)
+ {
+ return m_bank_base[offset >> 15][offset & 0x3fff];
+ }
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_rtype::write_cart)
+{
+ if (offset >= 0x7000 && offset < 0x8000)
+ {
+ m_selected_bank = data & 0x1f;
+ if (m_selected_bank & 0x10)
+ {
+ m_selected_bank &= 0x17;
+ }
+ m_bank_base[1] = get_rom_base() + m_selected_bank * 0x4000;
+ }
+}
+
diff --git a/src/emu/bus/msx_cart/rtype.h b/src/emu/bus/msx_cart/rtype.h
new file mode 100644
index 00000000000..999ba3232ff
--- /dev/null
+++ b/src/emu/bus/msx_cart/rtype.h
@@ -0,0 +1,33 @@
+#ifndef __MSX_CART_RTYPE_H
+#define __MSX_CART_RTYPE_H
+
+#include "bus/msx_cart/cartridge.h"
+
+
+extern const device_type MSX_CART_RTYPE;
+
+
+class msx_cart_rtype : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_rtype(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 initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+ virtual DECLARE_WRITE8_MEMBER(write_cart);
+
+ void restore_banks();
+
+private:
+ UINT8 m_selected_bank;
+ UINT8 *m_bank_base[2];
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_cart/superloderunner.c b/src/emu/bus/msx_cart/superloderunner.c
new file mode 100644
index 00000000000..8337ca63254
--- /dev/null
+++ b/src/emu/bus/msx_cart/superloderunner.c
@@ -0,0 +1,61 @@
+#include "emu.h"
+#include "superloderunner.h"
+
+const device_type MSX_CART_SUPERLODERUNNER = &device_creator<msx_cart_superloderunner>;
+
+
+msx_cart_superloderunner::msx_cart_superloderunner(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_CART_SUPERLODERUNNER, "MSX Cartridge - Super Lode Runner", tag, owner, clock, "msx_cart_superloderunner", __FILE__)
+ , msx_cart_interface(mconfig, *this)
+ , m_selected_bank(0)
+ , m_bank_base(NULL)
+{
+}
+
+
+void msx_cart_superloderunner::device_start()
+{
+ save_item(NAME(m_selected_bank));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_superloderunner::restore_banks), this));
+
+ // Install evil memory write handler
+ address_space &space = machine().device<cpu_device>("maincpu")->space(AS_PROGRAM);
+ space.install_write_handler(0x0000, 0x0000, write8_delegate(FUNC(msx_cart_superloderunner::banking), this));
+}
+
+
+void msx_cart_superloderunner::restore_banks()
+{
+ m_bank_base = get_rom_base() + (m_selected_bank & 0x0f) * 0x4000;
+}
+
+
+void msx_cart_superloderunner::initialize_cartridge()
+{
+ if (get_rom_size() != 0x20000)
+ {
+ fatalerror("crossblaim: Invalid ROM size\n");
+ }
+
+ restore_banks();
+}
+
+
+READ8_MEMBER(msx_cart_superloderunner::read_cart)
+{
+ if (offset >= 0x8000 && offset < 0xc000)
+ {
+ return m_bank_base[offset & 0x3fff];
+ }
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(msx_cart_superloderunner::banking)
+{
+ m_selected_bank = data;
+ restore_banks();
+}
+
diff --git a/src/emu/bus/msx_cart/superloderunner.h b/src/emu/bus/msx_cart/superloderunner.h
new file mode 100644
index 00000000000..5508f3f361f
--- /dev/null
+++ b/src/emu/bus/msx_cart/superloderunner.h
@@ -0,0 +1,33 @@
+#ifndef __MSX_CART_SUPERLODERUNNER_H
+#define __MSX_CART_SUPERLODERUNNER_H
+
+#include "bus/msx_cart/cartridge.h"
+
+
+extern const device_type MSX_CART_SUPERLODERUNNER;
+
+
+class msx_cart_superloderunner : public device_t
+ , public msx_cart_interface
+{
+public:
+ msx_cart_superloderunner(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+
+ virtual void initialize_cartridge();
+
+ virtual DECLARE_READ8_MEMBER(read_cart);
+
+ DECLARE_WRITE8_MEMBER(banking);
+
+ void restore_banks();
+
+private:
+ UINT8 m_selected_bank;
+ UINT8 *m_bank_base;
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_slot/bunsetsu.c b/src/emu/bus/msx_slot/bunsetsu.c
new file mode 100644
index 00000000000..49d529bc003
--- /dev/null
+++ b/src/emu/bus/msx_slot/bunsetsu.c
@@ -0,0 +1,77 @@
+/*
+ Emulation for the bunsetsu internal firmware mapper found in a number of MSX machines
+*/
+
+#include "emu.h"
+#include "bunsetsu.h"
+
+
+const device_type MSX_SLOT_BUNSETSU = &device_creator<msx_slot_bunsetsu_device>;
+
+
+msx_slot_bunsetsu_device::msx_slot_bunsetsu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : msx_slot_rom_device(mconfig, MSX_SLOT_BUNSETSU, "MSX Internal BUNSETSU", tag, owner, clock, "msx_slot_bunsetsu", __FILE__)
+ , m_bunsetsu_region(NULL)
+ , m_bunsetsu_region_tag(NULL)
+ , m_bunsetsu_address(0)
+{
+}
+
+
+void msx_slot_bunsetsu_device::device_start()
+{
+ msx_slot_rom_device::device_start();
+
+ if (m_bunsetsu_region_tag == NULL)
+ {
+ fatalerror("msx_slot_bunsetsu_device: no bunsetsu region tag specified\n");
+ }
+
+ m_bunsetsu_region = owner()->memregion(m_bunsetsu_region_tag);
+
+ if (m_bunsetsu_region == NULL)
+ {
+ fatalerror("msx_slot_bunsetsu_device: Unable to find region with tag '%s'\n", m_bunsetsu_region_tag);
+ }
+
+ if (m_bunsetsu_region->bytes() != 0x20000)
+ {
+ fatalerror("msx_slot_bunsetsu_device: Bunsetsu region must be 0x20000 bytes.\n");
+ }
+}
+
+
+void msx_slot_bunsetsu_device::device_reset()
+{
+ m_bunsetsu_address = 0;
+}
+
+
+READ8_MEMBER(msx_slot_bunsetsu_device::read)
+{
+ if (offset == 0xbfff)
+ {
+ return m_bunsetsu_region->u8(m_bunsetsu_address++ & 0x1ffff);
+ }
+ return msx_slot_rom_device::read(space, offset);
+}
+
+
+WRITE8_MEMBER(msx_slot_bunsetsu_device::write)
+{
+ switch (offset)
+ {
+ case 0xbffc:
+ m_bunsetsu_address = (m_bunsetsu_address & 0xffff00) | data;
+ break;
+
+ case 0xbffd:
+ m_bunsetsu_address = (m_bunsetsu_address & 0xff00ff) | (data << 8);
+ break;
+
+ case 0xbffe:
+ m_bunsetsu_address = (m_bunsetsu_address & 0x00ffff) | (data << 16);
+ break;
+ }
+}
+
diff --git a/src/emu/bus/msx_slot/bunsetsu.h b/src/emu/bus/msx_slot/bunsetsu.h
new file mode 100644
index 00000000000..d798cc52b34
--- /dev/null
+++ b/src/emu/bus/msx_slot/bunsetsu.h
@@ -0,0 +1,38 @@
+#ifndef __MSX_SLOT_BUNSETSU_H
+#define __MSX_SLOT_BUNSETSU_H
+
+#include "bus/msx_slot/slot.h"
+#include "bus/msx_slot/rom.h"
+
+
+extern const device_type MSX_SLOT_BUNSETSU;
+
+
+#define MCFG_MSX_SLOT_BUNSETSU_ADD(_tag, _startpage, _numpages, _region, _offset, _bunsetsu_region_tag) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_BUNSETSU, _startpage, _numpages) \
+ msx_slot_rom_device::set_rom_start(*device, _region, _offset); \
+ msx_slot_bunsetsu_device::set_bunsetsu_region_tag(*device, _bunsetsu_region_tag); \
+
+class msx_slot_bunsetsu_device : public msx_slot_rom_device
+{
+public:
+ msx_slot_bunsetsu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void set_bunsetsu_region_tag(device_t &device, const char *tag) { dynamic_cast<msx_slot_bunsetsu_device &>(device).m_bunsetsu_region_tag = tag; }
+
+ virtual void device_start();
+ virtual void device_reset();
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+private:
+ memory_region *m_bunsetsu_region;
+ const char *m_bunsetsu_region_tag;
+ UINT32 m_bunsetsu_address;
+};
+
+
+#endif
+
diff --git a/src/emu/bus/msx_slot/cartridge.c b/src/emu/bus/msx_slot/cartridge.c
new file mode 100644
index 00000000000..199d1c8a1b7
--- /dev/null
+++ b/src/emu/bus/msx_slot/cartridge.c
@@ -0,0 +1,317 @@
+#include "emu.h"
+#include "bus/msx_slot/cartridge.h"
+#include "hashfile.h"
+
+
+enum
+{
+ NOMAPPER = 0,
+ ASCII8,
+ ASCII8_SRAM,
+ ASCII16,
+ ASCII16_SRAM,
+ CROSSBLAIM,
+ GAMEMASTER2,
+ KOREAN_80IN1,
+ KOREAN_90IN1,
+ KOREAN_126IN1,
+ FMPAC,
+ RTYPE,
+ KONAMI,
+ KONAMI_SCC,
+ SUPERLODERUNNER,
+ MAJUTSUSHI,
+ DISK_ROM,
+ SYNTHESIZER,
+ MSXDOS2
+};
+
+
+const device_type MSX_SLOT_CARTRIDGE = &device_creator<msx_slot_cartridge_device>;
+
+
+msx_slot_cartridge_device::msx_slot_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_SLOT_CARTRIDGE, "MSX Cartridge slot", tag, owner, clock, "msx_slot_cartridge", __FILE__)
+ , device_image_interface(mconfig, *this)
+ , device_slot_interface(mconfig, *this)
+ , msx_internal_slot_interface()
+{
+}
+
+
+static const struct
+{
+ int pcb_id;
+ const char *slot_option;
+} slot_list[] =
+{
+ { NOMAPPER, "nomapper" },
+ { ASCII8, "ascii8" },
+ { ASCII8_SRAM, "ascii8_sram" },
+ { ASCII16, "ascii16" },
+ { ASCII16_SRAM, "ascii16_sram" },
+ { CROSSBLAIM, "cross_blaim" },
+ { GAMEMASTER2, "gamemaster2" },
+ { KOREAN_80IN1, "korean_80in1" },
+ { KOREAN_90IN1, "korean_90in1" },
+ { KOREAN_126IN1, "korean_126in1" },
+ { FMPAC, "fmpac" },
+ { RTYPE, "rtype" },
+ { KONAMI, "konami" },
+ { KONAMI_SCC, "konami_scc" },
+ { SUPERLODERUNNER, "superloderunner" },
+ { MAJUTSUSHI, "majutsushi" },
+ { DISK_ROM, "disk_rom" },
+ { SYNTHESIZER, "synthesizer" },
+ { MSXDOS2, "msxdos2" }
+};
+
+
+static const char *msx_cart_get_slot_option(int type)
+{
+ for (int i = 0; i < ARRAY_LENGTH(slot_list); i++)
+ {
+ if (slot_list[i].pcb_id == type)
+ return slot_list[i].slot_option;
+ }
+
+ return slot_list[0].slot_option;
+}
+
+
+void msx_slot_cartridge_device::device_start()
+{
+ m_cartridge = dynamic_cast<msx_cart_interface *>(get_card_device());
+}
+
+
+bool msx_slot_cartridge_device::call_load()
+{
+ if ( m_cartridge )
+ {
+ if ( software_entry() )
+ {
+ // Allocate and copy rom contents
+ UINT32 length = get_software_region_length("rom");
+
+ m_cartridge->rom_alloc( length );
+ UINT8 *rom_base = m_cartridge->get_rom_base();
+ memcpy(rom_base, get_software_region("rom"), length);
+
+ // Allocate ram
+ length = get_software_region_length("ram");
+ m_cartridge->ram_alloc( length );
+
+ // Allocate sram
+ length = get_software_region_length("sram");
+ m_cartridge->sram_alloc( length );
+ }
+ else
+ {
+ UINT32 length = this->length();
+
+ UINT32 length_aligned = 0x4000;
+ while (length_aligned < length )
+ {
+ length_aligned *= 2;
+ }
+
+ m_cartridge->rom_alloc(length_aligned);
+ m_cartridge->ram_alloc(0);
+ m_cartridge->sram_alloc(0);
+
+ if (fread(m_cartridge->get_rom_base(), length) != length)
+ {
+ seterror(IMAGE_ERROR_UNSPECIFIED, "Unable to fully read file");
+ return IMAGE_INIT_FAIL;
+ }
+
+ // Check if there's some mapper related
+ astring extrainfo;
+ if (hashfile_extrainfo(*this, extrainfo))
+ {
+ }
+ }
+
+ m_cartridge->initialize_cartridge();
+
+ if (m_cartridge->get_sram_size() > 0)
+ {
+ battery_load(m_cartridge->get_sram_base(), m_cartridge->get_sram_size(), 0x00);
+ }
+ }
+ return IMAGE_INIT_PASS;
+}
+
+
+void msx_slot_cartridge_device::call_unload()
+{
+ if (m_cartridge)
+ {
+ if (m_cartridge->get_sram_size() > 0)
+ {
+ battery_save(m_cartridge->get_sram_base(), m_cartridge->get_sram_size());
+ }
+ }
+}
+
+
+bool msx_slot_cartridge_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;
+}
+
+
+int msx_slot_cartridge_device::get_cart_type(UINT8 *rom, UINT32 length)
+{
+ if (length < 0x2000)
+ {
+ return -1;
+ }
+
+ if (length < 0x10000)
+ {
+ return NOMAPPER;
+ }
+
+ if ( (rom[0x10] == 'Y') && (rom[0x11] == 'Z') && (length > 0x18000) )
+ {
+ return GAMEMASTER2;
+ }
+
+ int kon4 = 0, kon5 = 0, asc8 = 0, asc16 = 0;
+
+ for (int i=0; i < length-3; i++)
+ {
+ if (rom[i] == 0x32 && rom[i+1] == 0)
+ {
+ switch (rom[i+2])
+ {
+ case 0x60:
+ case 0x70:
+ asc16++;
+ asc8++;
+ break;
+
+ case 0x68:
+ case 0x78:
+ asc8++;
+ asc16--;
+ break;
+ }
+
+ switch (rom[i+2])
+ {
+ case 0x60:
+ case 0x80:
+ case 0xa0:
+ kon4++;
+ break;
+
+ case 0x50:
+ case 0x70:
+ case 0x90:
+ case 0xb0:
+ kon5++;
+ break;
+ }
+ }
+ }
+
+ if (MAX (kon4, kon5) > MAX (asc8, asc16) )
+ {
+ return (kon5 > kon4) ? KONAMI_SCC : KONAMI;
+ }
+ else
+ {
+ return (asc8 > asc16) ? ASCII8 : ASCII16;
+ }
+
+ return NOMAPPER;
+}
+
+
+void msx_slot_cartridge_device::get_default_card_software(astring &result)
+{
+ if (open_image_file(mconfig().options()))
+ {
+ const char *slot_string = "nomapper";
+ UINT32 length = core_fsize(m_file);
+ dynamic_buffer rom(length);
+ int type = NOMAPPER;
+
+ // Check if there's some mapper related information in the hashfiles
+ astring extrainfo;
+ if (hashfile_extrainfo(*this, extrainfo))
+ {
+ int extrainfo_type = -1;
+ if (1 == sscanf(extrainfo.cstr(), "%d", &extrainfo_type))
+ {
+ static const struct { int extrainfo; int mapper; } extrainfo_map[] = {
+ //{ 0, NOMAPPER },
+ { 1, MSXDOS2 },
+ { 2, KONAMI_SCC },
+ { 3, KONAMI },
+ { 4, ASCII8 },
+ { 5, ASCII16 },
+ { 6, GAMEMASTER2 },
+ { 7, ASCII8_SRAM },
+ { 8, ASCII16_SRAM },
+ { 9, RTYPE },
+ { 10, MAJUTSUSHI },
+ { 11, FMPAC },
+ { 12, SUPERLODERUNNER },
+ { 13, SYNTHESIZER },
+ { 14, CROSSBLAIM },
+ { 15, DISK_ROM },
+ { 16, KOREAN_80IN1 },
+ { 17, KOREAN_126IN1 }
+ };
+
+ for (int i = 0; i < ARRAY_LENGTH(extrainfo_map); i++)
+ {
+ if (extrainfo_map[i].extrainfo == extrainfo_type)
+ {
+ type = extrainfo_map[i].mapper;
+ }
+ }
+ }
+ }
+
+ if (type == NOMAPPER)
+ {
+ // Not identified through hashfile, try automatic detection
+ type = get_cart_type(rom, length);
+ }
+
+ if (type > NOMAPPER)
+ {
+ slot_string = msx_cart_get_slot_option(type);
+ }
+
+ result.cpy(slot_string);
+ return;
+ }
+ software_get_default_slot(result, "nomapper");
+}
+
+
+READ8_MEMBER(msx_slot_cartridge_device::read)
+{
+ if ( m_cartridge )
+ {
+ return m_cartridge->read_cart(space, offset);
+ }
+ return 0xFF;
+}
+
+
+WRITE8_MEMBER(msx_slot_cartridge_device::write)
+{
+ if ( m_cartridge )
+ {
+ m_cartridge->write_cart(space, offset, data);
+ }
+}
+
diff --git a/src/emu/bus/msx_slot/cartridge.h b/src/emu/bus/msx_slot/cartridge.h
new file mode 100644
index 00000000000..6716dc3ca14
--- /dev/null
+++ b/src/emu/bus/msx_slot/cartridge.h
@@ -0,0 +1,57 @@
+#ifndef __MSX_SLOT_CARTRIDGE_H
+#define __MSX_SLOT_CARTRIDGE_H
+
+#include "slot.h"
+#include "bus/msx_cart/cartridge.h"
+
+
+extern const device_type MSX_SLOT_CARTRIDGE;
+
+
+#define MCFG_MSX_SLOT_CARTRIDGE_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, MSX_SLOT_CARTRIDGE, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(msx_cart, NULL, false)
+
+
+class msx_slot_cartridge_device : public device_t
+ , public device_image_interface
+ , public device_slot_interface
+ , public msx_internal_slot_interface
+{
+public:
+ // construction/destruction
+ msx_slot_cartridge_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() { update_names(MSX_SLOT_CARTRIDGE, "cartridge", "cart"); }
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual void call_unload();
+ virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry);
+ virtual iodevice_t image_type() const { return IO_CARTSLOT; }
+ virtual bool is_readable() const { return true; }
+ virtual bool is_writeable() const { return false; }
+ virtual bool is_creatable() const { return false; }
+ virtual bool must_be_loaded() const { return false; }
+ virtual bool is_reset_on_load() const { return true; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+ virtual const char *image_interface() const { return "msx_cart"; }
+ virtual const char *file_extensions() const { return "mx1,bin,rom"; }
+
+ // slot interface overrides
+ virtual void get_default_card_software(astring &result);
+
+ // msx_internal_slot-level overrides
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+private:
+ msx_cart_interface *m_cartridge;
+
+ int get_cart_type(UINT8 *rom, UINT32 length);
+};
+
+#endif
+
diff --git a/src/emu/bus/msx_slot/disk.c b/src/emu/bus/msx_slot/disk.c
new file mode 100644
index 00000000000..3995bbc73e6
--- /dev/null
+++ b/src/emu/bus/msx_slot/disk.c
@@ -0,0 +1,369 @@
+/*
+From: erbo@xs4all.nl (erik de boer)
+
+sony and philips have used (almost) the same design
+and this is the memory layout
+but it is not a msx standard !
+
+WD1793 or wd2793 registers
+
+address
+
+7FF8H read status register
+ write command register
+7FF9H r/w track register (r/o on NMS 8245 and Sony)
+7FFAH r/w sector register (r/o on NMS 8245 and Sony)
+7FFBH r/w data register
+
+
+hardware registers
+
+address
+
+7FFCH r/w bit 0 side select
+7FFDH r/w b7>M-on , b6>in-use , b1>ds1 , b0>ds0 (all neg. logic)
+7FFEH not used
+7FFFH read b7>drq , b6>intrq
+
+set on 7FFDH bit 2 always to 0 (some use it as disk change reset)
+
+*/
+
+#include "emu.h"
+#include "disk.h"
+
+
+const device_type MSX_SLOT_DISK1 = &device_creator<msx_slot_disk1_device>;
+const device_type MSX_SLOT_DISK2 = &device_creator<msx_slot_disk2_device>;
+
+
+msx_slot_disk_device::msx_slot_disk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
+ : msx_slot_rom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+ , m_fdc(NULL)
+ , m_floppy0(NULL)
+ , m_floppy1(NULL)
+ , m_floppy(NULL)
+ , m_fdc_tag(NULL)
+ , m_floppy0_tag(NULL)
+ , m_floppy1_tag(NULL)
+{
+}
+
+
+void msx_slot_disk_device::device_start()
+{
+ msx_slot_rom_device::device_start();
+
+ if (m_fdc_tag == NULL)
+ {
+ fatalerror("msx_slot_disk_device: no FDC tag specified\n");
+ }
+
+ m_fdc = owner()->subdevice<wd_fdc_analog_t>(m_fdc_tag);
+ m_floppy0 = owner()->subdevice<floppy_connector>(m_floppy0_tag);
+ m_floppy1 = owner()->subdevice<floppy_connector>(m_floppy1_tag);
+
+ if (m_fdc == NULL)
+ {
+ fatalerror("msx_slot_disk_device: Unable to find FDC with tag '%s'\n", m_fdc_tag);
+ }
+
+ if (m_floppy0 == NULL && m_floppy1 == NULL)
+ {
+ logerror("msx_slot_disk_device: Warning: both floppy0 and floppy1 were not found\n");
+ }
+}
+
+
+msx_slot_disk1_device::msx_slot_disk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : msx_slot_disk_device(mconfig, MSX_SLOT_DISK1, "MSX Internal floppy type 1", tag, owner, clock, "msx_slot_disk1", __FILE__)
+ , m_side_control(0)
+ , m_control(0)
+{
+}
+
+
+void msx_slot_disk1_device::device_start()
+{
+ msx_slot_disk_device::device_start();
+
+ save_item(NAME(m_side_control));
+ save_item(NAME(m_control));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_disk1_device::post_load), this));
+}
+
+
+void msx_slot_disk1_device::device_reset()
+{
+ m_fdc->dden_w(false);
+}
+
+
+void msx_slot_disk1_device::post_load()
+{
+ UINT8 data = m_control;
+
+ // To make sure the FDD busy led status gets set correctly
+ m_control ^= 0x40;
+
+ set_control(data);
+}
+
+
+void msx_slot_disk1_device::set_side_control(UINT8 data)
+{
+ m_side_control = data;
+
+ if (m_floppy)
+ {
+ m_floppy->ss_w(m_side_control & 0x01);
+ }
+}
+
+
+void msx_slot_disk1_device::set_control(UINT8 data)
+{
+ UINT8 old_m_control = m_control;
+
+ m_control = data;
+
+ switch (m_control & 0x03)
+ {
+ case 0:
+ case 2:
+ m_floppy = m_floppy0 ? m_floppy0->get_device() : NULL;
+ break;
+
+ case 1:
+ m_floppy = m_floppy1 ? m_floppy1->get_device() : NULL;
+ break;
+
+ default:
+ m_floppy = NULL;
+ break;
+ }
+
+ if (m_floppy)
+ {
+ m_floppy->mon_w((m_control & 0x80) ? 0 : 1);
+ m_floppy->ss_w(m_side_control & 0x01);
+ }
+
+ m_fdc->set_floppy(m_floppy);
+
+ if ((old_m_control ^ m_control) & 0x40)
+ {
+ set_led_status(machine(), 0, !(m_control & 0x40));
+ }
+}
+
+
+READ8_MEMBER(msx_slot_disk1_device::read)
+{
+ switch (offset)
+ {
+ case 0x7ff8:
+ case 0xbff8:
+ return m_fdc->status_r();
+
+ case 0x7ff9:
+ case 0xbff9:
+ return m_fdc->track_r();
+
+ case 0x7ffa:
+ case 0xbffa:
+ return m_fdc->sector_r();
+
+ case 0x7ffb:
+ case 0xbffb:
+ return m_fdc->data_r();
+
+ case 0x7ffc:
+ case 0xbffc:
+ return 0xfe | (m_side_control & 0x01);
+
+ case 0x7ffd:
+ case 0xbffd:
+ return ( m_control & 0x83 ) | 0x78;
+
+ case 0x7fff:
+ case 0xbfff:
+ return 0x3f | (m_fdc->intrq_r() ? 0 : 0x40) | (m_fdc->drq_r() ? 0 : 0x80);
+ }
+
+ return msx_slot_rom_device::read(space, offset);
+}
+
+
+WRITE8_MEMBER(msx_slot_disk1_device::write)
+{
+ switch (offset)
+ {
+ case 0x7ff8:
+ case 0xbff8:
+ m_fdc->cmd_w(data);
+ break;
+
+ case 0x7ff9:
+ case 0xbff9:
+ m_fdc->track_w(data);
+ break;
+
+ case 0x7ffa:
+ case 0xbffa:
+ m_fdc->sector_w(data);
+ break;
+
+ case 0x7ffb:
+ case 0xbffb:
+ m_fdc->data_w(data);
+ break;
+
+ case 0x7ffc:
+ case 0xbffc:
+ set_side_control(data);
+ break;
+
+ case 0x7ffd:
+ case 0xbffd:
+ set_control(data);
+ break;
+ }
+}
+
+
+msx_slot_disk2_device::msx_slot_disk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : msx_slot_disk_device(mconfig, MSX_SLOT_DISK2, "MSX Internal floppy type 2", tag, owner, clock, "msx_slot_disk2", __FILE__)
+ , m_control(0)
+{
+}
+
+
+void msx_slot_disk2_device::device_start()
+{
+ msx_slot_disk_device::device_start();
+
+ save_item(NAME(m_control));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_disk2_device::post_load), this));
+}
+
+
+void msx_slot_disk2_device::device_reset()
+{
+ m_fdc->dden_w(false);
+}
+
+
+void msx_slot_disk2_device::post_load()
+{
+ UINT8 data = m_control;
+
+ // To make sure the FDD busy led status gets set correctly
+ m_control ^= 0x40;
+
+ set_control(data);
+}
+
+
+void msx_slot_disk2_device::set_control(UINT8 data)
+{
+ UINT8 old_m_control = m_control;
+
+ m_control = data;
+
+ switch (m_control & 3)
+ {
+ case 1:
+ m_floppy = m_floppy0 ? m_floppy0->get_device() : NULL;
+ break;
+
+ case 2:
+ m_floppy = m_floppy1 ? m_floppy1->get_device() : NULL;
+ break;
+
+ default:
+ m_floppy = NULL;
+ break;
+ }
+
+ if (m_floppy)
+ {
+ m_floppy->mon_w((m_control & 0x08) ? 0 : 1);
+ m_floppy->ss_w((m_control & 0x04) ? 0 : 1);
+ }
+
+ m_fdc->set_floppy(m_floppy);
+
+ if ((old_m_control ^ m_control) & 0x40)
+ {
+ set_led_status(machine(), 0, !(m_control & 0x40));
+ }
+}
+
+
+READ8_MEMBER(msx_slot_disk2_device::read)
+{
+ switch (offset)
+ {
+ case 0x7fb8:
+ case 0xbfb8:
+ return m_fdc->status_r();
+
+ case 0x7fb9:
+ case 0xbfb9:
+ return m_fdc->track_r();
+
+ case 0x7fba:
+ case 0xbfba:
+ return m_fdc->sector_r();
+
+ case 0x7fbb:
+ case 0xbfbb:
+ return m_fdc->data_r();
+
+ case 0x7fbc:
+ case 0xbfbc:
+ return 0x3f | (m_fdc->drq_r() ? 0 : 0x40) | (m_fdc->intrq_r() ? 0x80 : 0);
+ }
+
+ return msx_slot_rom_device::read(space, offset);
+}
+
+
+WRITE8_MEMBER(msx_slot_disk2_device::write)
+{
+ switch (offset)
+ {
+ case 0x7fb8:
+ case 0xbfb8:
+ m_fdc->cmd_w(data);
+ break;
+
+ case 0x7fb9:
+ case 0xbfb9:
+ m_fdc->track_w(data);
+ break;
+
+ case 0x7fba:
+ case 0xbfba:
+ m_fdc->sector_w(data);
+ break;
+
+ case 0x7fbb:
+ case 0xbfbb:
+ m_fdc->data_w(data);
+ break;
+
+ case 0x7fbc:
+ case 0xbfbc:
+ set_control(data);
+ break;
+
+ default:
+ printf("Unmapped write writing %02x to %04x\n", data, offset);
+ break;
+ }
+}
+
diff --git a/src/emu/bus/msx_slot/disk.h b/src/emu/bus/msx_slot/disk.h
new file mode 100644
index 00000000000..afeff77d527
--- /dev/null
+++ b/src/emu/bus/msx_slot/disk.h
@@ -0,0 +1,97 @@
+#ifndef __MSX_SLOT_DISK_H
+#define __MSX_SLOT_DISK_H
+
+#include "bus/msx_slot/slot.h"
+#include "bus/msx_slot/rom.h"
+#include "machine/wd_fdc.h"
+#include "imagedev/flopdrv.h"
+#include "imagedev/floppy.h"
+
+
+extern const device_type MSX_SLOT_DISK1;
+extern const device_type MSX_SLOT_DISK2;
+
+
+#define MCFG_MSX_SLOT_DISK1_ADD(_tag, _startpage, _numpages, _region, _offset, _fdc_tag, _floppy0_tag, _floppy1_tag) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_DISK1, _startpage, _numpages) \
+ msx_slot_rom_device::set_rom_start(*device, _region, _offset); \
+ msx_slot_disk_device::set_fdc_tag(*device, _fdc_tag); \
+ msx_slot_disk_device::set_floppy0_tag(*device, _floppy0_tag); \
+ msx_slot_disk_device::set_floppy1_tag(*device, _floppy1_tag);
+
+#define MCFG_MSX_SLOT_DISK2_ADD(_tag, _startpage, _numpages, _region, _offset, _fdc_tag, _floppy0_tag, _floppy1_tag) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_DISK2, _startpage, _numpages) \
+ msx_slot_rom_device::set_rom_start(*device, _region, _offset); \
+ msx_slot_disk_device::set_fdc_tag(*device, _fdc_tag); \
+ msx_slot_disk_device::set_floppy0_tag(*device, _floppy0_tag); \
+ msx_slot_disk_device::set_floppy1_tag(*device, _floppy1_tag);
+
+
+class msx_slot_disk_device : public msx_slot_rom_device
+{
+public:
+ msx_slot_disk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ virtual void device_start();
+
+ // static configuration helpers
+ static void set_fdc_tag(device_t &device, const char *tag) { dynamic_cast<msx_slot_disk_device &>(device).m_fdc_tag = tag; }
+ static void set_floppy0_tag(device_t &device, const char *tag) { dynamic_cast<msx_slot_disk_device &>(device).m_floppy0_tag = tag; }
+ static void set_floppy1_tag(device_t &device, const char *tag) { dynamic_cast<msx_slot_disk_device &>(device).m_floppy1_tag = tag; }
+
+protected:
+ wd_fdc_analog_t *m_fdc;
+ floppy_connector *m_floppy0;
+ floppy_connector *m_floppy1;
+ floppy_image_device *m_floppy;
+
+private:
+ const char *m_fdc_tag;
+ const char *m_floppy0_tag;
+ const char *m_floppy1_tag;
+};
+
+
+class msx_slot_disk1_device : public msx_slot_disk_device
+{
+public:
+ msx_slot_disk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void device_start();
+ virtual void device_reset();
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+ void post_load();
+
+private:
+ UINT8 m_side_control;
+ UINT8 m_control;
+
+ void set_control(UINT8 data);
+ void set_side_control(UINT8 data);
+};
+
+
+class msx_slot_disk2_device : public msx_slot_disk_device
+{
+public:
+ msx_slot_disk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void device_start();
+ virtual void device_reset();
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+ void post_load();
+
+private:
+ UINT8 m_control;
+
+ void set_control(UINT8 data);
+};
+
+#endif
+
diff --git a/src/emu/bus/msx_slot/fs4600.c b/src/emu/bus/msx_slot/fs4600.c
new file mode 100644
index 00000000000..76adbc65411
--- /dev/null
+++ b/src/emu/bus/msx_slot/fs4600.c
@@ -0,0 +1,162 @@
+/*
+ Emulation for the internal firmware mapper in the National FS-4600.
+*/
+
+#include "emu.h"
+#include "fs4600.h"
+
+
+const device_type MSX_SLOT_FS4600 = &device_creator<msx_slot_fs4600_device>;
+
+
+msx_slot_fs4600_device::msx_slot_fs4600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_SLOT_FS4600, "MSX Internal FS4600 Firmware", tag, owner, clock, "msx_slot_fs4600", __FILE__)
+ , msx_internal_slot_interface()
+ , m_nvram(*this, "nvram")
+ , m_region(NULL)
+ , m_region_offset(0)
+ , m_rom(NULL)
+ , m_sram_address(0)
+ , m_control(0)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_selected_bank[i] = 0;
+ m_bank_base[i] = 0;
+ }
+ memset(m_sram, 0, sizeof(m_sram));
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( fs4600 )
+ MCFG_NVRAM_ADD_0FILL("nvram")
+MACHINE_CONFIG_END
+
+
+machine_config_constructor msx_slot_fs4600_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( fs4600 );
+}
+
+
+void msx_slot_fs4600_device::set_rom_start(device_t &device, const char *region, UINT32 offset)
+{
+ msx_slot_fs4600_device &dev = downcast<msx_slot_fs4600_device &>(device);
+
+ dev.m_region = region;
+ dev.m_region_offset = offset;
+}
+
+
+void msx_slot_fs4600_device::device_start()
+{
+ assert(m_region != NULL );
+
+ memory_region *m_rom_region = owner()->memregion(m_region);
+
+ // Sanity checks
+ if (m_rom_region == NULL )
+ {
+ fatalerror("Rom slot '%s': Unable to find memory region '%s'\n", tag(), m_region);
+ }
+ if (m_rom_region->bytes() < m_region_offset + 0x100000)
+ {
+ fatalerror("Memory region '%s' is too small for the FS4600 firmware\n", m_region);
+ }
+
+ m_rom = m_rom_region->base() + m_region_offset;
+ m_nvram->set_base(m_sram, 0x1000);
+
+ save_item(NAME(m_selected_bank));
+ save_item(NAME(m_sram_address));
+ save_item(NAME(m_control));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_fs4600_device::restore_banks), this));
+
+ restore_banks();
+}
+
+
+void msx_slot_fs4600_device::restore_banks()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ m_bank_base[i] = m_rom + ( ( m_selected_bank[i] * 0x4000 ) & 0x0fffff );
+ }
+}
+
+
+READ8_MEMBER(msx_slot_fs4600_device::read)
+{
+ if ((m_control & 0x02) && ((offset & 0x3fff) == 0x3ffd))
+ {
+ return m_sram[m_sram_address++ & 0xfff];
+ }
+ if ((m_control & 0x04) && (offset& 0x7ff8) == 0x7ff0)
+ {
+ return m_selected_bank[(offset >> 1) & 0x03];
+ }
+ return m_bank_base[offset >> 14][offset & 0x3fff];
+}
+
+
+WRITE8_MEMBER(msx_slot_fs4600_device::write)
+{
+ if (offset == 0x7ff9)
+ {
+ m_control = data;
+ }
+ else
+ {
+ if (m_control & 0x02)
+ {
+ switch (offset & 0x3fff)
+ {
+ case 0x3ffa:
+ m_sram_address = (m_sram_address & 0x00ffff) | (data << 16);
+ break;
+
+ case 0x3ffb:
+ m_sram_address = (m_sram_address & 0xff00ff) | (data << 8);
+ break;
+
+ case 0x3ffc:
+ m_sram_address = (m_sram_address & 0xffff00) | data;
+ break;
+
+ case 0x3ffd:
+ m_sram[m_sram_address++ & 0xfff] = data;
+ break;
+
+ default:
+ logerror("Unhandled write %02x to %04x\n", data, offset);
+ break;
+ }
+ }
+ else
+ {
+ switch (offset)
+ {
+ case 0x6000:
+ m_selected_bank[1] = data;
+ m_bank_base[1] = m_rom + ( ( m_selected_bank[1] * 0x4000 ) & 0x0fffff );
+ break;
+
+ case 0x6400:
+ m_selected_bank[0] = data;
+ m_bank_base[0] = m_rom + ( ( m_selected_bank[0] * 0x4000 ) & 0x0fffff );
+ break;
+
+ case 0x7000:
+ m_selected_bank[2] = data;
+ m_bank_base[2] = m_rom + ( ( m_selected_bank[2] * 0x4000 ) & 0x0fffff );
+ break;
+
+ default:
+ logerror("Unhandled write %02x to %04x\n", data, offset);;
+ break;
+ }
+ }
+ }
+}
+
diff --git a/src/emu/bus/msx_slot/fs4600.h b/src/emu/bus/msx_slot/fs4600.h
new file mode 100644
index 00000000000..61f855e7a08
--- /dev/null
+++ b/src/emu/bus/msx_slot/fs4600.h
@@ -0,0 +1,45 @@
+#ifndef __MSX_SLOT_FS4600_H
+#define __MSX_SLOT_FS4600_H
+
+#include "slot.h"
+#include "machine/nvram.h"
+
+
+extern const device_type MSX_SLOT_FS4600;
+
+
+#define MCFG_MSX_SLOT_FS4600_ADD(_tag, _startpage, _numpages, _region, _offset) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_FS4600, _startpage, _numpages) \
+ msx_slot_fs4600_device::set_rom_start(*device, _region, _offset);
+
+class msx_slot_fs4600_device : public device_t,
+ public msx_internal_slot_interface
+{
+public:
+ msx_slot_fs4600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void set_rom_start(device_t &device, const char *region, UINT32 offset);
+
+ virtual void device_start();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+ void restore_banks();
+
+private:
+ required_device<nvram_device> m_nvram;
+ const char *m_region;
+ UINT32 m_region_offset;
+ const UINT8 *m_rom;
+ UINT8 m_selected_bank[4];
+ const UINT8 *m_bank_base[4];
+ UINT32 m_sram_address;
+ UINT8 m_sram[0x1000];
+ UINT8 m_control;
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_slot/music.c b/src/emu/bus/msx_slot/music.c
new file mode 100644
index 00000000000..77e8369fef4
--- /dev/null
+++ b/src/emu/bus/msx_slot/music.c
@@ -0,0 +1,69 @@
+#include "emu.h"
+#include "music.h"
+
+
+const device_type MSX_SLOT_MUSIC = &device_creator<msx_slot_music_device>;
+
+
+msx_slot_music_device::msx_slot_music_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : msx_slot_rom_device(mconfig, MSX_SLOT_MUSIC, "MSX Internal MSX-MUSIC", tag, owner, clock, "msx_slot_music", __FILE__)
+ , m_ym2413(NULL)
+ , m_ym2413_tag(NULL)
+ , m_opll_active(false)
+ , m_unlock(0)
+{
+}
+
+
+void msx_slot_music_device::device_start()
+{
+ msx_slot_rom_device::device_start();
+
+ if (m_ym2413_tag == NULL)
+ {
+ fatalerror("msx_slot_music_device: no YM2413 tag specified\n");
+ }
+
+ m_ym2413 = owner()->subdevice<ym2413_device>(m_ym2413_tag);
+
+ if (m_ym2413 == NULL)
+ {
+ fatalerror("msx_slot_ym2413_device: Unable to find YM2413 with tag '%s'\n", m_ym2413_tag);
+ }
+
+ // Install IO read/write handlers
+ address_space &space = machine().device<cpu_device>("maincpu")->space(AS_IO);
+ space.install_write_handler(0x7c, 0x7d, write8_delegate(FUNC(msx_slot_music_device::write_ym2413), this));
+}
+
+
+void msx_slot_music_device::device_reset()
+{
+ m_opll_active = false;
+}
+
+
+READ8_MEMBER(msx_slot_music_device::read)
+{
+ return msx_slot_rom_device::read(space, offset);
+}
+
+
+WRITE8_MEMBER(msx_slot_music_device::write)
+{
+ if (m_unlock == 0xbe && data == 0x41)
+ {
+ m_opll_active = true;
+ }
+ m_unlock = data;
+}
+
+
+WRITE8_MEMBER(msx_slot_music_device::write_ym2413)
+{
+ if (m_opll_active)
+ {
+ m_ym2413->write(space, offset & 1, data);
+ }
+}
+
diff --git a/src/emu/bus/msx_slot/music.h b/src/emu/bus/msx_slot/music.h
new file mode 100644
index 00000000000..0dda5bf779c
--- /dev/null
+++ b/src/emu/bus/msx_slot/music.h
@@ -0,0 +1,43 @@
+#ifndef __MSX_SLOT_MUSIC_H
+#define __MSX_SLOT_MUSIC_H
+
+
+#include "bus/msx_slot/slot.h"
+#include "bus/msx_slot/rom.h"
+#include "sound/2413intf.h"
+
+
+extern const device_type MSX_SLOT_MUSIC;
+
+
+#define MCFG_MSX_SLOT_MUSIC_ADD(_tag, _startpage, _numpages, _region, _offset, _ym2413_tag) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_MUSIC, _startpage, _numpages) \
+ msx_slot_rom_device::set_rom_start(*device, _region, _offset); \
+ msx_slot_music_device::set_ym2413_tag(*device, _ym2413_tag); \
+
+class msx_slot_music_device : public msx_slot_rom_device
+{
+public:
+ msx_slot_music_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void set_ym2413_tag(device_t &device, const char *tag) { dynamic_cast<msx_slot_music_device &>(device).m_ym2413_tag = tag; }
+
+ virtual void device_start();
+ virtual void device_reset();
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+ DECLARE_WRITE8_MEMBER(write_ym2413);
+
+private:
+ ym2413_device *m_ym2413;
+ const char *m_ym2413_tag;
+ bool m_opll_active;
+ UINT8 m_unlock;
+};
+
+
+#endif
+
diff --git a/src/emu/bus/msx_slot/panasonic08.c b/src/emu/bus/msx_slot/panasonic08.c
new file mode 100644
index 00000000000..af762c32cfa
--- /dev/null
+++ b/src/emu/bus/msx_slot/panasonic08.c
@@ -0,0 +1,176 @@
+/*
+
+ Emulation of the firmware mapper as found in Panasonic FS-A1WX andFS-A1WSX machines.
+
+Todo:
+- Anything besides the basic mapping
+- SRAM?
+*/
+
+#include "emu.h"
+#include "panasonic08.h"
+
+
+const device_type MSX_SLOT_PANASONIC08 = &device_creator<msx_slot_panasonic08_device>;
+
+
+msx_slot_panasonic08_device::msx_slot_panasonic08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_SLOT_PANASONIC08, "MSX Internal Panasonic08", tag, owner, clock, "msx_slot_panasonic08", __FILE__)
+ , msx_internal_slot_interface()
+ , m_region(NULL)
+ , m_region_offset(0)
+ , m_rom(NULL)
+ , m_control(0)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ m_selected_bank[i] = 0;
+ m_bank_base[i] = 0;
+ }
+ memset(m_sram, 0, sizeof(m_sram));
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( panasonic08 )
+MACHINE_CONFIG_END
+
+
+machine_config_constructor msx_slot_panasonic08_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( panasonic08 );
+}
+
+
+void msx_slot_panasonic08_device::set_rom_start(device_t &device, const char *region, UINT32 offset)
+{
+ msx_slot_panasonic08_device &dev = downcast<msx_slot_panasonic08_device &>(device);
+
+ dev.m_region = region;
+ dev.m_region_offset = offset;
+}
+
+
+void msx_slot_panasonic08_device::device_start()
+{
+ assert(m_region != NULL );
+
+ memory_region *m_rom_region = owner()->memregion(m_region);
+
+ // Sanity checks
+ if (m_rom_region == NULL )
+ {
+ fatalerror("Rom slot '%s': Unable to find memory region '%s'\n", tag(), m_region);
+ }
+ if (m_rom_region->bytes() < m_region_offset + 0x200000)
+ {
+ fatalerror("Memory region '%s' is too small for the FS4600 firmware\n", m_region);
+ }
+
+ m_rom = m_rom_region->base() + m_region_offset;
+
+ save_item(NAME(m_selected_bank));
+ save_item(NAME(m_control));
+ save_item(NAME(m_sram));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_panasonic08_device::restore_banks), this));
+
+ restore_banks();
+}
+
+
+void msx_slot_panasonic08_device::map_bank(int bank)
+{
+ if (m_selected_bank[bank] >= 0x80 && m_selected_bank[bank] < 0x84) // Are these banks were sram is present? Mirroring?
+ {
+ logerror("panasonic08: mapping bank %d to sram\n", bank);
+ m_bank_base[bank] = m_sram;
+ }
+ else
+ {
+ m_bank_base[bank] = m_rom + ( ( m_selected_bank[bank] * 0x2000 ) & 0x1fffff );
+ }
+}
+
+
+void msx_slot_panasonic08_device::restore_banks()
+{
+ for (int i = 0; i < 8; i++)
+ {
+ map_bank(i);
+ }
+}
+
+
+READ8_MEMBER(msx_slot_panasonic08_device::read)
+{
+ if (m_control & 0x04)
+ {
+ // 7ff0 - 6000
+ // 7ff1 - 6400
+ // 7ff2 - 6800
+ // 7ff3 - 6c00
+ // 7ff4 - 7000
+ // 7ff5 - 7800
+ if (offset >= 0x7ff0 && offset < 0x7ff6) // maybe 7ff8 would make more sense here??
+ {
+ return m_selected_bank[offset - 0x7ff0];
+ }
+ }
+ return m_bank_base[offset >> 13][offset & 0x1fff];
+}
+
+
+WRITE8_MEMBER(msx_slot_panasonic08_device::write)
+{
+ if ((offset & 0xc000) == 0x8000)
+ {
+ UINT8 bank = m_selected_bank[offset >> 13];
+ if (bank >= 0x80 && bank < 0x84) // Are these banks were sram is present? Mirroring?
+ {
+ logerror("panasonic08: writing %02x to sram %04x\n", data, offset & 0x1fff);
+ m_sram[offset & 0x1fff] = data;
+ }
+ }
+
+ switch (offset)
+ {
+ case 0x6000: /* Switched 0x0000-0x1FFF */
+ m_selected_bank[0] = data;
+ map_bank(0);
+ break;
+
+ case 0x6400: /* Switches 0x2000-0x3FFF */
+ m_selected_bank[1] = data;
+ map_bank(1);
+ break;
+
+ case 0x6800: /* Switches 0x4000-0x5FFF */
+ m_selected_bank[2] = data;
+ map_bank(2);
+ break;
+
+ case 0x6c00:
+ m_selected_bank[3] = data;
+ map_bank(3);
+ break;
+
+ case 0x7000: /* Switches 0x8000-0x9FFF */
+ m_selected_bank[4] = data;
+ map_bank(4);
+ break;
+
+ case 0x7800:
+ m_selected_bank[5] = data;
+ map_bank(5);
+ break;
+
+ case 0x7ff9:
+ m_control = data;
+ break;
+
+ default:
+ logerror("Unhandled write %02x to %04x\n", data, offset);
+ break;
+ }
+}
+
diff --git a/src/emu/bus/msx_slot/panasonic08.h b/src/emu/bus/msx_slot/panasonic08.h
new file mode 100644
index 00000000000..6eedae2d505
--- /dev/null
+++ b/src/emu/bus/msx_slot/panasonic08.h
@@ -0,0 +1,44 @@
+#ifndef __MSX_SLOT_PANASONIC08_H
+#define __MSX_SLOT_PANASONIC08_H
+
+#include "slot.h"
+
+
+extern const device_type MSX_SLOT_PANASONIC08;
+
+
+#define MCFG_MSX_SLOT_PANASONIC08_ADD(_tag, _startpage, _numpages, _region, _offset) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_PANASONIC08, _startpage, _numpages) \
+ msx_slot_panasonic08_device::set_rom_start(*device, _region, _offset);
+
+class msx_slot_panasonic08_device : public device_t,
+ public msx_internal_slot_interface
+{
+public:
+ msx_slot_panasonic08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void set_rom_start(device_t &device, const char *region, UINT32 offset);
+
+ virtual void device_start();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+ void restore_banks();
+
+private:
+ const char *m_region;
+ UINT32 m_region_offset;
+ const UINT8 *m_rom;
+ UINT8 m_selected_bank[8];
+ const UINT8 *m_bank_base[8];
+ UINT8 m_control;
+ UINT8 m_sram[0x2000];
+
+ void map_bank(int bank);
+};
+
+
+#endif
diff --git a/src/emu/bus/msx_slot/ram.c b/src/emu/bus/msx_slot/ram.c
new file mode 100644
index 00000000000..f3a46daf8dc
--- /dev/null
+++ b/src/emu/bus/msx_slot/ram.c
@@ -0,0 +1,36 @@
+
+
+#include "emu.h"
+#include "ram.h"
+
+const device_type MSX_SLOT_RAM = &device_creator<msx_slot_ram_device>;
+
+msx_slot_ram_device::msx_slot_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_SLOT_RAM, "MSX Internal RAM", tag, owner, clock, "msx_slot_ram", __FILE__)
+ , msx_internal_slot_interface()
+{
+}
+
+void msx_slot_ram_device::device_start()
+{
+ m_ram.resize(m_size);
+ save_item(NAME(m_ram));
+}
+
+READ8_MEMBER(msx_slot_ram_device::read)
+{
+ if ( offset >= m_start_address && offset < m_end_address )
+ {
+ return m_ram[ offset - m_start_address ];
+ }
+ return 0xFF;
+}
+
+WRITE8_MEMBER(msx_slot_ram_device::write)
+{
+ if ( offset >= m_start_address && offset < m_end_address )
+ {
+ m_ram[offset - m_start_address] = data;
+ }
+}
+
diff --git a/src/emu/bus/msx_slot/ram.h b/src/emu/bus/msx_slot/ram.h
new file mode 100644
index 00000000000..9f66808b234
--- /dev/null
+++ b/src/emu/bus/msx_slot/ram.h
@@ -0,0 +1,26 @@
+#ifndef __MSX_SLOT_RAM_H
+#define __MSX_SLOT_RAM_H
+
+#include "slot.h"
+
+#define MCFG_MSX_SLOT_RAM_ADD(_tag, _startpage, _numpages) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_RAM, _startpage, _numpages) \
+
+class msx_slot_ram_device : public device_t,
+ public msx_internal_slot_interface
+{
+public:
+ msx_slot_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void device_start();
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+private:
+ dynamic_array<UINT8> m_ram;
+};
+
+extern const device_type MSX_SLOT_RAM;
+
+#endif
diff --git a/src/emu/bus/msx_slot/ram_mm.c b/src/emu/bus/msx_slot/ram_mm.c
new file mode 100644
index 00000000000..3c5bc7b47a1
--- /dev/null
+++ b/src/emu/bus/msx_slot/ram_mm.c
@@ -0,0 +1,79 @@
+#include "emu.h"
+#include "ram_mm.h"
+
+const device_type MSX_SLOT_RAM_MM = &device_creator<msx_slot_ram_mm_device>;
+
+msx_slot_ram_mm_device::msx_slot_ram_mm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_SLOT_RAM_MM, "MSX Internal Memory Mapped RAM", tag, owner, clock, "msx_slot_ram_mm", __FILE__)
+ , msx_internal_slot_interface()
+ , m_total_size(0)
+ , m_bank_mask(0)
+ , m_ramio_set_bits(0)
+{
+}
+
+void msx_slot_ram_mm_device::device_start()
+{
+ // Valid mapper sizes are 64KB, 128KB, 256KB, 512KB, 1MB, 2MB, and 4MB */
+ switch (m_total_size)
+ {
+ case 64*1024: m_bank_mask = 0x03; break;
+ case 128*1024: m_bank_mask = 0x07; break;
+ case 256*1024: m_bank_mask = 0x0F; break;
+ case 512*1024: m_bank_mask = 0x1F; break;
+ case 1024*1024: m_bank_mask = 0x3F; break;
+ case 2048*1024: m_bank_mask = 0x7F; break;
+ case 4096*1024: m_bank_mask = 0xFF; break;
+ default: fatalerror("Invalid memory mapper size specified\n");
+ }
+
+ m_ram.resize(m_total_size);
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ m_bank_selected[i] = 3 -i;
+ m_bank_base[i] = m_ram + 0x4000 * m_bank_selected[i];
+ }
+
+ save_item(NAME(m_ram));
+ save_item(NAME(m_bank_selected));
+
+ machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_ram_mm_device::restore_banks), this));
+
+ // Install IO read/write handlers
+ address_space &space = machine().device<cpu_device>("maincpu")->space(AS_IO);
+ space.install_read_handler(0xFC, 0xFF, read8_delegate(FUNC(msx_slot_ram_mm_device::read_mapper_bank), this));
+ space.install_write_handler(0xFC, 0xFF, write8_delegate(FUNC(msx_slot_ram_mm_device::write_mapper_bank), this));
+}
+
+void msx_slot_ram_mm_device::restore_banks()
+{
+ for ( int i = 0; i < 3; i++ )
+ {
+ m_bank_base[i] = m_ram + 0x4000 * ( m_bank_selected[i] & m_bank_mask );
+ }
+}
+
+READ8_MEMBER(msx_slot_ram_mm_device::read)
+{
+ return m_bank_base[offset >> 14][offset & 0x3fff];
+}
+
+WRITE8_MEMBER(msx_slot_ram_mm_device::write)
+{
+ m_bank_base[offset >> 14][offset & 0x3fff] = data;
+}
+
+READ8_MEMBER(msx_slot_ram_mm_device::read_mapper_bank)
+{
+ return m_bank_selected[offset & 3] | m_ramio_set_bits;
+}
+
+WRITE8_MEMBER(msx_slot_ram_mm_device::write_mapper_bank)
+{
+ offset &= 3;
+
+ m_bank_selected[offset] = data;
+ m_bank_base[offset] = m_ram + 0x4000 * ( m_bank_selected[offset] & m_bank_mask );
+}
+
diff --git a/src/emu/bus/msx_slot/ram_mm.h b/src/emu/bus/msx_slot/ram_mm.h
new file mode 100644
index 00000000000..5027fa428e1
--- /dev/null
+++ b/src/emu/bus/msx_slot/ram_mm.h
@@ -0,0 +1,44 @@
+#ifndef __MSX_SLOT_RAM_MM_H
+#define __MSX_SLOT_RAM_MM_H
+
+#include "slot.h"
+
+#define MCFG_MSX_SLOT_RAM_MM_ADD(_tag, _total_size) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_RAM_MM, 0, 4) \
+ msx_slot_ram_mm_device::set_total_size(*device, _total_size);
+
+#define MCFG_MSX_SLOT_RAMM_SET_RAMIO_BITS(_ramio_set_bits) \
+ msx_slot_ram_mm_device::set_ramio_set_bits(*device, _ramio_set_bits);
+
+class msx_slot_ram_mm_device : public device_t
+ , public msx_internal_slot_interface
+{
+public:
+ msx_slot_ram_mm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ static void set_total_size(device_t &device, UINT32 total_size) { dynamic_cast<msx_slot_ram_mm_device &>(device).m_total_size = total_size; }
+ static void set_ramio_set_bits(device_t &device, UINT8 ramio_set_bits) { dynamic_cast<msx_slot_ram_mm_device &>(device).m_ramio_set_bits = ramio_set_bits; }
+
+ virtual void device_start();
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+ DECLARE_READ8_MEMBER(read_mapper_bank);
+ DECLARE_WRITE8_MEMBER(write_mapper_bank);
+
+ void restore_banks();
+
+private:
+ dynamic_array<UINT8> m_ram;
+ UINT32 m_total_size;
+ UINT8 m_bank_mask;
+ UINT8 m_bank_selected[4];
+ UINT8 *m_bank_base[4];
+ UINT8 m_ramio_set_bits;
+};
+
+extern const device_type MSX_SLOT_RAM_MM;
+
+#endif
+
diff --git a/src/emu/bus/msx_slot/rom.c b/src/emu/bus/msx_slot/rom.c
new file mode 100644
index 00000000000..fcae656ac41
--- /dev/null
+++ b/src/emu/bus/msx_slot/rom.c
@@ -0,0 +1,66 @@
+#include "emu.h"
+#include "rom.h"
+
+
+const device_type MSX_SLOT_ROM = &device_creator<msx_slot_rom_device>;
+
+
+msx_slot_rom_device::msx_slot_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MSX_SLOT_ROM, "MSX Internal ROM", tag, owner, clock, "msx_slot_rom", __FILE__)
+ , msx_internal_slot_interface()
+ , m_region(NULL)
+ , m_region_offset(0)
+ , m_rom(NULL)
+{
+}
+
+
+msx_slot_rom_device::msx_slot_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
+ : device_t(mconfig, type, name, tag, owner, clock, shortname, source)
+ , msx_internal_slot_interface()
+ , m_region(NULL)
+ , m_region_offset(0)
+ , m_rom(NULL)
+{
+}
+
+
+void msx_slot_rom_device::set_rom_start(device_t &device, const char *region, UINT32 offset)
+{
+ msx_slot_rom_device &dev = downcast<msx_slot_rom_device &>(device);
+
+ dev.m_region = region;
+ dev.m_region_offset = offset;
+}
+
+
+void msx_slot_rom_device::device_start()
+{
+ assert(m_region != NULL );
+
+ memory_region *m_rom_region = owner()->memregion(m_region);
+
+ // Sanity checks
+ if (m_rom_region == NULL )
+ {
+ fatalerror("Rom slot '%s': Unable to find memory region '%s'\n", tag(), m_region);
+ }
+ if (m_rom_region->bytes() < m_region_offset + m_size)
+ {
+ fatalerror("Memory region '%s' is too small for rom slot '%s'\n", m_region, tag());
+ }
+
+ m_rom = m_rom_region->base() + m_region_offset;
+}
+
+
+READ8_MEMBER(msx_slot_rom_device::read)
+{
+ if ( offset >= m_start_address && offset < m_end_address )
+ {
+ return m_rom[ offset - m_start_address ];
+ }
+ return 0xFF;
+}
+
+
diff --git a/src/emu/bus/msx_slot/rom.h b/src/emu/bus/msx_slot/rom.h
new file mode 100644
index 00000000000..dfed30f902d
--- /dev/null
+++ b/src/emu/bus/msx_slot/rom.h
@@ -0,0 +1,32 @@
+#ifndef __MSX_SLOT_ROM_H
+#define __MSX_SLOT_ROM_H
+
+#include "slot.h"
+
+#define MCFG_MSX_SLOT_ROM_ADD(_tag, _startpage, _numpages, _region, _offset) \
+ MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_ROM, _startpage, _numpages) \
+ msx_slot_rom_device::set_rom_start(*device, _region, _offset);
+
+class msx_slot_rom_device : public device_t,
+ public msx_internal_slot_interface
+{
+public:
+ msx_slot_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+ msx_slot_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void set_rom_start(device_t &device, const char *region, UINT32 offset);
+
+ virtual void device_start();
+
+ virtual DECLARE_READ8_MEMBER(read);
+
+private:
+ const char *m_region;
+ UINT32 m_region_offset;
+ const UINT8 *m_rom;
+};
+
+extern const device_type MSX_SLOT_ROM;
+
+#endif
diff --git a/src/emu/bus/msx_slot/slot.c b/src/emu/bus/msx_slot/slot.c
new file mode 100644
index 00000000000..ad8b08634ec
--- /dev/null
+++ b/src/emu/bus/msx_slot/slot.c
@@ -0,0 +1,35 @@
+/***********************************************************************************************************
+
+ MSX (logical) internal slot interfacing
+
+The MSX standard uses logically defined slots, subslots, and pages to access rom and optional components
+in a system. There are no physical slots inside the system. A piece of rom/component can occur in multiple
+pages; and multiple pieces of rom/ram/components can occur in a single slot.
+
+***********************************************************************************************************/
+
+#include "emu.h"
+#include "slot.h"
+
+msx_internal_slot_interface::msx_internal_slot_interface()
+ : m_start_address(0)
+ , m_size(0)
+ , m_end_address(0)
+{
+}
+
+void msx_internal_slot_interface::set_start_address(device_t &device, UINT32 start_address)
+{
+ msx_internal_slot_interface &dev = dynamic_cast<msx_internal_slot_interface &>(device);
+ dev.m_start_address = start_address;
+ dev.m_end_address = dev.m_start_address + dev.m_size;
+}
+
+void msx_internal_slot_interface::set_size(device_t &device, UINT32 size)
+{
+ msx_internal_slot_interface &dev = dynamic_cast<msx_internal_slot_interface &>(device);
+
+ dev.m_size = size;
+ dev.m_end_address = dev.m_start_address + dev.m_size;
+}
+
diff --git a/src/emu/bus/msx_slot/slot.h b/src/emu/bus/msx_slot/slot.h
new file mode 100644
index 00000000000..3ddf36a038f
--- /dev/null
+++ b/src/emu/bus/msx_slot/slot.h
@@ -0,0 +1,37 @@
+/***********************************************************************************************************
+
+ MSX (logical) internal slot/page interfacing
+
+The MSX standard uses logically defined slots, subslots, and pages to access rom and optional components
+in a system. There are no physical slots inside the system. A piece of rom/component can occur in multiple
+pages; and multiple pieces of rom/ram/components can occur in a single slot.
+
+***********************************************************************************************************/
+
+#ifndef __MSX_SLOT_SLOT_H
+#define __MSX_SLOT_SLOT_H
+
+#define MCFG_MSX_INTERNAL_SLOT_ADD(_tag, _type, _startpage, _numpages) \
+ MCFG_DEVICE_ADD(_tag, _type, 0) \
+ msx_internal_slot_interface::set_start_address(*device, _startpage * 0x4000); \
+ msx_internal_slot_interface::set_size(*device, _numpages * 0x4000);
+
+class msx_internal_slot_interface
+{
+public:
+ msx_internal_slot_interface();
+
+ // static configuration helpers
+ static void set_start_address(device_t &device, UINT32 start_address);
+ static void set_size(device_t &device, UINT32 size);
+
+ virtual DECLARE_READ8_MEMBER(read) { return 0xFF; }
+ virtual DECLARE_WRITE8_MEMBER(write) { }
+
+protected:
+ UINT32 m_start_address;
+ UINT32 m_size;
+ UINT32 m_end_address;
+};
+
+#endif