summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/bus/snes
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2014-03-10 08:29:46 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2014-03-10 08:29:46 +0000
commit69e33bcb5ed9a375db6e7f3bc5a266f6731cc8d0 (patch)
tree60f4091511c2f33a76d5f4712271e6bfb8db7e8b /src/emu/bus/snes
parentbd205461703fffbacc1afe0c8a7c1c29786f39aa (diff)
snes and nes slot devices moved into bus folder (nw)
Diffstat (limited to 'src/emu/bus/snes')
-rw-r--r--src/emu/bus/snes/bsx.c545
-rw-r--r--src/emu/bus/snes/bsx.h149
-rw-r--r--src/emu/bus/snes/event.c286
-rw-r--r--src/emu/bus/snes/event.h55
-rw-r--r--src/emu/bus/snes/rom.c517
-rw-r--r--src/emu/bus/snes/rom.h207
-rw-r--r--src/emu/bus/snes/rom21.c265
-rw-r--r--src/emu/bus/snes/rom21.h65
-rw-r--r--src/emu/bus/snes/sa1.c1141
-rw-r--r--src/emu/bus/snes/sa1.h111
-rw-r--r--src/emu/bus/snes/sdd1.c618
-rw-r--r--src/emu/bus/snes/sdd1.h185
-rw-r--r--src/emu/bus/snes/sfx.c149
-rw-r--r--src/emu/bus/snes/sfx.h48
-rw-r--r--src/emu/bus/snes/sgb.c293
-rw-r--r--src/emu/bus/snes/sgb.h76
-rw-r--r--src/emu/bus/snes/snes_carts.c50
-rw-r--r--src/emu/bus/snes/snes_carts.h29
-rw-r--r--src/emu/bus/snes/snes_slot.c1397
-rw-r--r--src/emu/bus/snes/snes_slot.h275
-rw-r--r--src/emu/bus/snes/spc7110.c1681
-rw-r--r--src/emu/bus/snes/spc7110.h224
-rw-r--r--src/emu/bus/snes/sufami.c163
-rw-r--r--src/emu/bus/snes/sufami.h51
-rw-r--r--src/emu/bus/snes/upd.c567
-rw-r--r--src/emu/bus/snes/upd.h221
26 files changed, 9368 insertions, 0 deletions
diff --git a/src/emu/bus/snes/bsx.c b/src/emu/bus/snes/bsx.c
new file mode 100644
index 00000000000..1efa7378d25
--- /dev/null
+++ b/src/emu/bus/snes/bsx.c
@@ -0,0 +1,545 @@
+/***********************************************************************************************************
+
+ BS-X Satellaview cartridge emulation (for SNES/SFC)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***********************************************************************************************************/
+
+
+// TODO: Emulate FLASH memory... (possibly using flash device?)
+
+
+#include "emu.h"
+#include "bsx.h"
+
+
+//-------------------------------------------------
+// sns_rom_bsx_device - constructor
+//-------------------------------------------------
+
+const device_type SNS_ROM_BSX = &device_creator<sns_rom_bsx_device>;
+const device_type SNS_LOROM_BSX = &device_creator<sns_rom_bsxlo_device>;
+const device_type SNS_HIROM_BSX = &device_creator<sns_rom_bsxhi_device>;
+const device_type SNS_BSMEMPAK = &device_creator<sns_rom_bsmempak_device>;
+
+
+sns_rom_bsx_device::sns_rom_bsx_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)
+ : sns_rom_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_slot(*this, "bs_slot")
+{
+}
+
+sns_rom_bsx_device::sns_rom_bsx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_ROM_BSX, "SNES BS-X Cart", tag, owner, clock, "sns_rom_bsx", __FILE__),
+ m_slot(*this, "bs_slot")
+{
+}
+
+sns_rom_bsxlo_device::sns_rom_bsxlo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_BSX, "SNES Cart (LoROM) + BS-X slot", tag, owner, clock, "sns_rom_bsxlo", __FILE__),
+ m_slot(*this, "bs_slot")
+{
+}
+
+sns_rom_bsxhi_device::sns_rom_bsxhi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom21_device(mconfig, SNS_HIROM_BSX, "SNES Cart (HiROM) + BS-X slot", tag, owner, clock, "sns_rom_bsxhi", __FILE__),
+ m_slot(*this, "bs_slot")
+{
+}
+
+sns_rom_bsmempak_device::sns_rom_bsmempak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_BSMEMPAK, "SNES BS-X Memory packs", tag, owner, clock, "sns_bsmempak", __FILE__)
+{
+}
+
+
+void sns_rom_bsx_device::device_start()
+{
+ m_base_unit = auto_alloc(machine(), BSX_base(machine()));
+ m_base_unit->init();
+
+ memset(m_cart_regs, 0x00, sizeof(m_cart_regs));
+ m_cart_regs[7] = 0x80;
+ m_cart_regs[8] = 0x80;
+ access_update();
+
+ save_item(NAME(m_cart_regs));
+ save_item(NAME(access_00_1f));
+ save_item(NAME(access_80_9f));
+ save_item(NAME(access_40_4f));
+ save_item(NAME(access_50_5f));
+ save_item(NAME(access_60_6f));
+ save_item(NAME(rom_access));
+ save_item(NAME(m_pram));
+}
+
+void sns_rom_bsx_device::device_reset()
+{
+ memset(m_pram, 0xff, sizeof(m_pram));
+}
+
+void sns_rom_bsxlo_device::device_start()
+{
+}
+
+void sns_rom_bsxhi_device::device_start()
+{
+}
+
+void sns_rom_bsmempak_device::device_start()
+{
+ save_item(NAME(m_command));
+ save_item(NAME(m_write_old));
+ save_item(NAME(m_write_new));
+ save_item(NAME(m_flash_enable));
+ save_item(NAME(m_read_enable));
+ save_item(NAME(m_write_enable));
+}
+
+void sns_rom_bsmempak_device::device_reset()
+{
+ m_command = 0;
+ m_write_old = 0;
+ m_write_new = 0;
+
+ m_flash_enable = 0;
+ m_read_enable = 0;
+ m_write_enable = 0;
+}
+
+
+
+// BS-X Base Unit emulation, to be device-fied ?
+
+BSX_base::BSX_base(running_machine &machine)
+ : m_machine(machine)
+{
+ state_save_register_item(machine, "SNES_BSX", NULL, 0, regs);
+ state_save_register_item(machine, "SNES_BSX", NULL, 0, r2192_counter);
+ state_save_register_item(machine, "SNES_BSX", NULL, 0, r2192_hour);
+ state_save_register_item(machine, "SNES_BSX", NULL, 0, r2192_second);
+}
+
+void BSX_base::init()
+{
+ memset(regs, 0x00, sizeof(regs));
+ r2192_counter = 0;
+ r2192_hour = 0;
+ r2192_minute = 0;
+ r2192_second = 0;
+}
+
+
+UINT8 BSX_base::read(UINT32 offset)
+{
+ offset &= 0xffff;
+ if (offset < 0x2188 || offset >= 0x21a0)
+ {
+ mame_printf_debug("BS-X Base Unit reg read outside correct range!\n");
+ return 0x00;
+ }
+
+ switch (offset)
+ {
+ // no 218b? no 218d? no 2191? no 2195? no 219a-219f?
+ case 0x2192:
+ {
+ UINT8 counter = r2192_counter++;
+ if (r2192_counter >= 18)
+ r2192_counter = 0;
+
+ if (counter == 0)
+ {
+ system_time curtime, *systime = &curtime;
+ m_machine.current_datetime(curtime);
+ r2192_hour = systime->local_time.hour;
+ r2192_minute = systime->local_time.minute;
+ r2192_second = systime->local_time.second;
+ }
+
+ switch (counter)
+ {
+ case 0: return 0x00; //???
+ case 1: return 0x00; //???
+ case 2: return 0x00; //???
+ case 3: return 0x00; //???
+ case 4: return 0x00; //???
+ case 5: return 0x01;
+ case 6: return 0x01;
+ case 7: return 0x00;
+ case 8: return 0x00;
+ case 9: return 0x00;
+ case 10: return r2192_second;
+ case 11: return r2192_minute;
+ case 12: return r2192_hour;
+ case 13: return 0x00; //???
+ case 14: return 0x00; //???
+ case 15: return 0x00; //???
+ case 16: return 0x00; //???
+ case 17: return 0x00; //???
+ }
+ }
+ break;
+
+ case 0x2193:
+ return regs[offset - 0x2188] & ~0x0c;
+
+ default:
+ return regs[offset - 0x2188];
+ }
+
+ return 0x00;
+}
+
+
+void BSX_base::write(UINT32 offset, UINT8 data)
+{
+ offset &= 0xffff;
+ if (offset < 0x2188 || offset >= 0x21a0)
+ {
+ mame_printf_debug("BS-X Base Unit reg write outside correct range!\n");
+ return;
+ }
+
+ switch(offset)
+ {
+ // no 218d? no 2190? no 2195? no 2196? no 2198? no 219a-219f?
+ case 0x218f:
+ regs[6] >>= 1; // 0x218e
+ regs[6] = regs[7] - regs[6]; // 0x218f - 0x218e
+ regs[7] >>= 1; // 0x218f
+ break;
+
+ case 0x2191:
+ regs[offset - 0x2188] = data;
+ r2192_counter = 0;
+ break;
+
+ case 0x2192:
+ regs[8] = data; // sets 0x2190
+ break;
+
+ default:
+ regs[offset - 0x2188] = data;
+ break;
+ }
+}
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( bs_slot )
+//-------------------------------------------------
+
+static SLOT_INTERFACE_START(bsx_cart)
+ SLOT_INTERFACE_INTERNAL("bsmempak", SNS_BSMEMPAK)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( bs_slot )
+ MCFG_SNS_BSX_CARTRIDGE_ADD("bs_slot", bsx_cart, NULL)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor sns_rom_bsx_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( bs_slot );
+}
+
+machine_config_constructor sns_rom_bsxlo_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( bs_slot );
+}
+
+machine_config_constructor sns_rom_bsxhi_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( bs_slot );
+}
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+// BS-X base + cart
+
+void sns_rom_bsx_device::access_update()
+{
+ access_00_1f = BIT(m_cart_regs[0x07], 7);
+ access_40_4f = !BIT(m_cart_regs[0x05], 7);
+ access_50_5f = !BIT(m_cart_regs[0x06], 7);
+ access_60_6f = BIT(m_cart_regs[0x03], 7);
+ access_80_9f = BIT(m_cart_regs[0x08], 7);
+ if (BIT(m_cart_regs[0x01], 7))
+ rom_access = 0;
+ else
+ {
+// rom_access = BIT(m_cart_regs[0x02], 7) + 1;
+ rom_access = 1; // for whatever reason bsxsore changes access mode here and then fails to read the ROM properly!
+ printf("rom_access %s\n", !BIT(m_cart_regs[0x02], 7) ? "Lo" : "Hi");
+ }
+}
+
+READ8_MEMBER(sns_rom_bsx_device::read_l)
+{
+ if (offset < 0x200000 && access_00_1f)
+ {
+ // 0x00-0x1f:0x8000-0xffff -> CART
+ if (m_slot->m_cart && m_slot->m_cart->get_rom_size())
+ return m_slot->m_cart->read_l(space, offset);
+ }
+ if (offset >= 0x200000 && offset < 0x400000)
+ {
+ // 0x20-0x3f:0x6000-0x7fff -> PRAM
+ if ((offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)
+ return m_pram[offset & 0xffff];
+ }
+ if (offset >= 0x400000 && offset < 0x500000 && access_40_4f)
+ {
+ // 0x40-0x4f:0x0000-0xffff -> PRAM
+ return m_pram[offset & 0x7ffff];
+ }
+ if (offset >= 0x500000 && offset < 0x600000 && access_50_5f)
+ {
+ // 0x50-0x5f:0x0000-0xffff -> PRAM
+ return m_pram[offset & 0x7ffff];
+ }
+ if (offset >= 0x600000 && offset < 0x700000 && access_60_6f)
+ {
+ // 0x60-0x6f:0x0000-0xffff -> PRAM
+ return m_pram[offset & 0x7ffff];
+ }
+ if (offset >= 0x700000 && offset < 0x780000)
+ {
+ // 0x70-0x77:0x0000-0xffff -> PRAM
+ return m_pram[offset & 0x7ffff];
+ }
+
+ // if not in any of the cases above...
+ //$00-3f|80-bf:8000-ffff
+ //$40-7f|c0-ff:0000-ffff
+ if (!rom_access)
+ return m_pram[offset & 0x7ffff];
+ else
+ {
+ int bank = (rom_access == 1) ? (offset / 0x10000) : (offset / 0x8000);
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+
+ return 0x00;
+}
+
+
+READ8_MEMBER(sns_rom_bsx_device::read_h)
+{
+ if (offset < 0x200000 && access_80_9f)
+ {
+ // 0x80-0x9f:0x8000-0xffff -> CART
+ if (m_slot->m_cart && m_slot->m_cart->get_rom_size())
+ return m_slot->m_cart->read_l(space, offset);
+ }
+
+ // if not in any of the cases above...
+ //$00-3f|80-bf:8000-ffff
+ //$40-7f|c0-ff:0000-ffff
+ if (!rom_access)
+ return m_pram[offset & 0x7ffff];
+ else
+ {
+ int bank = (rom_access == 1) ? (offset / 0x10000) : (offset / 0x8000);
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+
+ return 0x00;
+}
+
+WRITE8_MEMBER(sns_rom_bsx_device::write_l)
+{
+ if (offset < 0x200000 && access_00_1f)
+ {
+ // write to cart...
+ return;
+ }
+ if (offset >= 0x200000 && offset < 0x400000)
+ {
+ // 0x20-0x3f:0x6000-0x7fff -> PRAM
+ if ((offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)
+ m_pram[offset & 0xffff] = data;
+ }
+ if (offset >= 0x400000 && offset < 0x500000 && access_40_4f)
+ {
+ // 0x40-0x4f:0x0000-0xffff -> PRAM
+ m_pram[offset & 0x7ffff] = data;
+ }
+ if (offset >= 0x500000 && offset < 0x600000 && access_50_5f)
+ {
+ // 0x50-0x5f:0x0000-0xffff -> PRAM
+ m_pram[offset & 0x7ffff] = data;
+ }
+ if (offset >= 0x600000 && offset < 0x700000 && access_60_6f)
+ {
+ // 0x60-0x6f:0x0000-0xffff -> PRAM
+ m_pram[offset & 0x7ffff] = data;
+ }
+ if (offset >= 0x700000 && offset < 0x780000)
+ {
+ // 0x70-0x77:0x0000-0xffff -> PRAM
+ m_pram[offset & 0x7ffff] = data;
+ }
+
+ // if not in any of the cases above...
+ //$00-3f|80-bf:8000-ffff
+ //$40-7f|c0-ff:0000-ffff
+ if (!rom_access)
+ m_pram[offset & 0x7ffff] = data;
+}
+
+
+WRITE8_MEMBER(sns_rom_bsx_device::write_h)
+{
+ if (offset < 0x200000 && access_80_9f)
+ {
+ // write to cart...
+ return;
+ }
+
+ // if not in any of the cases above...
+ //$00-3f|80-bf:8000-ffff
+ //$40-7f|c0-ff:0000-ffff
+ if (!rom_access)
+ m_pram[offset & 0x7ffff] = data;
+}
+
+
+READ8_MEMBER(sns_rom_bsx_device::chip_read)
+{
+ if ((offset & 0xffff) >= 0x2188 && (offset & 0xffff) < 0x21a0)
+ return m_base_unit->read(offset & 0xffff);
+
+ if ((offset & 0xf0ffff) == 0x005000) //$[00-0f]:5000 reg access
+ {
+ UINT8 n = (offset >> 16) & 0x0f;
+ return m_cart_regs[n];
+ }
+
+ if ((offset & 0xf8f000) == 0x105000) //$[10-17]:[5000-5fff] SRAM access
+ {
+ return m_nvram[((offset >> 16) & 7) * 0x1000 + (offset & 0xfff)];
+ }
+
+ return 0x00;
+}
+
+WRITE8_MEMBER(sns_rom_bsx_device::chip_write)
+{
+ if ((offset & 0xffff) >= 0x2188 && (offset & 0xffff) < 0x21a0)
+ m_base_unit->write(offset & 0xffff, data);
+
+ if ((offset & 0xf0ffff) == 0x005000) //$[00-0f]:5000 reg access
+ {
+ UINT8 n = (offset >> 16) & 0x0f;
+ m_cart_regs[n] = data;
+ if (n == 0x0e && data & 0x80)
+ access_update();
+ }
+
+ if ((offset & 0xf8f000) == 0x105000) //$[10-17]:[5000-5fff] SRAM access
+ {
+ m_nvram[((offset >> 16) & 7) * 0x1000 + (offset & 0xfff)] = data;
+ }
+}
+
+
+// LoROM cart w/BS-X slot
+
+READ8_MEMBER(sns_rom_bsxlo_device::read_l)
+{
+ if (offset < 0x400000)
+ {
+ int bank = offset / 0x10000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ // nothing [40-6f]
+ // RAM [70-7f]
+ return 0x00;
+}
+
+READ8_MEMBER(sns_rom_bsxlo_device::read_h)
+{
+ if (offset < 0x400000)
+ {
+ int bank = offset / 0x10000;
+ if (offset < 0x200000)
+ bank += 64;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ else if (offset < 0x700000)
+ {
+ if (m_slot->m_cart && m_slot->m_cart->get_rom_size())
+ return m_slot->m_cart->read_h(space, offset);
+ }
+ // RAM [70-7f]
+ return 0x00;
+}
+
+
+// HiROM cart w/BS-X slot
+
+READ8_MEMBER(sns_rom_bsxhi_device::read_l)
+{
+ return read_h(space, offset);
+}
+
+READ8_MEMBER(sns_rom_bsxhi_device::read_h)
+{
+ if (offset < 0x200000 && (offset & 0xffff) >= 0x8000)
+ {
+ int bank = offset / 0x8000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ if (offset >= 0x200000 && offset < 0x400000)
+ {
+ if (m_slot->m_cart && m_slot->m_cart->get_rom_size() && (offset & 0xffff) >= 0x8000)
+ return m_slot->m_cart->read_h(space, offset);
+ }
+ if (offset >= 0x400000 && offset < 0x600000)
+ {
+ // TODO: Ongaku Tsukuru Kanadeeru does not like accesses in 0x0000-0x8000 here... investigate...
+ int bank = offset / 0x8000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ if (offset >= 0x600000)
+ {
+ if (m_slot->m_cart && m_slot->m_cart->get_rom_size())
+ return m_slot->m_cart->read_h(space, offset);
+ }
+ return 0xff;
+}
+
+/*-------------------------------------------------
+ BS-X Memory Packs
+ -------------------------------------------------*/
+
+// Here we're cheating a bit, for the moment, to avoid the need of BSX mempacks as a completely different device
+// which would require separate loading routines
+// Hence, we use low read handler for ROM access in the 0x8000-0xffff range (i.e. mempack mapped as LoROM) and
+// hi read handler for ROM access in the 0x0000-0xffff range (i.e. mempack mapped as HiROM)...
+
+READ8_MEMBER(sns_rom_bsmempak_device::read_l)
+{
+ int bank = offset / 0x10000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+}
+
+READ8_MEMBER(sns_rom_bsmempak_device::read_h)
+{
+ int bank = offset / 0x8000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+}
+
+WRITE8_MEMBER(sns_rom_bsmempak_device::write_l)
+{
+}
diff --git a/src/emu/bus/snes/bsx.h b/src/emu/bus/snes/bsx.h
new file mode 100644
index 00000000000..369b8e856f7
--- /dev/null
+++ b/src/emu/bus/snes/bsx.h
@@ -0,0 +1,149 @@
+#ifndef __SNS_BSX_H
+#define __SNS_BSX_H
+
+#include "snes_slot.h"
+#include "rom.h"
+#include "rom21.h"
+
+class BSX_base
+{
+public:
+ BSX_base(running_machine &machine);
+ running_machine &machine() const { return m_machine; }
+
+ void init();
+ UINT8 read(UINT32 offset);
+ void write(UINT32 offset, UINT8 data);
+
+private:
+ // regs
+ UINT8 regs[0x18]; // 0x2188-0x219f
+
+ // counter + clock
+ UINT8 r2192_counter;
+ UINT8 r2192_hour, r2192_minute, r2192_second;
+
+ running_machine& m_machine;
+};
+
+// ======================> sns_rom_bsx_device
+
+class sns_rom_bsx_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_bsx_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);
+ sns_rom_bsx_device(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;
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ // base regs
+ BSX_base *m_base_unit;
+
+ // cart regs
+ UINT8 m_cart_regs[16];
+ UINT8 access_00_1f; // 1 = CART, 0 = NOTHING
+ UINT8 access_80_9f; // 1 = CART, 0 = NOTHING
+ UINT8 access_40_4f; // 1 = NOTHING, 0 = PRAM
+ UINT8 access_50_5f; // 1 = NOTHING, 0 = PRAM
+ UINT8 access_60_6f; // 1 = PRAM, 0 = NOTHING
+ UINT8 rom_access; // 2 = HiROM, 1 = LoROM, 0 = PRAM
+ void access_update();
+
+
+ UINT8 m_pram[0x80000];
+
+private:
+ required_device<sns_bsx_cart_slot_device> m_slot;
+};
+
+// ======================> sns_rom_bsxlo_device
+
+class sns_rom_bsxlo_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_bsxlo_device(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;
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+
+private:
+ required_device<sns_bsx_cart_slot_device> m_slot;
+};
+
+// ======================> sns_rom_bsxhi_device
+
+class sns_rom_bsxhi_device : public sns_rom21_device
+{
+public:
+ // construction/destruction
+ sns_rom_bsxhi_device(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;
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+
+private:
+ required_device<sns_bsx_cart_slot_device> m_slot;
+};
+
+
+// ======================> sns_rom_bsmempak_device
+
+class sns_rom_bsmempak_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_bsmempak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+// virtual DECLARE_WRITE8_MEMBER(write_h);
+// virtual DECLARE_READ8_MEMBER(chip_read);
+// virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ // flash regs
+ UINT32 m_command;
+ UINT8 m_write_old;
+ UINT8 m_write_new;
+
+ int m_flash_enable;
+ int m_read_enable;
+ int m_write_enable;
+};
+
+
+// device type definition
+extern const device_type SNS_ROM_BSX;
+extern const device_type SNS_LOROM_BSX;
+extern const device_type SNS_HIROM_BSX;
+extern const device_type SNS_BSMEMPAK;
+
+#endif
diff --git a/src/emu/bus/snes/event.c b/src/emu/bus/snes/event.c
new file mode 100644
index 00000000000..9a05a1a5fb4
--- /dev/null
+++ b/src/emu/bus/snes/event.c
@@ -0,0 +1,286 @@
+/***********************************************************************************************************
+
+ Super NES/Famicom Event cartridges emulation (for SNES/SFC)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ TODO: figure out how the Test Mode switch works...
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "event.h"
+
+
+//-------------------------------------------------
+// sns_rom_device - constructor
+//-------------------------------------------------
+
+const device_type SNS_PFEST94 = &device_creator<sns_pfest94_device>;
+
+
+sns_pfest94_device::sns_pfest94_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SNS_PFEST94, "SNES Powerfest '94", tag, owner, clock, "sns_pfest94", __FILE__),
+ device_sns_cart_interface( mconfig, *this ),
+ m_upd7725(*this, "dsp"),
+ m_dsw(*this, "DIPSW")
+{
+}
+
+
+void sns_pfest94_device::device_start()
+{
+ m_dsp_prg = auto_alloc_array(machine(), UINT32, 0x2000/4);
+ m_dsp_data = auto_alloc_array(machine(), UINT16, 0x800/2);
+ pfest94_timer = timer_alloc(TIMER_EVENT);
+ pfest94_timer->reset();
+
+ save_item(NAME(m_base_bank));
+ save_item(NAME(m_mask));
+ save_item(NAME(m_status));
+ save_item(NAME(m_count));
+}
+
+void sns_pfest94_device::device_reset()
+{
+ m_base_bank = 0;
+ m_mask = 0x07;
+ m_status = 0;
+ m_count = 0;
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+READ8_MEMBER(sns_pfest94_device::read_l)
+{
+ // menu
+ if ((offset & 0x208000) == 0x208000)
+ {
+ int bank = ((offset - 0x200000) / 0x10000) & 7;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ else
+ {
+ // never called beyond 0x400000!
+ offset &= 0x1fffff;
+ int bank = (m_base_bank == 0x18) ? offset / 0x8000 : offset / 0x10000;
+ return m_rom[rom_bank_map[m_base_bank + (bank & m_mask)] * 0x8000 + (offset & 0x7fff)];
+ }
+}
+
+READ8_MEMBER(sns_pfest94_device::read_h)
+{
+ // menu
+ if ((offset & 0x208000) == 0x208000)
+ {
+ int bank = ((offset - 0x200000) / 0x8000) & 7;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+
+ // called beyond 0x400000!
+ if (offset < 0x400000)
+ {
+ offset &= 0x1fffff;
+ int bank = (m_base_bank == 0x18) ? offset / 0x8000 : offset / 0x10000;
+ return m_rom[rom_bank_map[m_base_bank + (bank & m_mask)] * 0x8000 + (offset & 0x7fff)];
+ }
+ else
+ {
+ offset &= 0x3fffff;
+ int bank = offset / 0x8000;
+ return m_rom[rom_bank_map[m_base_bank + (bank & m_mask)] * 0x8000 + (offset & 0x7fff)];
+ }
+}
+
+
+// these are used for two diff effects: both to select game from menu and to access the DSP when running SMK!
+READ8_MEMBER( sns_pfest94_device::chip_read )
+{
+ if (offset & 0x8000)
+ {
+ // menu access
+ return m_status;
+ }
+ else
+ {
+ // DSP access
+ offset &= 0x1fff;
+ return m_upd7725->snesdsp_read(offset < 0x1000);
+ }
+}
+
+
+WRITE8_MEMBER( sns_pfest94_device::chip_write )
+{
+ if (offset & 0x8000)
+ {
+ // menu access
+ if (data == 0x00)
+ {
+ m_base_bank = 0;
+ m_mask = 0x07;
+ }
+ if (data == 0x09)
+ {
+ m_base_bank = 0x08;
+ m_mask = 0x0f;
+ // start timer
+ m_count = (3 + ((m_dsw->read() & 0xf0) >> 4)) * 60;
+ pfest94_timer->adjust(attotime::zero, 0, attotime::from_seconds(1));
+ }
+ if (data == 0x0c)
+ {
+ m_base_bank = 0x18;
+ m_mask = 0x0f;
+ }
+ if (data == 0x0a)
+ {
+ m_base_bank = 0x28;
+ m_mask = 0x1f;
+ }
+ }
+ else
+ {
+ // DSP access
+ offset &= 0x1fff;
+ m_upd7725->snesdsp_write(offset < 0x1000, data);
+ }
+}
+
+
+//-------------------------------------------------
+// NEC DSP
+//-------------------------------------------------
+
+// helpers
+inline UINT32 get_prg(UINT8 *CPU, UINT32 addr)
+{
+ return ((CPU[addr * 4] << 24) | (CPU[addr * 4 + 1] << 16) | (CPU[addr * 4 + 2] << 8) | 0x00);
+}
+inline UINT16 get_data(UINT8 *CPU, UINT32 addr)
+{
+ return ((CPU[addr * 2] << 8) | CPU[addr * 2 + 1]);
+}
+
+void sns_pfest94_device::speedup_addon_bios_access()
+{
+ m_upd7725->space(AS_PROGRAM).install_read_bank(0x0000, 0x07ff, "dsp_prg");
+ m_upd7725->space(AS_DATA).install_read_bank(0x0000, 0x03ff, "dsp_data");
+ membank("dsp_prg")->set_base(m_dsp_prg);
+ membank("dsp_data")->set_base(m_dsp_data);
+ // copy data in the correct format
+ for (int x = 0; x < 0x800; x++)
+ m_dsp_prg[x] = (m_bios[x * 4] << 24) | (m_bios[x * 4 + 1] << 16) | (m_bios[x * 4 + 2] << 8) | 0x00;
+ for (int x = 0; x < 0x400; x++)
+ m_dsp_data[x] = (m_bios[0x2000 + x * 2] << 8) | m_bios[0x2000 + x * 2 + 1];
+}
+
+
+// DSP dump contains prg at offset 0 and data at offset 0x2000
+READ32_MEMBER( sns_pfest94_device::necdsp_prg_r )
+{
+ return get_prg(m_bios, offset);
+}
+
+READ16_MEMBER( sns_pfest94_device::necdsp_data_r )
+{
+ return get_data(m_bios, offset + 0x2000/2);
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( dsp_prg_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( dsp_prg_map_lorom, AS_PROGRAM, 32, sns_pfest94_device )
+ AM_RANGE(0x0000, 0x07ff) AM_READ(necdsp_prg_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( dsp_data_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( dsp_data_map_lorom, AS_DATA, 16, sns_pfest94_device )
+ AM_RANGE(0x0000, 0x03ff) AM_READ(necdsp_data_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( snes_dsp )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( snes_dsp_pfest94 )
+ MCFG_CPU_ADD("dsp", UPD7725, 8000000)
+ MCFG_CPU_PROGRAM_MAP(dsp_prg_map_lorom)
+ MCFG_CPU_DATA_MAP(dsp_data_map_lorom)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor sns_pfest94_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_pfest94 );
+}
+
+//-------------------------------------------------
+// Dipswicth
+//-------------------------------------------------
+
+static INPUT_PORTS_START( pfest94_dsw )
+ PORT_START("DIPSW")
+ PORT_DIPUNUSED(0x03, 0x00)
+ PORT_DIPNAME( 0x04, 0x00, "Test Mode" )
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( On ) )
+ PORT_DIPUNUSED(0x08, 0x08)
+ PORT_DIPNAME( 0xf0, 0x30, "Timer" )
+ PORT_DIPSETTING( 0x00, "3 Minutes" )
+ PORT_DIPSETTING( 0x10, "4 Minutes" )
+ PORT_DIPSETTING( 0x20, "5 Minutes" )
+ PORT_DIPSETTING( 0x30, "6 Minutes" )
+ PORT_DIPSETTING( 0x40, "7 Minutes" )
+ PORT_DIPSETTING( 0x50, "8 Minutes" )
+ PORT_DIPSETTING( 0x60, "9 Minutes" )
+ PORT_DIPSETTING( 0x70, "10 Minutes" )
+ PORT_DIPSETTING( 0x80, "11 Minutes" )
+ PORT_DIPSETTING( 0x90, "12 Minutes" )
+ PORT_DIPSETTING( 0xa0, "13 Minutes" )
+ PORT_DIPSETTING( 0xb0, "14 Minutes" )
+ PORT_DIPSETTING( 0xc0, "15 Minutes" )
+ PORT_DIPSETTING( 0xd0, "16 Minutes" )
+ PORT_DIPSETTING( 0xe0, "17 Minutes" )
+ PORT_DIPSETTING( 0xf0, "18 Minutes" )
+INPUT_PORTS_END
+
+
+ioport_constructor sns_pfest94_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( pfest94_dsw );
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void sns_pfest94_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_EVENT)
+ {
+ if (!m_count)
+ {
+ m_status |= 2;
+ pfest94_timer->reset();
+ }
+ m_count--;
+ }
+}
diff --git a/src/emu/bus/snes/event.h b/src/emu/bus/snes/event.h
new file mode 100644
index 00000000000..fd286c0f523
--- /dev/null
+++ b/src/emu/bus/snes/event.h
@@ -0,0 +1,55 @@
+#ifndef __SNS_EVENT_H
+#define __SNS_EVENT_H
+
+#include "snes_slot.h"
+#include "cpu/upd7725/upd7725.h"
+
+
+// ======================> sns_pfest94_device
+
+class sns_pfest94_device : public device_t,
+ public device_sns_cart_interface
+{
+public:
+ // construction/destruction
+ sns_pfest94_device(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 device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ required_device<upd7725_device> m_upd7725;
+ required_ioport m_dsw;
+
+ virtual void speedup_addon_bios_access();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ virtual DECLARE_READ32_MEMBER(necdsp_prg_r);
+ virtual DECLARE_READ16_MEMBER(necdsp_data_r);
+
+private:
+ UINT8 m_base_bank;
+ UINT8 m_mask;
+ UINT8 m_status;
+ UINT32 m_count;
+
+ UINT32 *m_dsp_prg;
+ UINT16 *m_dsp_data;
+
+ static const device_timer_id TIMER_EVENT = 0;
+ emu_timer *pfest94_timer;
+};
+
+
+// device type definition
+extern const device_type SNS_PFEST94;
+
+#endif
diff --git a/src/emu/bus/snes/rom.c b/src/emu/bus/snes/rom.c
new file mode 100644
index 00000000000..55f376ae856
--- /dev/null
+++ b/src/emu/bus/snes/rom.c
@@ -0,0 +1,517 @@
+/***********************************************************************************************************
+
+ Super NES/Famicom (LoROM) cartridge emulation (for SNES/SFC)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "rom.h"
+
+
+//-------------------------------------------------
+// sns_rom_device - constructor
+//-------------------------------------------------
+
+const device_type SNS_LOROM = &device_creator<sns_rom_device>;
+const device_type SNS_LOROM_OBC1 = &device_creator<sns_rom_obc1_device>;
+// LoROM pirate carts with protection
+const device_type SNS_LOROM_POKEMON = &device_creator<sns_rom_pokemon_device>;
+const device_type SNS_LOROM_TEKKEN2 = &device_creator<sns_rom_tekken2_device>;
+const device_type SNS_LOROM_SOULBLAD = &device_creator<sns_rom_soulblad_device>;
+const device_type SNS_LOROM_BANANA = &device_creator<sns_rom_banana_device>;
+const device_type SNS_LOROM_BUGSLIFE = &device_creator<sns_rom_bugs_device>;
+// LoROM pirate multicarts
+const device_type SNS_LOROM_MCPIR1 = &device_creator<sns_rom_mcpirate1_device>;
+const device_type SNS_LOROM_MCPIR2 = &device_creator<sns_rom_mcpirate2_device>;
+const device_type SNS_LOROM_20COL = &device_creator<sns_rom_20col_device>;
+
+
+sns_rom_device::sns_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),
+ device_sns_cart_interface( mconfig, *this )
+{
+}
+
+sns_rom_device::sns_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SNS_LOROM, "SNES Cart (LoROM)", tag, owner, clock, "sns_rom", __FILE__),
+ device_sns_cart_interface( mconfig, *this )
+{
+}
+
+sns_rom_obc1_device::sns_rom_obc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_OBC1, "SNES Cart (LoROM) + OBC-1", tag, owner, clock, "sns_rom_obc1", __FILE__)
+{
+}
+
+
+
+// Pirate LoROM 'mappers'
+sns_rom_pokemon_device::sns_rom_pokemon_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_POKEMON, "SNES Pirate Carts with Protection", tag, owner, clock, "sns_rom_pokemon", __FILE__)
+{
+}
+
+sns_rom_tekken2_device::sns_rom_tekken2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_TEKKEN2, "SNES Tekken 2", tag, owner, clock, "sns_rom_tekken2", __FILE__)
+{
+}
+
+sns_rom_soulblad_device::sns_rom_soulblad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_SOULBLAD, "SNES Soul Blade", tag, owner, clock, "sns_rom_soulblad", __FILE__)
+{
+}
+
+sns_rom_banana_device::sns_rom_banana_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_BANANA, "SNES Banana de Pijamas", tag, owner, clock, "sns_rom_banana", __FILE__)
+{
+}
+
+sns_rom_bugs_device::sns_rom_bugs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_BUGSLIFE, "SNES A Bug's Life", tag, owner, clock, "sns_rom_bugslife", __FILE__)
+{
+}
+
+// Multigame LoROM 'mappers'
+sns_rom_mcpirate1_device::sns_rom_mcpirate1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_MCPIR1, "SNES Pirate Multigame Carts Type 1", tag, owner, clock, "sns_rom_mcpirate1", __FILE__)
+{
+}
+
+sns_rom_mcpirate2_device::sns_rom_mcpirate2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_MCPIR2, "SNES Pirate Multigame Carts Type 2", tag, owner, clock, "sns_rom_mcpirate2", __FILE__)
+{
+}
+
+sns_rom_20col_device::sns_rom_20col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_20COL, "SNES Super 20 Collection", tag, owner, clock, "sns_rom_20col", __FILE__)
+{
+}
+
+
+void sns_rom_device::device_start()
+{
+}
+
+void sns_rom_obc1_device::device_start()
+{
+ save_item(NAME(m_ram));
+ save_item(NAME(m_address));
+ save_item(NAME(m_offset));
+ save_item(NAME(m_shift));
+}
+
+void sns_rom_obc1_device::device_reset()
+{
+ memset(m_ram, 0xff, sizeof(m_ram));
+ // or from rom?
+ m_offset = (m_ram[0x1ff5] & 0x01) ? 0x1800 : 0x1c00;
+ m_address = (m_ram[0x1ff6] & 0x7f);
+ m_shift = (m_ram[0x1ff6] & 0x03) << 1;
+}
+
+
+void sns_rom_pokemon_device::device_start()
+{
+ save_item(NAME(m_latch));
+}
+
+void sns_rom_pokemon_device::device_reset()
+{
+ m_latch = 0;
+}
+
+void sns_rom_tekken2_device::device_start()
+{
+ save_item(NAME(m_prot));
+}
+
+void sns_rom_tekken2_device::device_reset()
+{
+ m_prot = 0;
+}
+
+void sns_rom_bugs_device::device_start()
+{
+ save_item(NAME(m_latch));
+}
+
+void sns_rom_bugs_device::device_reset()
+{
+ memset(m_latch, 0, sizeof(m_latch));
+}
+
+
+
+void sns_rom_mcpirate1_device::device_start()
+{
+ m_base_bank = 0;
+ save_item(NAME(m_base_bank));
+}
+
+void sns_rom_mcpirate1_device::device_reset()
+{
+}
+
+void sns_rom_mcpirate2_device::device_start()
+{
+ m_base_bank = 0;
+ save_item(NAME(m_base_bank));
+}
+
+void sns_rom_mcpirate2_device::device_reset()
+{
+}
+
+void sns_rom_20col_device::device_start()
+{
+ m_base_bank = 4;
+ save_item(NAME(m_base_bank));
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+READ8_MEMBER(sns_rom_device::read_l)
+{
+ return read_h(space, offset);
+}
+
+READ8_MEMBER(sns_rom_device::read_h)
+{
+ int bank = offset / 0x10000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+}
+
+
+
+// Lo-ROM + OBC-1 (used by Metal Combat - Falcon's Revenge)
+// same as above but additional read/write handling for the add-on chip
+
+/***************************************************************************
+
+ Based on C++ implementation by Byuu in BSNES.
+
+ Byuu's code is released under GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ The implementation below is released under the MAME license
+ for use in MAME, MESS and derivatives by permission of Byuu
+
+ Copyright (for the implementation below) MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***********************************************************************************************************/
+
+
+READ8_MEMBER( sns_rom_obc1_device::chip_read )
+{
+ UINT16 address = offset & 0x1fff;
+ UINT8 value;
+
+ switch (address)
+ {
+ case 0x1ff0:
+ value = m_ram[m_offset + (m_address << 2) + 0];
+ break;
+
+ case 0x1ff1:
+ value = m_ram[m_offset + (m_address << 2) + 1];
+ break;
+
+ case 0x1ff2:
+ value = m_ram[m_offset + (m_address << 2) + 2];
+ break;
+
+ case 0x1ff3:
+ value = m_ram[m_offset + (m_address << 2) + 3];
+ break;
+
+ case 0x1ff4:
+ value = m_ram[m_offset + (m_address >> 2) + 0x200];
+ break;
+
+ default:
+ value = m_ram[address];
+ break;
+ }
+
+ return value;
+}
+
+
+WRITE8_MEMBER( sns_rom_obc1_device::chip_write )
+{
+ UINT16 address = offset & 0x1fff;
+ UINT8 temp;
+
+ switch(address)
+ {
+ case 0x1ff0:
+ m_ram[m_offset + (m_address << 2) + 0] = data;
+ break;
+
+ case 0x1ff1:
+ m_ram[m_offset + (m_address << 2) + 1] = data;
+ break;
+
+ case 0x1ff2:
+ m_ram[m_offset + (m_address << 2) + 2] = data;
+ break;
+
+ case 0x1ff3:
+ m_ram[m_offset + (m_address << 2) + 3] = data;
+ break;
+
+ case 0x1ff4:
+ temp = m_ram[m_offset + (m_address >> 2) + 0x200];
+ temp = (temp & ~(3 << m_shift)) | ((data & 0x03) << m_shift);
+ m_ram[m_offset + (m_address >> 2) + 0x200] = temp;
+ break;
+
+ case 0x1ff5:
+ m_offset = (data & 0x01) ? 0x1800 : 0x1c00;
+ m_ram[address & 0x1fff] = data;
+ break;
+
+ case 0x1ff6:
+ m_address = data & 0x7f;
+ m_shift = (data & 0x03) << 1;
+ m_ram[address & 0x1fff] = data;
+ break;
+
+ default:
+ m_ram[address & 0x1fff] = data;
+ break;
+ }
+}
+
+
+
+// Lo-ROM + Protection devices used in pirate carts
+
+
+// Pokemon (and many others): a byte is written and a permutation of its bits must be returned.
+// Address range for read/write depends on the game (check snes.xml)
+READ8_MEMBER( sns_rom_pokemon_device::chip_read )
+{
+ return BITSWAP8(m_latch,0,6,7,1,2,3,4,5);
+}
+
+WRITE8_MEMBER( sns_rom_pokemon_device::chip_write )
+{
+ m_latch = data;
+}
+
+
+// Tekken 2: It accesses the protection in a very strange way, always reading/writing the same data $f0 times,
+// because each access must be repeated a couple of times to be registered (typically around 7-30 times)
+// They probably used a microcontroller here.
+// The protection itself is accessed in banks $80-$bf. Accessing (read/write, doesn't matter) adress lines
+// A8,A9,A10 in these banks in a certain sequence makes the mc return a 4bit value. [d4s]
+// Details on a possible algorythm behind the sequence of accesses were provided by nocash. Thanks!
+void sns_rom_tekken2_device::update_prot(UINT32 offset)
+{
+ // accesses to [80-bf][8000-87ff] ranges update the protection value
+ offset &= 0x7ff;
+
+ switch (offset & 0x700)
+ {
+ case 0x000:
+ m_prot = 0;
+ break;
+ case 0x100:
+ // used for read access
+ break;
+ case 0x200: // BIT 0
+ m_prot |= 1;
+ break;
+ case 0x300: // BIT 1
+ m_prot |= 2;
+ break;
+ case 0x400: // BIT 2
+ m_prot |= 4;
+ break;
+ case 0x500: // BIT 3
+ m_prot |= 8;
+ break;
+ case 0x600: // DIRECTION
+ m_prot |= 0x10;
+ break;
+ case 0x700: // FUNCTION
+ m_prot |= 0x20;
+ break;
+ }
+}
+
+READ8_MEMBER( sns_rom_tekken2_device::chip_read )
+{
+ update_prot(offset);
+
+ if ((offset & 0x700) == 0x100)
+ {
+ if (BIT(m_prot, 5)) // FUNCTION = 1 means Shift
+ {
+ if (BIT(m_prot, 4)) // DIRECTION = 1 means Right
+ return (m_prot & 0x0f) >> 1;
+ else // DIRECTION = 0 means Left
+ return (m_prot & 0x0f) << 1;
+ }
+ else // FUNCTION = 0 means Add/Sub
+ {
+ if (BIT(m_prot, 4)) // DIRECTION = 1 means Minus
+ return (m_prot & 0x0f) - 1;
+ else // DIRECTION = 0 means Plus
+ return (m_prot & 0x0f) + 1;
+ }
+ }
+
+ return 0xff; // should be open_bus
+}
+
+WRITE8_MEMBER( sns_rom_tekken2_device::chip_write )
+{
+ update_prot(offset);
+}
+
+
+// Soul Blade: Adresses $xxx0-$xxx3 in banks $80-$bf always read $55, $0f, $aa, $f0.
+// Banks $c0-$ff return open bus.
+READ8_MEMBER( sns_rom_soulblad_device::chip_read )
+{
+ UINT8 value = 0;
+ offset &= 3;
+ switch (offset)
+ {
+ case 0:
+ default:
+ value = 0x55;
+ break;
+ case 1:
+ value = 0x0f;
+ break;
+ case 2:
+ value = 0xaa;
+ break;
+ case 3:
+ value = 0xf0;
+ break;
+ }
+ return value;
+}
+
+// Multicart pirate banking emulation
+// LoROM games, writes to [ff][ff00-ffff] control bankswitch
+// The actual banks depends on the last 8bits of the address accessed.
+
+// Type 1: bits0-4 of the address are used as base bank (256KB chunks)
+READ8_MEMBER(sns_rom_mcpirate1_device::read_l)
+{
+ return read_h(space, offset);
+}
+
+READ8_MEMBER(sns_rom_mcpirate1_device::read_h)
+{
+ int bank = (offset / 0x10000) + (m_base_bank * 8);
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+}
+
+WRITE8_MEMBER( sns_rom_mcpirate1_device::chip_write )
+{
+ m_base_bank = offset & 0x1f;
+// printf("offset %X data %X bank %X\n", offset, data, m_base_bank);
+}
+
+// Type 2: bits0-3 & bit5 of the address are used as base bank (256KB chunks)
+READ8_MEMBER(sns_rom_mcpirate2_device::read_l)
+{
+ return read_h(space, offset);
+}
+
+READ8_MEMBER(sns_rom_mcpirate2_device::read_h)
+{
+ int bank = (offset / 0x10000) + (m_base_bank * 8);
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+}
+
+WRITE8_MEMBER( sns_rom_mcpirate2_device::chip_write )
+{
+ m_base_bank = (offset & 0x0f) | ((offset & 0x20) >> 1);
+// printf("offset %X data %X bank %X\n", offset, data, m_base_bank);
+}
+
+// Korean 20 in 1 collection with NES games
+// - base bank is selected (in 32KB chunks) by bits 0-4 of data written at 0x808000
+// - bits 6-7 seem related to prg size: 0x00 means 4*32KB, 0xc0 means 2*32KB, 0x80 means 1*32KB
+// (they are used to setup how large is the ROM to be accessed, games 15-20 don't work well if
+// accesses in [01-3f] don't go to the only 32KB bank)
+// - bit 5 is always 0
+// it's worth to notice that for FC games size of bank is twice the size of original FC PRG
+READ8_MEMBER(sns_rom_20col_device::read_l)
+{
+ return read_h(space, offset);
+}
+
+READ8_MEMBER(sns_rom_20col_device::read_h)
+{
+ int prg32k = (!BIT(m_base_bank, 6) && BIT(m_base_bank, 7));
+ int bank = prg32k ? 0 : (offset / 0x10000);
+ return m_rom[((m_base_bank & 0x1f) + bank) * 0x8000 + (offset & 0x7fff)];
+}
+
+WRITE8_MEMBER( sns_rom_20col_device::chip_write )
+{
+ // [#] game - written bank value
+ // [01] spartan x - c6
+ // [02] smb - c8
+ // [03] antarcitc adv - 8e
+ // [04] twinbee - ca
+ // [05] battle city - 8f
+ // [06] circus charlie - 90
+ // [07] galaga - 91
+ // [08] yie ar kungfu - 92
+ // [09] star force - 93
+ // [10] road fighter - 94
+ // [11] pinball - 95
+ // [12] bomberman - 96
+ // [13] new tetris?? - 0
+ // [14] arkanoid - cc
+ // [15] balloon fight - 97
+ // [16] donkey kong - 98
+ // [17] donkey kong 3 - 99
+ // [18] donkey kong jr - 9a
+ // [19] mario bros - 9b
+ // [20] popeye - 9c
+ m_base_bank = data & 0xdf;
+// printf("offset %X data %X bank %X\n", offset, data, m_base_bank);
+}
+
+
+
+// Work in progress (probably very wrong)
+
+READ8_MEMBER( sns_rom_banana_device::chip_read )
+{
+ return BITSWAP8(m_latch[0xf],0,6,7,1,2,3,4,5);
+}
+
+WRITE8_MEMBER( sns_rom_banana_device::chip_write )
+{
+// printf("write addr %X data %X\n", offset, data);
+ m_latch[0xf] = data;
+}
+
+READ8_MEMBER( sns_rom_bugs_device::chip_read )
+{
+ return BITSWAP8(m_latch[offset & 0xff],0,6,7,1,2,3,4,5);
+}
+
+WRITE8_MEMBER( sns_rom_bugs_device::chip_write )
+{
+ m_latch[offset & 0xff] = data;
+}
diff --git a/src/emu/bus/snes/rom.h b/src/emu/bus/snes/rom.h
new file mode 100644
index 00000000000..2830f573434
--- /dev/null
+++ b/src/emu/bus/snes/rom.h
@@ -0,0 +1,207 @@
+#ifndef __SNS_ROM_H
+#define __SNS_ROM_H
+
+#include "snes_slot.h"
+
+
+// ======================> sns_rom_device
+
+class sns_rom_device : public device_t,
+ public device_sns_cart_interface
+{
+public:
+ // construction/destruction
+ sns_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);
+ sns_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+};
+
+// ======================> sns_rom_obc1_device
+
+class sns_rom_obc1_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_obc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ int m_address;
+ int m_offset;
+ int m_shift;
+ UINT8 m_ram[0x2000];
+};
+
+
+
+// ======================> sns_rom_pokemon_device
+
+class sns_rom_pokemon_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_pokemon_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read); // protection device
+ virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device
+ UINT8 m_latch;
+};
+
+// ======================> sns_rom_tekken2_device
+
+class sns_rom_tekken2_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_tekken2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read); // protection device
+ virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device
+
+ void update_prot(UINT32 offset);
+
+ // bit0-3 prot value, bit4 direction, bit5 function
+ // reads must return (prot value) +1/-1/<<1/>>1 depending on bit4 & bit5
+ UINT8 m_prot;
+};
+
+// ======================> sns_rom_soulblad_device
+
+class sns_rom_soulblad_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_soulblad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read); // protection device
+};
+
+// ======================> sns_rom_mcpirate1_device
+
+class sns_rom_mcpirate1_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_mcpirate1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device
+ UINT8 m_base_bank;
+};
+
+// ======================> sns_rom_mcpirate2_device
+
+class sns_rom_mcpirate2_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_mcpirate2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device
+ UINT8 m_base_bank;
+};
+
+// ======================> sns_rom_20col_device
+
+class sns_rom_20col_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_20col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device
+ UINT8 m_base_bank;
+};
+
+// ======================> sns_rom_banana_device
+
+class sns_rom_banana_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_banana_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+// virtual void device_start();
+// virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read); // protection device
+ virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device
+ UINT8 m_latch[16];
+};
+
+// ======================> sns_rom_bugs_device
+
+class sns_rom_bugs_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_bugs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read); // protection device
+ virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device
+ UINT8 m_latch[0x800];
+};
+
+
+// device type definition
+extern const device_type SNS_LOROM;
+extern const device_type SNS_LOROM_OBC1;
+extern const device_type SNS_LOROM_POKEMON;
+extern const device_type SNS_LOROM_TEKKEN2;
+extern const device_type SNS_LOROM_SOULBLAD;
+extern const device_type SNS_LOROM_MCPIR1;
+extern const device_type SNS_LOROM_MCPIR2;
+extern const device_type SNS_LOROM_20COL;
+extern const device_type SNS_LOROM_BANANA;
+extern const device_type SNS_LOROM_BUGSLIFE;
+
+#endif
diff --git a/src/emu/bus/snes/rom21.c b/src/emu/bus/snes/rom21.c
new file mode 100644
index 00000000000..5c991504579
--- /dev/null
+++ b/src/emu/bus/snes/rom21.c
@@ -0,0 +1,265 @@
+/***********************************************************************************************************
+
+ Super NES/Famicom (HiROM) cartridge emulation (for SNES/SFC)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "rom21.h"
+
+
+//-------------------------------------------------
+// sns_rom_device - constructor
+//-------------------------------------------------
+
+const device_type SNS_HIROM = &device_creator<sns_rom21_device>;
+const device_type SNS_HIROM_SRTC = &device_creator<sns_rom21_srtc_device>;
+
+
+sns_rom21_device::sns_rom21_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),
+ device_sns_cart_interface( mconfig, *this )
+{
+}
+
+sns_rom21_device::sns_rom21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SNS_HIROM, "SNES Cart (HiROM)", tag, owner, clock, "sns_rom21", __FILE__),
+ device_sns_cart_interface( mconfig, *this )
+{
+}
+
+sns_rom21_srtc_device::sns_rom21_srtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom21_device(mconfig, SNS_HIROM_SRTC, "SNES Cart (HiROM) + S-RTC", tag, owner, clock, "sns_rom21_srtc", __FILE__)
+{
+}
+
+
+void sns_rom21_device::device_start()
+{
+}
+
+void sns_rom21_device::device_reset()
+{
+}
+
+void sns_rom21_srtc_device::device_start()
+{
+ save_item(NAME(m_mode));
+ save_item(NAME(m_index));
+// save_item(NAME(m_rtc_ram));
+}
+
+void sns_rom21_srtc_device::device_reset()
+{
+ m_mode = RTCM_Read;
+ m_index = -1;
+// memset(m_rtc_ram, 0, sizeof(m_rtc_ram));
+
+// at this stage, rtc_ram is not yet allocated. this will be fixed when converting RTC to be a separate device.
+// update_time();
+}
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+// low and hi reads are not the same! (different ROM banks are accessed)
+
+READ8_MEMBER(sns_rom21_device::read_l)
+{
+ // here ROM banks from 128 to 255, mirrored twice
+ int bank = (offset & 0x3fffff) / 0x8000;
+ return m_rom[rom_bank_map[bank + 0x80] * 0x8000 + (offset & 0x7fff)];
+}
+
+READ8_MEMBER(sns_rom21_device::read_h)
+{
+ // here ROM banks from 0 to 127, mirrored twice
+ int bank = (offset & 0x3fffff) / 0x8000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+}
+
+
+// Hi-ROM + S-RTC (used by Daikaijuu Monogatari II)
+// same as above but additional read/write handling for the RTC
+/***************************************************************************
+
+ Based on C++ implementation by Byuu in BSNES.
+
+ Byuu's code is released under GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ The implementation below is released under the MAME license
+ for use in MAME, MESS and derivatives by permission of Byuu
+
+ Copyright (for the implementation below) MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***************************************************************************/
+
+static const UINT8 srtc_months[12] =
+{
+ 31, 28, 31,
+ 30, 31, 30,
+ 31, 31, 30,
+ 31, 30, 31
+};
+
+void sns_rom21_srtc_device::update_time()
+{
+ system_time curtime, *systime = &curtime;
+ machine().current_datetime(curtime);
+ m_rtc_ram[0] = systime->local_time.second % 10;
+ m_rtc_ram[1] = systime->local_time.second / 10;
+ m_rtc_ram[2] = systime->local_time.minute % 10;
+ m_rtc_ram[3] = systime->local_time.minute / 10;
+ m_rtc_ram[4] = systime->local_time.hour % 10;
+ m_rtc_ram[5] = systime->local_time.hour / 10;
+ m_rtc_ram[6] = systime->local_time.mday % 10;
+ m_rtc_ram[7] = systime->local_time.mday / 10;
+ m_rtc_ram[8] = systime->local_time.month;
+ m_rtc_ram[9] = (systime->local_time.year - 1000) % 10;
+ m_rtc_ram[10] = ((systime->local_time.year - 1000) / 10) % 10;
+ m_rtc_ram[11] = (systime->local_time.year - 1000) / 100;
+ m_rtc_ram[12] = systime->local_time.weekday % 7;
+}
+
+// Returns day-of-week for specified date
+// e.g. 0 = Sunday, 1 = Monday, ... 6 = Saturday
+// Usage: weekday(2008, 1, 1) returns the weekday of January 1st, 2008
+UINT8 sns_rom21_srtc_device::srtc_weekday( UINT32 year, UINT32 month, UINT32 day )
+{
+ UINT32 y = 1900, m = 1; // Epoch is 1900-01-01
+ UINT32 sum = 0; // Number of days passed since epoch
+
+ year = MAX(1900, year);
+ month = MAX(1, MIN(12, month));
+ day = MAX(1, MIN(31, day));
+
+ while (y < year)
+ {
+ UINT8 leapyear = 0;
+ if ((y % 4) == 0)
+ {
+ leapyear = 1;
+ if ((y % 100) == 0 && (y % 400) != 0)
+ {
+ leapyear = 0;
+ }
+ }
+ sum += leapyear ? 366 : 365;
+ y++;
+ }
+
+ while (m < month)
+ {
+ UINT32 days = srtc_months[m - 1];
+ if (days == 28)
+ {
+ UINT8 leapyear = 0;
+ if ((y % 4) == 0)
+ {
+ leapyear = 1;
+ if ((y % 100) == 0 && (y % 400) != 0)
+ {
+ leapyear = 0;
+ }
+ }
+ days += leapyear ? 1 : 0;
+ }
+ sum += days;
+ m++;
+ }
+
+ sum += day - 1;
+ return (sum + 1) % 7; // 1900-01-01 was a Monday
+}
+
+
+// this gets called only for accesses at 0x2800,
+// because for 0x2801 open bus gets returned...
+READ8_MEMBER(sns_rom21_srtc_device::chip_read)
+{
+ if (m_mode != RTCM_Read)
+ return 0x00;
+
+ if (m_index < 0)
+ {
+ update_time();
+ m_index++;
+ return 0x0f;
+ }
+ else if (m_index > 12)
+ {
+ m_index = -1;
+ return 0x0f;
+ }
+ else
+ return m_rtc_ram[m_index++];
+}
+
+// this gets called only for accesses at 0x2801
+WRITE8_MEMBER(sns_rom21_srtc_device::chip_write)
+{
+ data &= 0x0f; // Only the low four bits are used
+
+ if (data == 0x0d)
+ {
+ m_mode = RTCM_Read;
+ m_index = -1;
+ return;
+ }
+
+ if (data == 0x0e)
+ {
+ m_mode = RTCM_Command;
+ return;
+ }
+
+ if (data == 0x0f)
+ return; // Unknown behaviour
+
+ if (m_mode == RTCM_Write)
+ {
+ if (m_index >= 0 && m_index < 12)
+ {
+ m_rtc_ram[m_index++] = data;
+
+ if (m_index == 12)
+ {
+ // Day of week is automatically calculated and written
+ UINT32 day = m_rtc_ram[6] + m_rtc_ram[7] * 10;
+ UINT32 month = m_rtc_ram[8];
+ UINT32 year = m_rtc_ram[9] + m_rtc_ram[10] * 10 + m_rtc_ram[11] * 100;
+ year += 1000;
+
+ m_rtc_ram[m_index++] = srtc_weekday(year, month, day);
+ }
+ }
+ }
+ else if (m_mode == RTCM_Command)
+ {
+ if (data == 0)
+ {
+ m_mode = RTCM_Write;
+ m_index = 0;
+ }
+ else if (data == 4)
+ {
+ UINT8 i;
+ m_mode = RTCM_Ready;
+ m_index = -1;
+ for(i = 0; i < 13; i++)
+ m_rtc_ram[i] = 0;
+ }
+ else
+ {
+ // Unknown behaviour
+ m_mode = RTCM_Ready;
+ }
+ }
+}
diff --git a/src/emu/bus/snes/rom21.h b/src/emu/bus/snes/rom21.h
new file mode 100644
index 00000000000..d9738e0c035
--- /dev/null
+++ b/src/emu/bus/snes/rom21.h
@@ -0,0 +1,65 @@
+#ifndef __SNS_ROM21_H
+#define __SNS_ROM21_H
+
+#include "snes_slot.h"
+
+
+// ======================> sns_rom21_device
+
+class sns_rom21_device : public device_t,
+ public device_sns_cart_interface
+{
+public:
+ // construction/destruction
+ sns_rom21_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);
+ sns_rom21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+};
+
+// ======================> sns_rom21_srtc_device
+
+class sns_rom21_srtc_device : public sns_rom21_device
+{
+public:
+ // construction/destruction
+ sns_rom21_srtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ // S-RTC specific variables
+ enum
+ {
+ RTCM_Ready = 0,
+ RTCM_Command,
+ RTCM_Read,
+ RTCM_Write
+ };
+
+ void update_time();
+ UINT8 srtc_weekday(UINT32 year, UINT32 month, UINT32 day);
+
+ //this is now allocated in the main snes cart class, to allow saving to nvram
+ //UINT8 m_rtc_ram[13];
+ INT32 m_mode;
+ INT8 m_index;
+};
+
+
+// device type definition
+extern const device_type SNS_HIROM;
+extern const device_type SNS_HIROM_SRTC;
+
+#endif
diff --git a/src/emu/bus/snes/sa1.c b/src/emu/bus/snes/sa1.c
new file mode 100644
index 00000000000..872fe5ab52e
--- /dev/null
+++ b/src/emu/bus/snes/sa1.c
@@ -0,0 +1,1141 @@
+/***********************************************************************************************************
+
+ SA-1 add-on chip emulation (for SNES/SFC)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ Note:
+ - SA-1 register description below is based on no$cash docs.
+ - about bankswitch handling: no matter what is ROM size, at loading the ROM is mirrored up to 8MB and a
+ rom_bank_map[0x100] array is built as a lookup table for 256x32KB banks filling the 8MB accessible ROM
+ area; this allows to handle any 0-7 value written to CXB/DXB/EXB/FXB SA-1 registers without any masking!
+ - about BWRAM "bitmap mode": in 2bits mode
+ 600000h.Bit0-1 mirrors to 400000h.Bit0-1
+ 600001h.Bit0-1 mirrors to 400000h.Bit2-3
+ 600002h.Bit0-1 mirrors to 400000h.Bit4-5
+ 600003h.Bit0-1 mirrors to 400000h.Bit6-7
+ ...
+ in 4bits mode
+ 600000h.Bit0-3 mirrors to 400000h.Bit0-3
+ 600001h.Bit0-3 mirrors to 400000h.Bit4-7
+ 600002h.Bit0-3 mirrors to 400001h.Bit0-3
+ 600003h.Bit0-3 mirrors to 400001h.Bit4-7
+ ...
+ to handle the separate modes, bitmap accesses go to offset + 0x100000
+
+ TODO:
+ - test case for BWRAM & IRAM write protect (bsnes does not seem to ever protect either, so it's not implemented
+ for the moment)
+ - almost everything CPU related!
+
+ Compatibility:
+ asahishi: plays OK
+ daisenx2: plays OK
+ derbyjo2: hangs going into game
+ dbzhypd, dbzhypdj: plays OK
+ habumeij: boots, goes into game, on-screen timer counts down after SA-1 is enabled but controls aren't responsive
+ haruaug3a, pebble, haruaug3: uses SA-1 DMA
+ itoibass: boots, some missing gfx
+ jikkparo: plays OK
+ jl96drem: plays OK
+ jumpind: boots and runs, uses SA-1 normal DMA only but has corrupt gfx
+ kakinoki: S-CPU crashes after pressing start
+ kirby3j, kirby3: uses SA-1 DMA
+ kirbysdb, kirbyss, kirbyfun, kirbysd, kirbysda: plays OK
+ marvelou: plays OK, uses SA-1 normal DMA only but has corrupt gfx
+ miniyonk: plays OK
+ panicbw: plays OK
+ pgaeuro, pgaeurou, pga96, pga96u, pga, pgaj: plays OK
+ przeo, przeou: plays OK
+ prokishi: plays OK
+ rinkaiho: plays OK
+ saikouso: plays OK
+ sdf1gpp, sdf1gp: corrupt menu gfx, hangs going into game (I think)
+ sdgungnx: plays OK
+ shinshog: plays OK
+ shogisai: plays OK
+ shogisa2: plays OK
+ smrpgj, smrpg: needs SA-1 character conversion for level up Bonus Chance (possible to get past now)
+ srobotg: some corrupt in-game GFX, may be SNES rendering errors
+ sshogi3: plays OK
+ taikyoid: plays OK
+ takemiya: plays OK
+ [Note: for Igo & Shougi games, "plays OK" means you can get ingame and the CPU replies to your moves... subtle bugs
+ might indeed exist...]
+
+ ***********************************************************************************************************/
+
+#include "emu.h"
+#include "sa1.h"
+
+#define SA1_IRQ_SCPU (0x80)
+#define SA1_IRQ_TIMER (0x40)
+#define SA1_IRQ_DMA (0x20)
+#define SA1_NMI_SCPU (0x10)
+
+#define SCPU_IRQ_SA1 (0x80)
+#define SCPU_IRQV_ALT (0x40)
+#define SCPU_IRQ_CHARCONV (0x20)
+#define SCPU_NMIV_ALT (0x10)
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type SNS_LOROM_SA1 = &device_creator<sns_sa1_device>;
+
+
+sns_sa1_device::sns_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SNS_LOROM_SA1, "SNES Cart + SA-1", tag, owner, clock, "sns_rom_sa1", __FILE__),
+ device_sns_cart_interface( mconfig, *this ),
+ m_sa1(*this, "sa1cpu")
+{
+}
+
+
+void sns_sa1_device::device_start()
+{
+}
+
+void sns_sa1_device::device_reset()
+{
+ memset(m_internal_ram, 0, 0x800);
+
+ m_sa1_ctrl = 0x20;
+ m_scpu_ctrl = 0;
+ m_irq_vector = 0;
+ m_nmi_vector = 0;
+ m_hcount = 0;
+ m_vcount = 0;
+ m_bank_c_hi = 0;
+ m_bank_c_rom = 0;
+ m_bank_d_hi = 0;
+ m_bank_d_rom = 1;
+ m_bank_e_hi = 0;
+ m_bank_e_rom = 2;
+ m_bank_f_hi = 0;
+ m_bank_f_rom = 3;
+ m_bwram_snes = 0;
+ m_bwram_sa1 = 0;
+ m_bwram_sa1_source = 0;
+ m_bwram_sa1_format = 0;
+ m_bwram_write_snes = 1;
+ m_bwram_write_sa1 = 1;
+ m_bwpa_sa1 = 0x0f;
+ m_iram_write_snes = 1;
+ m_iram_write_sa1 = 1;
+ m_src_addr = 0;
+ m_dst_addr = 0;
+ memset(m_brf_reg, 0, 0x10);
+ m_math_ctlr = 0;
+ m_math_overflow = 0;
+ m_math_a = 0;
+ m_math_b = 0;
+ m_math_res = 0;
+ m_vda = 0;
+ m_vbit = 0;
+ m_vlen = 0;
+ m_drm = 0;
+ m_hcr = 0;
+ m_vcr = 0;
+ m_scpu_sie = m_sa1_sie = 0;
+ m_scpu_flags = m_sa1_flags = 0;
+ m_dma_ctrl = 0;
+ m_dma_ccparam = 0;
+ m_dma_cnt = 0;
+
+ // sa-1 CPU starts out not running?
+ m_sa1->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+void sns_sa1_device::recalc_irqs()
+{
+ if (m_scpu_flags & m_scpu_sie & (SCPU_IRQ_SA1|SCPU_IRQ_CHARCONV))
+ {
+ machine().device("maincpu")->execute().set_input_line(G65816_LINE_IRQ, ASSERT_LINE);
+ }
+ else
+ {
+ machine().device("maincpu")->execute().set_input_line(G65816_LINE_IRQ, CLEAR_LINE);
+ }
+
+ if (m_sa1_flags & m_sa1_sie & (SA1_IRQ_SCPU|SA1_IRQ_TIMER|SA1_IRQ_DMA))
+ {
+ m_sa1->set_input_line(G65816_LINE_IRQ, ASSERT_LINE);
+ }
+ else
+ {
+ m_sa1->set_input_line(G65816_LINE_IRQ, CLEAR_LINE);
+ }
+
+ if (m_sa1_flags & m_sa1_sie & SA1_NMI_SCPU)
+ {
+ m_sa1->set_input_line(G65816_LINE_NMI, ASSERT_LINE);
+ }
+ else
+ {
+ m_sa1->set_input_line(G65816_LINE_NMI, CLEAR_LINE);
+ }
+}
+
+
+/*-------------------------------------------------
+ RAM / SRAM / Registers
+ -------------------------------------------------*/
+
+
+// handle this separately to avoid accessing recursively the regs?
+
+UINT8 sns_sa1_device::var_length_read(address_space &space, UINT32 offset)
+{
+ // handle 0xffea/0xffeb/0xffee/0xffef
+ if ((offset & 0xffffe0) == 0x00ffe0)
+ {
+ if (offset == 0xffea && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 0) & 0xff;
+ if (offset == 0xffeb && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 8) & 0xff;
+ if (offset == 0xffee && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 0) & 0xff;
+ if (offset == 0xffef && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 8) & 0xff;
+ }
+
+ if ((offset & 0xc08000) == 0x008000) //$00-3f:8000-ffff
+ return read_l(space, (offset & 0x7fffff));
+
+ if ((offset & 0xc08000) == 0x808000) //$80-bf:8000-ffff
+ return read_h(space, (offset & 0x7fffff));
+
+ if ((offset & 0xc00000) == 0xc00000) //$c0-ff:0000-ffff
+ return read_h(space, (offset & 0x7fffff));
+
+ if ((offset & 0x40e000) == 0x006000) //$00-3f|80-bf:6000-7fff
+ return read_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff));
+
+ if ((offset & 0xf00000) == 0x400000) //$40-4f:0000-ffff
+ return read_bwram(offset & 0xfffff);
+
+ if ((offset & 0x40f800) == 0x000000) //$00-3f|80-bf:0000-07ff
+ return read_iram(offset);
+
+ if ((offset & 0x40f800) == 0x003000) //$00-3f|80-bf:3000-37ff
+ return read_iram(offset);
+
+ return 0;
+}
+
+void sns_sa1_device::dma_transfer(address_space &space)
+{
+// printf("DMA src %08x (%d), dst %08x (%d) cnt %d\n", m_src_addr, m_dma_ctrl & 3, m_dst_addr, m_dma_ctrl & 4, m_dma_cnt);
+
+ while (m_dma_cnt--)
+ {
+ UINT8 data = 0; // open bus?
+ UINT32 dma_src = m_src_addr++;
+ UINT32 dma_dst = m_dst_addr++;
+
+ // source and destination cannot be the same
+ // source = { 0=ROM, 1=BWRAM, 2=IRAM }
+ // destination = { 0=IRAM, 1=BWRAM }
+ if ((m_dma_ctrl & 0x03) == 1 && (m_dma_ctrl & 0x04) == 0x04) continue;
+ if ((m_dma_ctrl & 0x03) == 2 && (m_dma_ctrl & 0x04) == 0x00) continue;
+
+ switch (m_dma_ctrl & 0x03)
+ {
+ case 0: // ROM
+ if ((dma_src & 0x408000) == 0x008000 && (dma_src & 0x800000) == 0x000000)
+ {
+ data = read_l(space, (dma_src & 0x7fffff));
+ }
+ if ((dma_src & 0x408000) == 0x008000 && (dma_src & 0x800000) == 0x800000)
+ {
+ data = read_h(space, (dma_src & 0x7fffff));
+ }
+ if ((dma_src & 0xc00000) == 0xc00000)
+ {
+ data = read_h(space, (dma_src & 0x7fffff));
+ }
+ break;
+
+ case 1: // BWRAM
+ if ((dma_src & 0x40e000) == 0x006000)
+ {
+ data = read_bwram((m_bwram_sa1 * 0x2000) + (dma_src & 0x1fff));
+ }
+ if ((dma_src & 0xf00000) == 0x400000)
+ {
+ data = read_bwram(dma_src & 0xfffff);
+ }
+ break;
+
+ case 2: // IRAM
+ data = read_iram(dma_src);
+ break;
+ }
+
+ switch (m_dma_ctrl & 0x04)
+ {
+ case 0x00: // IRAM
+ write_iram(dma_dst, data);
+ break;
+
+ case 0x04: // BWRAM
+ if ((dma_dst & 0x40e000) == 0x006000)
+ {
+ write_bwram((m_bwram_sa1 * 0x2000) + (dma_dst & 0x1fff), data);
+ }
+ if ((dma_dst & 0xf00000) == 0x400000)
+ {
+ write_bwram(dma_dst & 0xfffff, data);
+ }
+ break;
+ }
+ }
+
+ m_sa1_flags |= SA1_IRQ_DMA;
+ recalc_irqs();
+}
+
+void sns_sa1_device::dma_cctype1_transfer(address_space &space)
+{
+ m_scpu_flags |= SCPU_IRQ_CHARCONV;
+ recalc_irqs();
+}
+
+void sns_sa1_device::dma_cctype2_transfer(address_space &space)
+{
+}
+
+UINT8 sns_sa1_device::read_regs(address_space &space, UINT32 offset)
+{
+ UINT8 value = 0xff;
+ offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs
+
+ switch (offset)
+ {
+ case 0x100:
+ // S-CPU Flag Read
+ value = (m_scpu_ctrl & 0x0f) | m_scpu_flags;
+ break;
+ case 0x101:
+ // SA-1 Flag Read
+ value = (m_sa1_ctrl & 0x0f) | m_sa1_flags;
+ break;
+ case 0x102:
+ // H-Count Read Low
+ //latch counters
+ m_hcr = m_hcount >> 2;
+ m_vcr = m_vcount;
+ //then return h-count
+ value = (m_hcr >> 0) & 0xff;
+ break;
+ case 0x103:
+ // H-Count Read High
+ value = (m_hcr >> 8) & 0xff;
+ break;
+ case 0x104:
+ // V-Count Read Low
+ value = (m_vcr >> 0) & 0xff;
+ break;
+ case 0x105:
+ // V-Count Read High
+ value = (m_vcr >> 8) & 0xff;
+ break;
+ case 0x106:
+ // Math Result bits0-7
+ value = (UINT64)(m_math_res >> 0) & 0xff;
+ break;
+ case 0x107:
+ // Math Result bits8-15
+ value = (UINT64)(m_math_res >> 8) & 0xff;
+ break;
+ case 0x108:
+ // Math Result bits16-23
+ value = (UINT64)(m_math_res >> 16) & 0xff;
+ break;
+ case 0x109:
+ // Math Result bits24-31
+ value = (UINT64)(m_math_res >> 24) & 0xff;
+ break;
+ case 0x10a:
+ // Math Result bits32-39
+ value = (UINT64)(m_math_res >> 32) & 0xff;
+ break;
+ case 0x10b:
+ // Math Overflow (above 40bit result)
+ value = m_math_overflow;
+ break;
+ case 0x10c:
+ // Var-Length Read Port Low
+ {
+ UINT32 data = (var_length_read(space, m_vda + 0) << 0) | (var_length_read(space, m_vda + 1) << 8)
+ | (var_length_read(space, m_vda + 2) << 16);
+ data >>= m_vbit;
+ value = (data >> 0) & 0xff;
+ }
+ break;
+ case 0x10d:
+ // Var-Length Read Port High
+ {
+ UINT32 data = (var_length_read(space, m_vda + 0) << 0) | (var_length_read(space, m_vda + 1) << 8)
+ | (var_length_read(space, m_vda + 2) << 16);
+ data >>= m_vbit;
+
+ if (m_drm == 1)
+ {
+ //auto-increment mode
+ m_vbit += m_vlen;
+ m_vda += (m_vbit >> 3);
+ m_vbit &= 7;
+ }
+
+ value = (data >> 8) & 0xff;
+ }
+ break;
+ case 0x10e:
+ // SNES VC Version Code Register (R)
+ break;
+ default:
+ logerror("SA-1 Read access to an unmapped reg (%x)", offset);
+ break;
+ }
+ return value;
+}
+
+void sns_sa1_device::write_regs(address_space &space, UINT32 offset, UINT8 data)
+{
+ offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs
+
+ switch (offset)
+ {
+ case 0x000:
+ // SA-1 control flags
+// printf("%02x to SA-1 control\n", data);
+ if ((BIT(data, 5)) && !(BIT(m_sa1_ctrl, 5)))
+ {
+// printf("Engaging SA-1 reset\n");
+ m_sa1->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+ }
+ else if (!(BIT(data, 5)) && (BIT(m_sa1_ctrl, 5)))
+ {
+// printf("Releasing SA-1 reset\n");
+ m_sa1->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
+ m_sa1->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+ m_sa1->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
+ }
+
+ m_sa1_ctrl = data;
+
+ // message to S-CPU
+ m_scpu_ctrl &= 0xf0;
+ m_scpu_ctrl |= (data & 0x0f);
+
+ if (BIT(m_sa1_ctrl, 7))
+ {
+ m_sa1_flags |= SA1_IRQ_SCPU;
+ }
+ if (BIT(m_sa1_ctrl, 4))
+ {
+ m_sa1_flags |= SA1_NMI_SCPU;
+ }
+ recalc_irqs();
+ break;
+ case 0x001:
+ // SNES SIE 00h SNES CPU Int Enable (W)
+ m_scpu_sie = data;
+// printf("S-CPU IE = %02x\n", data);
+ recalc_irqs();
+ break;
+ case 0x002:
+ // SNES SIC 00h SNES CPU Int Clear (W)
+ if (BIT(data, 7)) // ack IRQ from SA-1
+ {
+ m_scpu_flags &= ~SCPU_IRQ_SA1;
+ }
+ if (BIT(data, 5)) // ack character conversion IRQ
+ {
+ m_scpu_flags &= ~SCPU_IRQ_CHARCONV;
+ }
+ recalc_irqs();
+ break;
+ case 0x003:
+ // SNES CRV - SA-1 CPU Reset Vector Lsb (W)
+ m_sa1_reset &= 0xff00;
+ m_sa1_reset |= data;
+ break;
+ case 0x004:
+ // SNES CRV - SA-1 CPU Reset Vector Msb (W)
+ m_sa1_reset &= 0x00ff;
+ m_sa1_reset |= (data<<8);
+ break;
+ case 0x005:
+ // SNES CNV - SA-1 CPU NMI Vector Lsb (W)
+ m_sa1_nmi &= 0xff00;
+ m_sa1_nmi |= data;
+ break;
+ case 0x006:
+ // SNES CNV - SA-1 CPU NMI Vector Msb (W)
+ m_sa1_nmi &= 0x00ff;
+ m_sa1_nmi |= (data<<8);
+ break;
+ case 0x007:
+ // SNES CIV - SA-1 CPU IRQ Vector Lsb (W)
+ m_sa1_irq &= 0xff00;
+ m_sa1_irq |= data;
+ break;
+ case 0x008:
+ // SNES CIV - SA-1 CPU IRQ Vector Msb (W)
+ m_sa1_irq &= 0x00ff;
+ m_sa1_irq |= (data<<8);
+ break;
+ case 0x009:
+ // S-CPU control flags
+ m_scpu_ctrl = data;
+ if (m_scpu_ctrl & 0x80)
+ {
+ m_scpu_flags |= SCPU_IRQ_SA1;
+// printf("SA-1 cause S-CPU IRQ\n");
+ }
+
+ // message to SA-1
+ m_sa1_ctrl &= 0xf0;
+ m_sa1_ctrl |= (data & 0x0f);
+
+ // clear IRQ/NMI override flags in flags word
+ m_scpu_flags &= ~(SCPU_IRQV_ALT|SCPU_NMIV_ALT);
+
+ // and set them
+ m_scpu_flags |= (data & (SCPU_IRQV_ALT|SCPU_NMIV_ALT));
+
+ recalc_irqs();
+ break;
+ case 0x00a:
+ // SA-1 CIE 00h SA-1 CPU Int Enable (W)
+ m_sa1_sie = data;
+// printf("SA-1 IE = %02x\n", data);
+ recalc_irqs();
+ break;
+ case 0x00b:
+ // SA-1 CIC 00h SA-1 CPU Int Clear (W)
+ if (BIT(data, 7))
+ {
+ m_sa1_flags &= ~SA1_IRQ_SCPU;
+ }
+ if (BIT(data, 6))
+ {
+ m_sa1_flags &= ~SA1_IRQ_TIMER;
+ }
+ if (BIT(data, 5))
+ {
+ m_sa1_flags &= ~SA1_IRQ_DMA;
+ }
+ if (BIT(data, 4))
+ {
+ m_sa1_flags &= ~SA1_NMI_SCPU;
+ }
+ recalc_irqs();
+ break;
+ case 0x00c:
+ // NMI Vector Low
+ m_nmi_vector = (m_nmi_vector & 0xff00) | (data << 0);
+ break;
+ case 0x00d:
+ // NMI Vector High
+ m_nmi_vector = (m_nmi_vector & 0x00ff) | (data << 8);
+ break;
+ case 0x00e:
+ // IRQ Vector Low
+ m_irq_vector = (m_irq_vector & 0xff00) | (data << 0);
+ break;
+ case 0x00f:
+ // IRQ Vector High
+ m_irq_vector = (m_irq_vector & 0x00ff) | (data << 8);
+ break;
+ case 0x010:
+ // SA-1 TMC 00h H/V Timer Control (W)
+ break;
+ case 0x011:
+ // SA-1 CTR - SA-1 CPU Timer Restart (W)
+ break;
+ case 0x012:
+ // H-Count Low
+ m_hcount = (m_hcount & 0xff00) | (data << 0);
+ break;
+ case 0x013:
+ // H-Count High
+ m_hcount = (m_hcount & 0x00ff) | (data << 8);
+ break;
+ case 0x014:
+ // V-Count Low
+ m_vcount = (m_vcount & 0xff00) | (data << 0);
+ break;
+ case 0x015:
+ // V-Count High
+ m_vcount = (m_vcount & 0x00ff) | (data << 8);
+ break;
+ case 0x020:
+ // ROM 1MB bank for [c0-cf]
+ m_bank_c_hi = BIT(data, 7);
+ m_bank_c_rom = data & 0x07;
+ break;
+ case 0x021:
+ // ROM 1MB bank for [d0-df]
+ m_bank_d_hi = BIT(data, 7);
+ m_bank_d_rom = data & 0x07;
+ break;
+ case 0x022:
+ // ROM 1MB bank for [e0-ef]
+ m_bank_e_hi = BIT(data, 7);
+ m_bank_e_rom = data & 0x07;
+ break;
+ case 0x023:
+ // ROM 1MB bank for [f0-ff]
+ m_bank_f_hi = BIT(data, 7);
+ m_bank_f_rom = data & 0x07;
+ break;
+ case 0x024:
+ // BWRAM bank from SNES side
+ m_bwram_snes = data & 0x1f; // max 32x8K banks
+ break;
+ case 0x025:
+ // BWRAM bank & type from SA-1 side
+ m_bwram_sa1_source = BIT(data, 7); // 0 = normal, 1 = bitmap?
+ m_bwram_sa1 = data & 0x7f; // up to 128x8K banks here?
+ break;
+ case 0x026:
+ // enable writing to BWRAM from SNES
+ m_bwram_write_snes = BIT(data, 7);
+ break;
+ case 0x027:
+ // enable writing to BWRAM from SA-1
+ m_bwram_write_sa1 = BIT(data, 7);
+ break;
+ case 0x028:
+ // write protected area at bottom of BWRAM
+ m_bwpa_sa1 = 0x100 * (data & 0x0f);
+ break;
+ case 0x029:
+ // enable writing to IRAM from SNES (1 bit for each 0x100 chunk)
+ m_iram_write_snes = data;
+ break;
+ case 0x02a:
+ // enable writing to IRAM from SA-1 (1 bit for each 0x100 chunk)
+ m_iram_write_sa1 = data;
+ break;
+ case 0x030:
+ // SA-1 DCNT 00h DMA Control (W)
+// printf("%02x to SA-1 DMA control\n", data);
+ m_dma_ctrl = data;
+ break;
+ case 0x031:
+ // Both CDMA 00h Character Conversion DMA Parameters (W)
+ m_dma_ccparam = data;
+ break;
+ case 0x032:
+ // DMA Source Device Start Address Low
+ m_src_addr = (m_src_addr & 0xffff00) | (data << 0);
+ break;
+ case 0x033:
+ // DMA Source Device Start Address Mid
+ m_src_addr = (m_src_addr & 0xff00ff) | (data << 8);
+ break;
+ case 0x034:
+ // DMA Source Device Start Address High
+ m_src_addr = (m_src_addr & 0x00ffff) | (data << 16);
+ break;
+ case 0x035:
+ // DMA Dest Device Start Address Low
+ m_dst_addr = (m_dst_addr & 0xffff00) | (data << 0);
+ break;
+ case 0x036:
+ // DMA Dest Device Start Address Mid
+ m_dst_addr = (m_dst_addr & 0xff00ff) | (data << 8);
+ if (m_dma_ctrl & 0x80)
+ {
+ if (!(m_dma_ctrl & 0x20) && !(m_dma_ctrl & 0x04)) // Normal DMA to IRAM
+ {
+ dma_transfer(space);
+// printf("SA-1: normal DMA to IRAM\n");
+ }
+
+ if (m_dma_ctrl & 0x20 && m_dma_ctrl & 0x10) // CC DMA Type 1
+ {
+// printf("SA-1: CC DMA type 1\n");
+ dma_cctype1_transfer(space);
+ }
+ }
+ break;
+ case 0x037:
+ // DMA Dest Device Start Address High
+ m_dst_addr = (m_dst_addr & 0xffff00) | (data << 16);
+ if (m_dma_ctrl & 0x80)
+ {
+ if (!(m_dma_ctrl & 0x20) && m_dma_ctrl & 0x04) // Normal DMA to BWRAM
+ {
+// printf("SA-1: normal DMA to BWRAM\n");
+ dma_transfer(space);
+ }
+ }
+ break;
+ case 0x038:
+ // SA-1 DTC - DMA Terminal Counter Lsb (W)
+ m_dma_cnt &= 0xff00;
+ m_dma_cnt |= data;
+ break;
+ case 0x039:
+ // SA-1 DTC - DMA Terminal Counter Msb (W)
+ m_dma_cnt &= 0x00ff;
+ m_dma_cnt |= (data<<8);
+ break;
+ case 0x03f:
+ // Format for BWRAM when mapped to bitmap
+ m_bwram_sa1_format = BIT(data, 7); // 0 = 4bit, 1 = 2bit
+ break;
+ case 0x040:
+ case 0x041:
+ case 0x042:
+ case 0x043:
+ case 0x044:
+ case 0x045:
+ case 0x046:
+ case 0x047:
+ case 0x048:
+ case 0x049:
+ case 0x04a:
+ case 0x04b:
+ case 0x04c:
+ case 0x04d:
+ case 0x04e:
+ case 0x04f:
+ // Bit Map Register File (2240h..224Fh)
+ m_brf_reg[offset & 0x0f] = data;
+ if ((offset & 0x07) == 7 && m_dma_ctrl & 0x80)
+ {
+ if (m_dma_ctrl & 0x20 && !(m_dma_ctrl & 0x10)) // CC DMA Type 2
+ {
+// printf("SA-1: CC DMA type 2\n");
+ dma_cctype2_transfer(space);
+ }
+ }
+ break;
+ case 0x050:
+ // Math control
+ m_math_ctlr = data & 0x03;
+ if (data & 0x02)
+ m_math_res = 0;
+ break;
+ case 0x051:
+ // Math A Low
+ m_math_a = (m_math_a & 0xff00) | data;
+ break;
+ case 0x052:
+ // Math A High
+ m_math_a = (data << 8) | (m_math_a & 0x00ff);
+ break;
+ case 0x053:
+ // Math B Low
+ m_math_b = (m_math_b & 0xff00) | data;
+ break;
+ case 0x054:
+ // Math B High
+ m_math_b = (data << 8) | (m_math_b & 0x00ff);
+ // After Math B has been written, we do math
+ switch (m_math_ctlr)
+ {
+ case 0: //signed multiplication
+ m_math_res = (INT16)m_math_a * (INT16)m_math_b;
+ m_math_b = 0;
+ break;
+ case 1: //unsigned division
+ if (m_math_b == 0)
+ m_math_res = 0;
+ else
+ {
+ INT16 quotient = (INT16)m_math_a / (UINT16)m_math_b;
+ UINT16 remainder = (INT16)m_math_a % (UINT16)m_math_b;
+ m_math_res = (UINT64)((remainder << 16) | quotient);
+ }
+ break;
+ case 2: //sigma (accumulative multiplication)
+ case 3:
+ UINT64 acum = (INT16)m_math_a * (INT16)m_math_b;
+ UINT64 mask = U64(0xffffffffff);
+ m_math_res += acum;
+ m_math_overflow = (m_math_res > mask) ? 0x80 : 0;
+ m_math_res &= mask;
+ m_math_b = 0;
+ break;
+ }
+ break;
+ case 0x058:
+ // Var-Length Bit Processing
+ m_drm = BIT(data, 7); // Data Read Mode
+ m_vlen = (data & 0x0f);
+ if (m_vlen == 0)
+ m_vlen = 16;
+
+ if (m_drm == 0)
+ {
+ //fixed mode
+ m_vbit += m_vlen;
+ m_vda += (m_vbit >> 3);
+ m_vbit &= 7;
+ }
+ break;
+ case 0x059:
+ // Var-Length Read Start Address Low
+ m_vda = (m_vda & 0xffff00) | (data << 0);
+ break;
+ case 0x05a:
+ // Var-Length Read Start Address Mid
+ m_vda = (m_vda & 0xff00ff) | (data << 8);
+ break;
+ case 0x05b:
+ // Var-Length Read Start Address High
+ m_vda = (m_vda & 0x00ffff) | (data << 16);
+ m_vbit = 0;
+ break;
+ default:
+ logerror("SA-1 Write access to an unmapped reg (%x) with data %x", offset, data);
+ break;
+ }
+}
+
+UINT8 sns_sa1_device::read_iram(UINT32 offset)
+{
+ return m_internal_ram[offset & 0x7ff];
+}
+
+void sns_sa1_device::write_iram(UINT32 offset, UINT8 data)
+{
+ m_internal_ram[offset & 0x7ff] = data;
+}
+
+UINT8 sns_sa1_device::read_bwram(UINT32 offset)
+{
+ int shift = 0;
+ UINT8 mask = 0xff;
+
+ if (!m_nvram)
+ return 0xff; // this should probably never happen, or are there SA-1 games with no BWRAM?
+
+ if (offset < 0x100000)
+ return m_nvram[offset & (m_nvram_size - 1)];
+
+ // Bitmap BWRAM
+ offset -= 0x100000;
+
+ if (m_bwram_sa1_format)
+ {
+ // 2bits mode
+ offset /= 4;
+ shift = ((offset % 4) * 2);
+ mask = 0x03;
+ }
+ else
+ {
+ // 4bits mode
+ offset /= 2;
+ shift = ((offset % 2) * 4);
+ mask = 0x0f;
+ }
+
+ // only return the correct bits
+ return (m_nvram[offset & (m_nvram_size - 1)] >> shift) & mask;
+}
+
+void sns_sa1_device::write_bwram(UINT32 offset, UINT8 data)
+{
+ UINT8 mask = 0xff;
+
+ if (!m_nvram)
+ return; // this should probably never happen, or are there SA-1 games with no BWRAM?
+
+ if (offset < 0x100000)
+ {
+ m_nvram[offset & (m_nvram_size - 1)] = data;
+ return;
+ }
+
+ // Bitmap BWRAM
+ offset -= 0x100000;
+
+ if (m_bwram_sa1_format)
+ {
+ // 2bits mode
+ offset /= 4;
+ data = (data & 0x03) << ((offset % 4) * 2);
+ mask = 0x03 << ((offset % 4) * 2);
+ }
+ else
+ {
+ // 4bits mode
+ offset /= 2;
+ data = (data & 0x0f) << ((offset % 2) * 4);
+ mask = 0x0f << ((offset % 2) * 4);
+ }
+
+ // only change the correct bits, keeping the rest untouched
+ m_nvram[offset & (m_nvram_size - 1)] = (m_nvram[offset & (m_nvram_size - 1)] & ~mask) | data;
+}
+
+
+
+/*-------------------------------------------------
+ Accesses from SNES CPU
+ -------------------------------------------------*/
+
+
+READ8_MEMBER(sns_sa1_device::read_l)
+{
+ int bank = 0;
+
+ if (offset == 0xffea && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 0) & 0xff;
+ if (offset == 0xffeb && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 8) & 0xff;
+ if (offset == 0xffee && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 0) & 0xff;
+ if (offset == 0xffef && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 8) & 0xff;
+
+ // ROM is mapped to [00-3f][8000-ffff] only here
+ if (offset < 0x200000)
+ {
+ if (!m_bank_c_hi) // when HiROM mapping is disabled, we always access first 1MB here
+ bank = (offset / 0x10000) + 0x00;
+ else // when HiROM mapping is enabled, we mirror [c0-cf][0000-ffff] bank
+ bank = (offset / 0x10000) + (m_bank_c_rom * 0x20);
+
+ bank &= 0xff;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ else if (offset < 0x400000)
+ {
+ offset -= 0x200000;
+ if (!m_bank_d_hi) // when HiROM mapping is disabled, we always access second 1MB here
+ bank = (offset / 0x10000) + 0x20;
+ else // when HiROM mapping is enabled, we mirror [d0-df][0000-ffff] bank
+ bank = (offset / 0x10000) + (m_bank_d_rom * 0x20);
+
+ bank &= 0xff;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ else
+ return 0; // this should not happen (the driver should only call read_l in the above case)
+}
+
+READ8_MEMBER(sns_sa1_device::read_h)
+{
+ int bank = 0;
+
+ // ROM is mapped to [80-bf][8000-ffff] & [c0-ff][0000-ffff]
+ if (offset < 0x200000)
+ {
+ if (!m_bank_e_hi) // when HiROM mapping is disabled, we always access third 1MB here
+ bank = (offset / 0x10000) + 0x40;
+ else // when HiROM mapping is enabled, we mirror [e0-ef][0000-ffff] bank
+ bank = (offset / 0x10000) + (m_bank_e_rom * 0x20);
+
+ bank &= 0xff;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ else if (offset < 0x400000)
+ {
+ offset -= 0x200000;
+ if (!m_bank_f_hi) // when HiROM mapping is disabled, we always access fourth 1MB here
+ bank = (offset / 0x10000) + 0x60;
+ else // when HiROM mapping is enabled, we mirror [f0-ff][0000-ffff] bank
+ bank = (offset / 0x10000) + (m_bank_f_rom * 0x20);
+
+ bank &= 0xff;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ else if (offset < 0x500000)
+ return m_rom[rom_bank_map[(m_bank_c_rom * 0x20) + ((offset - 0x400000) / 0x8000)] * 0x8000 + (offset & 0x7fff)];
+ else if (offset < 0x600000)
+ return m_rom[rom_bank_map[(m_bank_d_rom * 0x20) + ((offset - 0x500000) / 0x8000)] * 0x8000 + (offset & 0x7fff)];
+ else if (offset < 0x700000)
+ return m_rom[rom_bank_map[(m_bank_e_rom * 0x20) + ((offset - 0x600000) / 0x8000)] * 0x8000 + (offset & 0x7fff)];
+ else
+ return m_rom[rom_bank_map[(m_bank_f_rom * 0x20) + ((offset - 0x700000) / 0x8000)] * 0x8000 + (offset & 0x7fff)];
+}
+
+WRITE8_MEMBER(sns_sa1_device::write_l)
+{
+}
+
+WRITE8_MEMBER(sns_sa1_device::write_h)
+{
+}
+
+READ8_MEMBER( sns_sa1_device::chip_read )
+{
+ UINT16 address = offset & 0xffff;
+
+ if (offset < 0x400000 && address >= 0x2200 && address < 0x2400)
+ return read_regs(space, address & 0x1ff); // SA-1 Regs
+
+ if (offset < 0x400000 && address >= 0x3000 && address < 0x3800)
+ return read_iram(address & 0x7ff); // Internal SA-1 RAM (2K)
+
+ if (offset < 0x400000 && address >= 0x6000 && address < 0x8000)
+ return read_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff)); // SA-1 BWRAM
+
+ if (offset >= 0x400000 && offset < 0x500000)
+ return read_bwram(offset & 0xfffff); // SA-1 BWRAM again (but not called for the [c0-cf] range, because it's not mirrored)
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER( sns_sa1_device::chip_write )
+{
+ UINT16 address = offset & 0xffff;
+
+ if (offset < 0x400000 && address >= 0x2200 && address < 0x2400)
+ write_regs(space, address & 0x1ff, data); // SA-1 Regs
+
+ if (offset < 0x400000 && address >= 0x3000 && address < 0x3800)
+ write_iram(address & 0x7ff, data); // Internal SA-1 RAM (2K)
+
+ if (offset < 0x400000 && address >= 0x6000 && address < 0x8000)
+ write_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff), data); // SA-1 BWRAM
+
+ if (offset >= 0x400000 && offset < 0x500000)
+ write_bwram(offset & 0xfffff, data); // SA-1 BWRAM again (but not called for the [c0-cf] range, because it's not mirrored)
+}
+
+
+/*-------------------------------------------------
+ Accesses from SA-1 CPU
+ -------------------------------------------------*/
+
+// These handlers basically match the SNES CPU ones, but there is no access to internal
+// I/O regs or WRAM, and there are a few additional accesses to IRAM (in [00-3f][0000-07ff])
+// and to BWRAM (in [60-6f][0000-ffff], so-called bitmap mode)
+
+READ8_MEMBER( sns_sa1_device::sa1_hi_r )
+{
+ UINT16 address = offset & 0xffff;
+
+ if (offset < 0x400000)
+ {
+ if (address < 0x6000)
+ {
+ if (address < 0x0800)
+ return read_iram(offset); // Internal SA-1 RAM (2K)
+ else if (address >= 0x2200 && address < 0x2400)
+ return read_regs(space, offset & 0x1ff); // SA-1 Regs
+ else if (address >= 0x3000 && address < 0x3800)
+ return read_iram(offset); // Internal SA-1 RAM (2K)
+ }
+ else if (address < 0x8000)
+ return read_bwram((m_bwram_sa1 * 0x2000) + (offset & 0x1fff) + (m_bwram_sa1_source * 0x100000)); // SA-1 BWRAM
+ else
+ return read_h(space, offset); // ROM
+
+ return 0xff; // maybe open bus? same as the main system one or diff? (currently not accessible from carts anyway...)
+ }
+ else
+ return read_h(space, offset); // ROM
+}
+
+READ8_MEMBER( sns_sa1_device::sa1_lo_r )
+{
+ UINT16 address = offset & 0xffff;
+
+ if (offset < 0x400000)
+ {
+ if (address < 0x6000)
+ {
+ if (address < 0x0800)
+ return read_iram(offset); // Internal SA-1 RAM (2K)
+ else if (address >= 0x2200 && address < 0x2400)
+ return read_regs(space, offset & 0x1ff); // SA-1 Regs
+ else if (address >= 0x3000 && address < 0x3800)
+ return read_iram(offset); // Internal SA-1 RAM (2K)
+ }
+ else if (address < 0x8000)
+ return read_bwram((m_bwram_sa1 * 0x2000) + (offset & 0x1fff) + (m_bwram_sa1_source * 0x100000)); // SA-1 BWRAM
+ else if (offset == 0xffee)
+ {
+ return m_sa1_irq & 0xff;
+ }
+ else if (offset == 0xffef)
+ {
+ return m_sa1_irq>>8;
+ }
+ else if (offset == 0xffea)
+ {
+ return m_sa1_nmi & 0xff;
+ }
+ else if (offset == 0xffeb)
+ {
+ return m_sa1_nmi>>8;
+ }
+ else if (offset == 0xfffc)
+ {
+ return m_sa1_reset & 0xff;
+ }
+ else if (offset == 0xfffd)
+ {
+ return m_sa1_reset>>8;
+ }
+ else
+ return read_l(space, offset); // ROM
+
+ return 0xff; // maybe open bus? same as the main system one or diff? (currently not accessible from carts anyway...)
+ }
+ else if (offset < 0x500000)
+ return read_bwram(offset & 0xfffff); // SA-1 BWRAM (not mirrored above!)
+ else if (offset >= 0x600000 && offset < 0x700000)
+ return read_bwram((offset & 0xfffff) + 0x100000); // SA-1 BWRAM Bitmap mode
+ else
+ return 0xff; // nothing should be mapped here, so maybe open bus?
+}
+
+WRITE8_MEMBER( sns_sa1_device::sa1_hi_w )
+{
+ UINT16 address = offset & 0xffff;
+ if (offset < 0x400000)
+ {
+ if (address < 0x6000)
+ {
+ if (address < 0x0800)
+ write_iram(offset, data); // Internal SA-1 RAM (2K)
+ else if (address >= 0x2200 && address < 0x2400)
+ write_regs(space, offset & 0x1ff, data); // SA-1 Regs
+ else if (address >= 0x3000 && address < 0x3800)
+ write_iram(offset, data); // Internal SA-1 RAM (2K)
+ }
+ else if (address < 0x8000)
+ write_bwram((m_bwram_sa1 * 0x2000) + (offset & 0x1fff) + (m_bwram_sa1_source * 0x100000), data); // SA-1 BWRAM
+ }
+}
+
+WRITE8_MEMBER( sns_sa1_device::sa1_lo_w )
+{
+ if (offset >= 0x400000 && offset < 0x500000)
+ write_bwram(offset & 0xfffff, data); // SA-1 BWRAM (not mirrored above!)
+ else if (offset >= 0x600000 && offset < 0x700000)
+ write_bwram((offset & 0xfffff) + 0x100000, data); // SA-1 BWRAM Bitmap mode
+ else
+ sa1_hi_w(space, offset, data);
+}
+
+static ADDRESS_MAP_START( sa1_map, AS_PROGRAM, 8, sns_sa1_device )
+ AM_RANGE(0x000000, 0x7dffff) AM_READWRITE(sa1_lo_r, sa1_lo_w)
+ AM_RANGE(0x7e0000, 0x7fffff) AM_NOP
+ AM_RANGE(0x800000, 0xffffff) AM_READWRITE(sa1_hi_r, sa1_hi_w)
+ADDRESS_MAP_END
+
+
+static MACHINE_CONFIG_FRAGMENT( snes_sa1 )
+ MCFG_CPU_ADD("sa1cpu", G65816, 10000000)
+ MCFG_CPU_PROGRAM_MAP(sa1_map)
+MACHINE_CONFIG_END
+
+machine_config_constructor sns_sa1_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_sa1 );
+}
diff --git a/src/emu/bus/snes/sa1.h b/src/emu/bus/snes/sa1.h
new file mode 100644
index 00000000000..a72263116d0
--- /dev/null
+++ b/src/emu/bus/snes/sa1.h
@@ -0,0 +1,111 @@
+#ifndef __SNS_SA1_H
+#define __SNS_SA1_H
+
+#include "snes_slot.h"
+#include "cpu/g65816/g65816.h"
+
+
+// ======================> sns_sa1_device
+
+class sns_sa1_device : public device_t,
+ public device_sns_cart_interface
+{
+public:
+ // construction/destruction
+ sns_sa1_device(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 device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ DECLARE_READ8_MEMBER(sa1_lo_r);
+ DECLARE_READ8_MEMBER(sa1_hi_r);
+ DECLARE_WRITE8_MEMBER(sa1_lo_w);
+ DECLARE_WRITE8_MEMBER(sa1_hi_w);
+
+private:
+
+ UINT8 var_length_read(address_space &space, UINT32 offset);
+ void dma_transfer(address_space &space);
+ void dma_cctype1_transfer(address_space &space);
+ void dma_cctype2_transfer(address_space &space);
+
+ UINT8 read_regs(address_space &space, UINT32 offset);
+ UINT8 read_iram(UINT32 offset);
+ UINT8 read_bwram(UINT32 offset);
+ void write_regs(address_space &space, UINT32 offset, UINT8 data);
+ void write_iram(UINT32 offset, UINT8 data);
+ void write_bwram(UINT32 offset, UINT8 data);
+ void recalc_irqs();
+
+ required_device<g65816_device> m_sa1;
+
+ UINT8 m_internal_ram[0x800];
+
+ // register related
+ // $2200
+ UINT8 m_sa1_ctrl;
+ // $2201
+ UINT8 m_scpu_sie;
+ // $2203-$2208
+ UINT16 m_sa1_reset, m_sa1_nmi, m_sa1_irq;
+ // $2209
+ UINT8 m_scpu_ctrl;
+ // $220a
+ UINT8 m_sa1_sie;
+ // $200c-$200d - S-CPU vectors
+ UINT16 m_irq_vector, m_nmi_vector;
+ // $2012-$2015
+ UINT16 m_hcount, m_vcount;
+ // $2220-$2223
+ int m_bank_c_hi, m_bank_c_rom;
+ int m_bank_d_hi, m_bank_d_rom;
+ int m_bank_e_hi, m_bank_e_rom;
+ int m_bank_f_hi, m_bank_f_rom;
+ // $2224-$2225 & $223f
+ UINT8 m_bwram_snes, m_bwram_sa1;
+ int m_bwram_sa1_source, m_bwram_sa1_format;
+ // $2226-$2227
+ int m_bwram_write_snes, m_bwram_write_sa1;
+ // $2228
+ UINT32 m_bwpa_sa1;
+ // $2229-$222a
+ UINT8 m_iram_write_snes, m_iram_write_sa1;
+ // $2230-$2231
+ UINT8 m_dma_ctrl, m_dma_ccparam;
+ // $2232-$2237
+ UINT32 m_src_addr, m_dst_addr;
+ // $2238-$2239
+ UINT16 m_dma_cnt;
+ // $2240-$224f
+ UINT8 m_brf_reg[0x10];
+ // $2250-$2254
+ UINT8 m_math_ctlr, m_math_overflow;
+ UINT16 m_math_a, m_math_b;
+ UINT64 m_math_res;
+ // $2258-$225b
+ UINT32 m_vda;
+ UINT8 m_vbit, m_vlen;
+ int m_drm;
+ // $2300-$2301
+ UINT8 m_scpu_flags, m_sa1_flags;
+ // $2302-$2305
+ UINT16 m_hcr, m_vcr;
+};
+
+
+// device type definition
+extern const device_type SNS_LOROM_SA1;
+
+#endif
diff --git a/src/emu/bus/snes/sdd1.c b/src/emu/bus/snes/sdd1.c
new file mode 100644
index 00000000000..6d5356317b7
--- /dev/null
+++ b/src/emu/bus/snes/sdd1.c
@@ -0,0 +1,618 @@
+/***********************************************************************************************************
+
+ S-DD1 add-on chip emulation (for SNES/SFC)
+
+ Based on Andreas Naive Public Domain code.
+ Code ported by MooglyGuy and updated to slots by Fabio Priuli.
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "sdd1.h"
+
+
+#define SSD1_ADD(addr)\
+ mmc[(addr >> 20) & 3] + (addr & 0x0fffff)
+
+
+// Input Manager
+
+void SDD1_IM::IM_prepareDecomp(UINT32 in_buf)
+{
+ m_byte_ptr = in_buf;
+ m_bit_count = 4;
+}
+
+UINT8 SDD1_IM::IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len)
+{
+ UINT8 codeword = ROM[SSD1_ADD(m_byte_ptr)] << m_bit_count;
+
+ ++m_bit_count;
+
+ if (codeword & 0x80)
+ {
+ codeword |= ROM[SSD1_ADD((m_byte_ptr + 1))] >> (9 - m_bit_count);
+ m_bit_count += code_len;
+ }
+
+ if (m_bit_count & 0x08)
+ {
+ m_byte_ptr++;
+ m_bit_count &= 0x07;
+ }
+
+ return codeword;
+}
+
+// GCD
+
+void SDD1_GCD::GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind)
+{
+ const UINT8 run_count[] =
+ {
+ 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
+ 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
+ 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
+ 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
+ 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
+ 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
+ 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
+ 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
+ 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
+ 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
+ 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
+ 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
+ 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
+ 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
+ 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
+ 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
+ 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
+ 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
+ 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
+ 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
+ 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
+ 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
+ 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
+ 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
+ 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
+ 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
+ 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
+ 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
+ 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
+ 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
+ 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
+ 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
+ };
+
+ UINT8 codeword = m_IM->IM_getCodeword(ROM, mmc, code_num);
+
+ if (codeword & 0x80)
+ {
+ *LPSind = 1;
+ *MPScount = run_count[codeword >> (code_num ^ 0x07)];
+ }
+ else
+ {
+ *MPScount = (1 << code_num);
+ }
+}
+
+// BG
+
+void SDD1_BG::BG_prepareDecomp()
+{
+ m_MPScount = 0;
+ m_LPSind = 0;
+}
+
+UINT8 SDD1_BG::BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun)
+{
+ UINT8 bit;
+
+ if (!(m_MPScount || m_LPSind))
+ {
+ m_GCD->GCD_getRunCount(ROM, mmc, m_code_num, &(m_MPScount), &(m_LPSind));
+ }
+
+ if (m_MPScount)
+ {
+ bit = 0;
+ m_MPScount--;
+ }
+ else
+ {
+ bit = 1;
+ m_LPSind = 0;
+ }
+
+ if (m_MPScount || m_LPSind)
+ {
+ (*endOfRun) = 0;
+ }
+ else
+ {
+ (*endOfRun) = 1;
+ }
+
+ return bit;
+}
+
+// PEM
+
+struct SDD1_PEM_state
+{
+ UINT8 code_num;
+ UINT8 nextIfMPS;
+ UINT8 nextIfLPS;
+};
+
+static const SDD1_PEM_state PEM_evolution_table[33] =
+{
+ { 0,25,25},
+ { 0, 2, 1},
+ { 0, 3, 1},
+ { 0, 4, 2},
+ { 0, 5, 3},
+ { 1, 6, 4},
+ { 1, 7, 5},
+ { 1, 8, 6},
+ { 1, 9, 7},
+ { 2,10, 8},
+ { 2,11, 9},
+ { 2,12,10},
+ { 2,13,11},
+ { 3,14,12},
+ { 3,15,13},
+ { 3,16,14},
+ { 3,17,15},
+ { 4,18,16},
+ { 4,19,17},
+ { 5,20,18},
+ { 5,21,19},
+ { 6,22,20},
+ { 6,23,21},
+ { 7,24,22},
+ { 7,24,23},
+ { 0,26, 1},
+ { 1,27, 2},
+ { 2,28, 4},
+ { 3,29, 8},
+ { 4,30,12},
+ { 5,31,16},
+ { 6,32,18},
+ { 7,24,22}
+};
+
+void SDD1_PEM::PEM_prepareDecomp()
+{
+ for (int i = 0; i < 32; i++)
+ {
+ m_contextInfo[i].status = 0;
+ m_contextInfo[i].MPS = 0;
+ }
+}
+
+UINT8 SDD1_PEM::PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context)
+{
+ UINT8 endOfRun;
+ UINT8 bit;
+
+ SDD1_PEM_ContextInfo *pContInfo = &(m_contextInfo)[context];
+ UINT8 currStatus = pContInfo->status;
+ const SDD1_PEM_state* pState = &(PEM_evolution_table[currStatus]);
+ UINT8 currentMPS = pContInfo->MPS;
+
+ bit = m_BG[pState->code_num]->BG_getBit(ROM, mmc, &endOfRun);
+
+ if (endOfRun)
+ {
+ if (bit)
+ {
+ if (!(currStatus & 0xfe))
+ {
+ (pContInfo->MPS) ^= 0x01;
+ }
+ pContInfo->status = pState->nextIfLPS;
+ }
+ else
+ {
+ pContInfo->status = pState->nextIfMPS;
+ }
+ }
+
+ return bit ^ currentMPS;
+}
+
+// CM
+
+void SDD1_CM::CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte)
+{
+ INT32 i = 0;
+ m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0;
+ m_contextBitsInfo = ROM[SSD1_ADD(first_byte)] & 0x30;
+ m_bit_number = 0;
+ for (i = 0; i < 8; i++)
+ {
+ m_prevBitplaneBits[i] = 0;
+ }
+ switch (m_bitplanesInfo)
+ {
+ case 0x00:
+ m_currBitplane = 1;
+ break;
+ case 0x40:
+ m_currBitplane = 7;
+ break;
+ case 0x80:
+ m_currBitplane = 3;
+ break;
+ }
+}
+
+UINT8 SDD1_CM::CM_getBit(UINT8 *ROM, UINT32 *mmc)
+{
+ UINT8 currContext;
+ UINT16 *context_bits;
+ UINT8 bit = 0;
+
+ switch (m_bitplanesInfo)
+ {
+ case 0x00:
+ m_currBitplane ^= 0x01;
+ break;
+ case 0x40:
+ m_currBitplane ^= 0x01;
+ if (!(m_bit_number & 0x7f))
+ m_currBitplane = ((m_currBitplane + 2) & 0x07);
+ break;
+ case 0x80:
+ m_currBitplane ^= 0x01;
+ if (!(m_bit_number & 0x7f))
+ m_currBitplane ^= 0x02;
+ break;
+ case 0xc0:
+ m_currBitplane = m_bit_number & 0x07;
+ break;
+ }
+
+ context_bits = &(m_prevBitplaneBits)[m_currBitplane];
+
+ currContext = (m_currBitplane & 0x01) << 4;
+ switch (m_contextBitsInfo)
+ {
+ case 0x00:
+ currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001);
+ break;
+ case 0x10:
+ currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001);
+ break;
+ case 0x20:
+ currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001);
+ break;
+ case 0x30:
+ currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003);
+ break;
+ }
+
+ bit = m_PEM->PEM_getBit(ROM, mmc, currContext);
+
+ *context_bits <<= 1;
+ *context_bits |= bit;
+
+ m_bit_number++;
+
+ return bit;
+}
+
+// OL
+
+void SDD1_OL::OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf)
+{
+ m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0;
+ m_length = out_len;
+ m_buffer = out_buf;
+}
+
+void SDD1_OL::OL_launch(UINT8 *ROM, UINT32 *mmc)
+{
+ UINT8 i;
+ UINT8 register1 = 0, register2 = 0;
+
+ switch (m_bitplanesInfo)
+ {
+ case 0x00:
+ case 0x40:
+ case 0x80:
+ i = 1;
+ do
+ { // if length == 0, we output 2^16 bytes
+ if (!i)
+ {
+ *(m_buffer++) = register2;
+ i = ~i;
+ }
+ else
+ {
+ for (register1 = register2 = 0, i = 0x80; i; i >>= 1)
+ {
+ if (m_CM->CM_getBit(ROM, mmc))
+ register1 |= i;
+
+ if (m_CM->CM_getBit(ROM, mmc))
+ register2 |= i;
+ }
+ *(m_buffer++) = register1;
+ }
+ } while (--(m_length));
+ break;
+ case 0xc0:
+ do
+ {
+ for (register1 = 0, i = 0x01; i; i <<= 1)
+ {
+ if (m_CM->CM_getBit(ROM, mmc))
+ {
+ register1 |= i;
+ }
+ }
+ *(m_buffer++) = register1;
+ } while (--(m_length));
+ break;
+ }
+}
+
+// S-DD1
+
+SDD1_emu::SDD1_emu(running_machine &machine)
+ : m_machine(machine)
+{
+ m_IM = auto_alloc(machine, SDD1_IM());
+ m_GCD = auto_alloc(machine, SDD1_GCD(m_IM));
+ m_BG0 = auto_alloc(machine, SDD1_BG(m_GCD, 0));
+ m_BG1 = auto_alloc(machine, SDD1_BG(m_GCD, 1));
+ m_BG2 = auto_alloc(machine, SDD1_BG(m_GCD, 2));
+ m_BG3 = auto_alloc(machine, SDD1_BG(m_GCD, 3));
+ m_BG4 = auto_alloc(machine, SDD1_BG(m_GCD, 4));
+ m_BG5 = auto_alloc(machine, SDD1_BG(m_GCD, 5));
+ m_BG6 = auto_alloc(machine, SDD1_BG(m_GCD, 6));
+ m_BG7 = auto_alloc(machine, SDD1_BG(m_GCD, 7));
+ m_PEM = auto_alloc(machine, SDD1_PEM(m_BG0, m_BG1, m_BG2, m_BG3,
+ m_BG4, m_BG5, m_BG6, m_BG7));
+ m_CM = auto_alloc(machine, SDD1_CM(m_PEM));
+ m_OL = auto_alloc(machine, SDD1_OL(m_CM));
+}
+
+void SDD1_emu::SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf)
+{
+ m_IM->IM_prepareDecomp(in_buf);
+ m_BG0->BG_prepareDecomp();
+ m_BG1->BG_prepareDecomp();
+ m_BG2->BG_prepareDecomp();
+ m_BG3->BG_prepareDecomp();
+ m_BG4->BG_prepareDecomp();
+ m_BG5->BG_prepareDecomp();
+ m_BG6->BG_prepareDecomp();
+ m_BG7->BG_prepareDecomp();
+ m_PEM->PEM_prepareDecomp();
+ m_CM->CM_prepareDecomp(ROM, mmc, in_buf);
+ m_OL->OL_prepareDecomp(ROM, mmc, in_buf, out_len, out_buf);
+
+ m_OL->OL_launch(ROM, mmc);
+}
+
+
+//-------------------------------------------------
+// sns_rom_sdd1_device - constructor
+//-------------------------------------------------
+
+const device_type SNS_LOROM_SDD1 = &device_creator<sns_rom_sdd1_device>;
+
+
+sns_rom_sdd1_device::sns_rom_sdd1_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),
+ device_sns_cart_interface( mconfig, *this )
+{
+}
+
+sns_rom_sdd1_device::sns_rom_sdd1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SNS_LOROM_SDD1, "SNES Cart + S-DD1", tag, owner, clock, "sns_rom_sdd1", __FILE__),
+ device_sns_cart_interface( mconfig, *this )
+{
+}
+
+
+void sns_rom_sdd1_device::device_start()
+{
+ m_sdd1emu = auto_alloc(machine(), SDD1_emu(machine()));
+
+ m_buffer.data = (UINT8*)auto_alloc_array(machine(), UINT8, 0x10000);
+ m_buffer.ready = 0;
+
+ save_item(NAME(m_sdd1_enable));
+ save_item(NAME(m_xfer_enable));
+ save_item(NAME(m_mmc));
+
+ for (int i = 0; i < 8; i++)
+ {
+ save_item(NAME(m_dma[i].addr), i);
+ save_item(NAME(m_dma[i].size), i);
+ }
+
+ save_pointer(NAME(m_buffer.data), 0x10000);
+ save_item(NAME(m_buffer.offset));
+ save_item(NAME(m_buffer.size));
+ save_item(NAME(m_buffer.ready));
+
+ // TODO: save remaining decomp-related items so to fix support if we try to save mid-decompression...
+}
+
+void sns_rom_sdd1_device::device_reset()
+{
+ m_sdd1_enable = 0x00;
+ m_xfer_enable = 0x00;
+
+ m_mmc[0] = 0 << 20;
+ m_mmc[1] = 1 << 20;
+ m_mmc[2] = 2 << 20;
+ m_mmc[3] = 3 << 20;
+
+ for(int i = 0; i < 8; i++)
+ {
+ m_dma[i].addr = 0;
+ m_dma[i].size = 0;
+ }
+}
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+READ8_MEMBER( sns_rom_sdd1_device::chip_read )
+{
+ UINT16 addr = offset & 0xffff;
+
+ switch (addr)
+ {
+ case 0x4804:
+ return (m_mmc[0] >> 20) & 7;
+ case 0x4805:
+ return (m_mmc[1] >> 20) & 7;
+ case 0x4806:
+ return (m_mmc[2] >> 20) & 7;
+ case 0x4807:
+ return (m_mmc[3] >> 20) & 7;
+ }
+
+// we should never get here, but...
+ return 0;
+}
+
+
+WRITE8_MEMBER( sns_rom_sdd1_device::chip_write )
+{
+ UINT16 addr = offset & 0xffff;
+
+ if ((addr & 0x4380) == 0x4300)
+ {
+ UINT8 channel = (addr >> 4) & 7;
+ switch(addr & 0xf)
+ {
+ case 2:
+ m_dma[channel].addr = (m_dma[channel].addr & 0xffff00) + (data << 0);
+ break;
+ case 3:
+ m_dma[channel].addr = (m_dma[channel].addr & 0xff00ff) + (data << 8);
+ break;
+ case 4:
+ m_dma[channel].addr = (m_dma[channel].addr & 0x00ffff) + (data << 16);
+ break;
+
+ case 5:
+ m_dma[channel].size = (m_dma[channel].size & 0xff00) + (data << 0);
+ break;
+ case 6:
+ m_dma[channel].size = (m_dma[channel].size & 0x00ff) + (data << 8);
+ break;
+ }
+ return;
+ }
+
+ switch(addr)
+ {
+ case 0x4800:
+ m_sdd1_enable = data;
+ break;
+ case 0x4801:
+ m_xfer_enable = data;
+ break;
+
+ case 0x4804:
+ m_mmc[0] = (data & 7) << 20;
+ break;
+ case 0x4805:
+ m_mmc[1] = (data & 7) << 20;
+ break;
+ case 0x4806:
+ m_mmc[2] = (data & 7) << 20;
+ break;
+ case 0x4807:
+ m_mmc[3] = (data & 7) << 20;
+ break;
+ }
+
+}
+
+UINT8 sns_rom_sdd1_device::read_helper(UINT32 addr)
+{
+ if (m_sdd1_enable & m_xfer_enable)
+ {
+ // at least one channel has S-DD1 decompression enabled...
+ for (int i = 0; i < 8; i++)
+ {
+ if (m_sdd1_enable & m_xfer_enable & (1 << i))
+ {
+ // S-DD1 always uses fixed transfer mode, so address will not change during transfer
+ if ((addr + 0xc00000) == m_dma[i].addr)
+ {
+ UINT8 data;
+ if (!m_buffer.ready)
+ {
+ // first byte read for channel performs full decompression.
+ // this really should stream byte-by-byte, but it's not necessary since the size is known
+ m_buffer.offset = 0;
+ m_buffer.size = m_dma[i].size ? m_dma[i].size : 65536;
+
+ // SDD1_emu calls this function; it needs to access uncompressed data;
+ // so temporarily disable decompression mode for decompress() call.
+ m_sdd1emu->SDD1emu_decompress(m_rom, m_mmc, addr, m_buffer.size, m_buffer.data);
+
+ m_buffer.ready = 1;
+ }
+
+ // fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
+ data = m_buffer.data[(UINT16)m_buffer.offset++];
+ if (m_buffer.offset >= m_buffer.size)
+ {
+ m_buffer.ready = 0;
+ m_xfer_enable &= ~(1 << i);
+ }
+
+ return data;
+ }
+ }
+ }
+ }
+
+ return m_rom[m_mmc[(addr >> 20) & 3] + (addr & 0x0fffff)];
+}
+
+READ8_MEMBER(sns_rom_sdd1_device::read_l)
+{
+ if (offset < 0x400000)
+ return m_rom[rom_bank_map[offset / 0x10000] * 0x8000 + (offset & 0x7fff)];
+ else
+ return m_rom[rom_bank_map[(offset - 0x400000) / 0x8000] * 0x8000 + (offset & 0x7fff)];
+}
+
+READ8_MEMBER(sns_rom_sdd1_device::read_h)
+{
+ if (offset >= 0x400000)
+ return read_helper(offset - 0x400000);
+ else
+ return read_l(space, offset);
+}
+
+
+READ8_MEMBER( sns_rom_sdd1_device::read_ram )
+{
+ return m_nvram[offset & 0x1fff];
+}
+
+WRITE8_MEMBER( sns_rom_sdd1_device::write_ram )
+{
+ m_nvram[offset & 0x1fff] = data;
+}
diff --git a/src/emu/bus/snes/sdd1.h b/src/emu/bus/snes/sdd1.h
new file mode 100644
index 00000000000..fdd94ed7b2f
--- /dev/null
+++ b/src/emu/bus/snes/sdd1.h
@@ -0,0 +1,185 @@
+#ifndef __SNS_SDD1_H
+#define __SNS_SDD1_H
+
+#include "snes_slot.h"
+
+// misc classes for the S-DD1
+
+class SDD1_IM //Input Manager
+{
+public:
+ SDD1_IM() {}
+
+ UINT32 m_byte_ptr;
+ UINT8 m_bit_count;
+
+ void IM_prepareDecomp(UINT32 in_buf);
+ UINT8 IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len);
+};
+
+class SDD1_GCD //Golomb-Code Decoder
+{
+public:
+ SDD1_GCD(SDD1_IM* associatedIM)
+ : m_IM(associatedIM) { }
+
+ SDD1_IM* m_IM;
+
+ void GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind);
+};
+
+class SDD1_BG // Bits Generator
+{
+public:
+ SDD1_BG(SDD1_GCD* associatedGCD, UINT8 code)
+ : m_code_num(code),
+ m_GCD(associatedGCD) { }
+
+ UINT8 m_code_num;
+ UINT8 m_MPScount;
+ UINT8 m_LPSind;
+ SDD1_GCD* m_GCD;
+
+ void BG_prepareDecomp();
+ UINT8 BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun);
+} ;
+
+struct SDD1_PEM_ContextInfo
+{
+ UINT8 status;
+ UINT8 MPS;
+};
+
+class SDD1_PEM //Probability Estimation Module
+{
+public:
+ SDD1_PEM(
+ SDD1_BG* associatedBG0, SDD1_BG* associatedBG1,
+ SDD1_BG* associatedBG2, SDD1_BG* associatedBG3,
+ SDD1_BG* associatedBG4, SDD1_BG* associatedBG5,
+ SDD1_BG* associatedBG6, SDD1_BG* associatedBG7)
+ {
+ m_BG[0] = associatedBG0;
+ m_BG[1] = associatedBG1;
+ m_BG[2] = associatedBG2;
+ m_BG[3] = associatedBG3;
+ m_BG[4] = associatedBG4;
+ m_BG[5] = associatedBG5;
+ m_BG[6] = associatedBG6;
+ m_BG[7] = associatedBG7;
+ }
+
+ SDD1_PEM_ContextInfo m_contextInfo[32];
+ SDD1_BG* m_BG[8];
+
+ void PEM_prepareDecomp();
+ UINT8 PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context);
+} ;
+
+
+class SDD1_CM
+{
+public:
+ SDD1_CM(SDD1_PEM* associatedPEM)
+ : m_PEM(associatedPEM) { }
+
+ UINT8 m_bitplanesInfo;
+ UINT8 m_contextBitsInfo;
+ UINT8 m_bit_number;
+ UINT8 m_currBitplane;
+ UINT16 m_prevBitplaneBits[8];
+ SDD1_PEM* m_PEM;
+
+ void CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte);
+ UINT8 CM_getBit(UINT8 *ROM, UINT32 *mmc);
+} ;
+
+
+class SDD1_OL
+{
+public:
+ SDD1_OL(SDD1_CM* associatedCM)
+ : m_CM(associatedCM) { }
+
+ UINT8 m_bitplanesInfo;
+ UINT16 m_length;
+ UINT8* m_buffer;
+ SDD1_CM* m_CM;
+
+ void OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf);
+ void OL_launch(UINT8 *ROM, UINT32 *mmc);
+} ;
+
+class SDD1_emu
+{
+public:
+ SDD1_emu(running_machine &machine);
+
+ running_machine &machine() const { return m_machine; }
+
+ SDD1_IM* m_IM;
+ SDD1_GCD* m_GCD;
+ SDD1_BG* m_BG0; SDD1_BG* m_BG1; SDD1_BG* m_BG2; SDD1_BG* m_BG3;
+ SDD1_BG* m_BG4; SDD1_BG* m_BG5; SDD1_BG* m_BG6; SDD1_BG* m_BG7;
+ SDD1_PEM* m_PEM;
+ SDD1_CM* m_CM;
+ SDD1_OL* m_OL;
+
+ void SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf);
+
+private:
+ running_machine& m_machine;
+};
+
+
+
+// ======================> sns_rom_sdd1_device
+
+class sns_rom_sdd1_device : public device_t,
+ public device_sns_cart_interface
+{
+public:
+ // construction/destruction
+ sns_rom_sdd1_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);
+ sns_rom_sdd1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_READ8_MEMBER(read_ram);
+ virtual DECLARE_WRITE8_MEMBER(write_ram);
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ UINT8 read_helper(UINT32 offset);
+
+ UINT8 m_sdd1_enable; // channel bit-mask
+ UINT8 m_xfer_enable; // channel bit-mask
+ UINT32 m_mmc[4]; // memory map controller ROM indices
+
+ struct
+ {
+ UINT32 addr; // $43x2-$43x4 -- DMA transfer address
+ UINT16 size; // $43x5-$43x6 -- DMA transfer size
+ } m_dma[8];
+
+ SDD1_emu* m_sdd1emu;
+
+ struct
+ {
+ UINT8 *data; // pointer to decompressed S-DD1 data (65536 bytes)
+ UINT16 offset; // read index into S-DD1 decompression buffer
+ UINT32 size; // length of data buffer; reads decrement counter, set ready to false at 0
+ UINT8 ready; // 1 when data[] is valid; 0 to invoke sdd1emu.decompress()
+ } m_buffer;
+};
+
+
+// device type definition
+extern const device_type SNS_LOROM_SDD1;
+
+#endif
diff --git a/src/emu/bus/snes/sfx.c b/src/emu/bus/snes/sfx.c
new file mode 100644
index 00000000000..75c2827a5a6
--- /dev/null
+++ b/src/emu/bus/snes/sfx.c
@@ -0,0 +1,149 @@
+/***********************************************************************************************************
+
+ SuperFX add-on chip emulation (for SNES/SFC)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "sfx.h"
+#include "cpu/g65816/g65816.h"
+
+//-------------------------------------------------
+// sns_rom_superfx_device - constructor
+//-------------------------------------------------
+
+const device_type SNS_LOROM_SUPERFX = &device_creator<sns_rom_superfx_device>;
+
+
+sns_rom_superfx_device::sns_rom_superfx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_SUPERFX, "SNES Cart (LoROM) + SuperFX", tag, owner, clock, "sns_rom_superfx", __FILE__),
+ m_superfx(*this, "superfx")
+{
+}
+
+void sns_rom_superfx_device::device_start()
+{
+ save_item(NAME(sfx_ram));
+}
+
+void sns_rom_superfx_device::device_reset()
+{
+ memset(sfx_ram, 0x00, sizeof(sfx_ram));
+}
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+// LoROM + SuperFX (GSU-1,2)
+// TODO: mask sfx_ram based on the actual RAM...
+
+READ8_MEMBER( sns_rom_superfx_device::superfx_r_bank1 )
+{
+ return m_rom[rom_bank_map[offset / 0x10000] * 0x8000 + (offset & 0x7fff)];
+}
+
+READ8_MEMBER( sns_rom_superfx_device::superfx_r_bank2 )
+{
+ return m_rom[rom_bank_map[offset / 0x8000] * 0x8000 + (offset & 0x7fff)];
+}
+
+READ8_MEMBER( sns_rom_superfx_device::superfx_r_bank3 )
+{
+ return sfx_ram[offset & 0xfffff];
+}
+
+WRITE8_MEMBER( sns_rom_superfx_device::superfx_w_bank1 )
+{
+}
+
+WRITE8_MEMBER( sns_rom_superfx_device::superfx_w_bank2 )
+{
+}
+
+WRITE8_MEMBER( sns_rom_superfx_device::superfx_w_bank3 )
+{
+ sfx_ram[offset & 0xfffff] = data;
+}
+
+static ADDRESS_MAP_START( sfx_map, AS_PROGRAM, 8, sns_rom_superfx_device )
+ AM_RANGE(0x000000, 0x3fffff) AM_READWRITE(superfx_r_bank1, superfx_w_bank1)
+ AM_RANGE(0x400000, 0x5fffff) AM_READWRITE(superfx_r_bank2, superfx_w_bank2)
+ AM_RANGE(0x600000, 0x7dffff) AM_READWRITE(superfx_r_bank3, superfx_w_bank3)
+ AM_RANGE(0x800000, 0xbfffff) AM_READWRITE(superfx_r_bank1, superfx_w_bank1)
+ AM_RANGE(0xc00000, 0xdfffff) AM_READWRITE(superfx_r_bank2, superfx_w_bank2)
+ AM_RANGE(0xe00000, 0xffffff) AM_READWRITE(superfx_r_bank3, superfx_w_bank3)
+ADDRESS_MAP_END
+
+
+WRITE_LINE_MEMBER(sns_rom_superfx_device::snes_extern_irq_w)
+{
+ machine().device("maincpu")->execute().set_input_line(G65816_LINE_IRQ, state);
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( snes_sfx )
+ MCFG_CPU_ADD("superfx", SUPERFX, 21480000) /* 21.48MHz */
+ MCFG_CPU_PROGRAM_MAP(sfx_map)
+ MCFG_SUPERFX_OUT_IRQ(WRITELINE(sns_rom_superfx_device, snes_extern_irq_w)) /* IRQ line from cart */
+MACHINE_CONFIG_END
+
+machine_config_constructor sns_rom_superfx_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_sfx );
+}
+
+READ8_MEMBER( sns_rom_superfx_device::chip_read )
+{
+ return m_superfx->mmio_read(offset);
+}
+
+WRITE8_MEMBER( sns_rom_superfx_device::chip_write )
+{
+ m_superfx->mmio_write(offset, data);
+}
+
+
+READ8_MEMBER( sns_rom_superfx_device::read_l )
+{
+ return read_h(space, offset);
+}
+
+READ8_MEMBER(sns_rom_superfx_device::read_h)
+{
+ if (offset < 0x400000)
+ return m_rom[rom_bank_map[offset / 0x10000] * 0x8000 + (offset & 0x7fff)];
+ else if (offset < 0x600000)
+ {
+ if (m_superfx->access_rom())
+ {
+ return m_rom[rom_bank_map[(offset - 0x400000) / 0x8000] * 0x8000 + (offset & 0x7fff)];
+ }
+ else
+ {
+ static const UINT8 sfx_data[16] = {
+ 0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01,
+ 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01,
+ };
+ return sfx_data[offset & 0x0f];
+ }
+ }
+ return 0xff; // this handler should never be called for [60-7f]/[e0-ff] ranges
+}
+
+READ8_MEMBER( sns_rom_superfx_device::read_ram )
+{
+ if (m_superfx->access_ram())
+ return sfx_ram[offset & 0xfffff];
+ return 0xff; // should be open bus...
+}
+
+WRITE8_MEMBER( sns_rom_superfx_device::write_ram )
+{
+ if (m_superfx->access_ram())
+ sfx_ram[offset & 0xfffff] = data;
+}
diff --git a/src/emu/bus/snes/sfx.h b/src/emu/bus/snes/sfx.h
new file mode 100644
index 00000000000..a68ea4ffce9
--- /dev/null
+++ b/src/emu/bus/snes/sfx.h
@@ -0,0 +1,48 @@
+#ifndef __SNS_SFX_H
+#define __SNS_SFX_H
+
+#include "snes_slot.h"
+#include "rom.h"
+#include "cpu/superfx/superfx.h"
+
+
+// ======================> sns_rom_superfx_device
+
+class sns_rom_superfx_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_superfx_device(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;
+
+ required_device<superfx_device> m_superfx;
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_READ8_MEMBER(read_ram);
+ virtual DECLARE_WRITE8_MEMBER(write_ram);
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ virtual DECLARE_READ8_MEMBER(superfx_r_bank1);
+ virtual DECLARE_READ8_MEMBER(superfx_r_bank2);
+ virtual DECLARE_READ8_MEMBER(superfx_r_bank3);
+ virtual DECLARE_WRITE8_MEMBER(superfx_w_bank1);
+ virtual DECLARE_WRITE8_MEMBER(superfx_w_bank2);
+ virtual DECLARE_WRITE8_MEMBER(superfx_w_bank3);
+ virtual DECLARE_WRITE_LINE_MEMBER(snes_extern_irq_w);
+
+
+ UINT8 sfx_ram[0x200000];
+};
+
+
+// device type definition
+extern const device_type SNS_LOROM_SUPERFX;
+
+#endif
diff --git a/src/emu/bus/snes/sgb.c b/src/emu/bus/snes/sgb.c
new file mode 100644
index 00000000000..a2e8eabe4c2
--- /dev/null
+++ b/src/emu/bus/snes/sgb.c
@@ -0,0 +1,293 @@
+/***********************************************************************************************************
+
+ Super Game Boy emulation (for SNES/SFC)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ TODO: almost everything, e.g.
+ * implement gb_timer_callback
+ * gb_io_r/w
+ * add hook-up to copy LCD scanline to m_lcd_buffer
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "sgb.h"
+
+//-------------------------------------------------
+// sns_rom_sgb_device - constructor
+//-------------------------------------------------
+
+const device_type SNS_LOROM_SUPERGB = &device_creator<sns_rom_sgb_device>;
+
+
+sns_rom_sgb_device::sns_rom_sgb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_SUPERGB, "SNES Super Game Boy Cart", tag, owner, clock, "sns_rom_sgb", __FILE__),
+ m_gb_cpu(*this, "sgb_cpu"),
+ m_gb_snd(*this, "sgb_snd"),
+ m_gb_lcd(*this, "sgb_lcd"),
+ m_cartslot(*this, "gb_slot")
+{
+}
+
+
+void sns_rom_sgb_device::device_start()
+{
+}
+
+void sns_rom_sgb_device::device_reset()
+{
+}
+
+
+
+// SuperGB emulation
+
+//-------------------------------------------------
+// ADDRESS_MAP( supergb_map )
+//-------------------------------------------------
+
+READ8_MEMBER(sns_rom_sgb_device::gb_cart_r)
+{
+ return m_cartslot->read_rom(space, offset);
+}
+
+WRITE8_MEMBER(sns_rom_sgb_device::gb_bank_w)
+{
+ m_cartslot->write_bank(space, offset, data);
+}
+
+READ8_MEMBER(sns_rom_sgb_device::gb_ram_r)
+{
+ return m_cartslot->read_ram(space, offset);
+}
+
+WRITE8_MEMBER(sns_rom_sgb_device::gb_ram_w)
+{
+ m_cartslot->write_ram(space, offset, data);
+}
+
+READ8_MEMBER(sns_rom_sgb_device::gb_echo_r)
+{
+ return space.read_byte(0xc000 + offset);
+}
+
+WRITE8_MEMBER(sns_rom_sgb_device::gb_echo_w)
+{
+ return space.write_byte(0xc000 + offset, data);
+}
+
+READ8_MEMBER(sns_rom_sgb_device::gb_io_r)
+{
+ return 0;
+}
+
+WRITE8_MEMBER(sns_rom_sgb_device::gb_io_w)
+{
+}
+
+READ8_MEMBER(sns_rom_sgb_device::gb_ie_r)
+{
+ return m_gb_cpu->get_ie();
+}
+
+WRITE8_MEMBER(sns_rom_sgb_device::gb_ie_w)
+{
+ m_gb_cpu->set_ie(data & 0x1f);
+}
+
+
+
+static ADDRESS_MAP_START(supergb_map, AS_PROGRAM, 8, sns_rom_sgb_device )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gb_cart_r, gb_bank_w)
+ AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, vram_r, vram_w) /* 8k VRAM */
+ AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w ) /* 8k switched RAM bank (cartridge) */
+ AM_RANGE(0xc000, 0xdfff) AM_RAM /* 8k low RAM */
+ AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w) /* echo RAM */
+ AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w) /* I/O */
+ AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("sgb_snd", gameboy_sound_device, sound_r, sound_w) /* sound registers */
+ AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, oam_r, oam_w) /* OAM RAM */
+ AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
+ AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("sgb_snd", gameboy_sound_device, wave_r, wave_w) /* Wave RAM */
+ AM_RANGE(0xff40, 0xff7f) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, video_r, video_w) /* also disable bios?? */ /* Video controller & BIOS flip-flop */
+ AM_RANGE(0xff80, 0xfffe) AM_RAM /* High RAM */
+ AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */
+ADDRESS_MAP_END
+
+
+
+WRITE8_MEMBER( sns_rom_sgb_device::gb_timer_callback )
+{
+}
+
+
+static SLOT_INTERFACE_START(supergb_cart)
+ SLOT_INTERFACE_INTERNAL("rom", GB_STD_ROM)
+ SLOT_INTERFACE_INTERNAL("rom_mbc1", GB_ROM_MBC1)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( supergb )
+ MCFG_CPU_ADD("sgb_cpu", LR35902, 4295454) /* 4.295454 MHz */
+ MCFG_CPU_PROGRAM_MAP(supergb_map)
+ MCFG_LR35902_TIMER_CB(WRITE8(sns_rom_sgb_device, gb_timer_callback))
+ MCFG_LR35902_HALT_BUG
+
+ MCFG_GB_LCD_SGB_ADD("sgb_lcd")
+
+ MCFG_SOUND_ADD("sgb_snd", GAMEBOY, 0)
+
+ MCFG_GB_CARTRIDGE_ADD("gb_slot", supergb_cart, NULL)
+MACHINE_CONFIG_END
+
+
+machine_config_constructor sns_rom_sgb_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( supergb );
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+
+READ8_MEMBER(sns_rom_sgb_device::read_l)
+{
+ return read_h(space, offset);
+}
+
+READ8_MEMBER(sns_rom_sgb_device::read_h)
+{
+ int bank = offset / 0x10000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+}
+
+READ8_MEMBER( sns_rom_sgb_device::chip_read )
+{
+ UINT16 address = offset & 0xffff;
+
+ //LY counter
+ if (address == 0x6000)
+ {
+ m_sgb_ly = 0;// GameBoy PPU LY here
+ m_sgb_row = m_lcd_row;
+ return m_sgb_ly;
+ }
+
+ //command ready port
+ if (address == 0x6002)
+ {
+ bool data = (m_packetsize > 0);
+ if (data)
+ {
+ for (int i = 0; i < 16; i++)
+ m_joy_pckt[i] = m_packet_data[0][i];
+ m_packetsize--;
+
+ //hack because we still don't emulate input packets!
+ if (!m_packetsize) m_packetsize = 64;
+
+ // shift packet
+ for (int i = 0; i < m_packetsize; i++)
+ for (int j = 0; j < 16; j++)
+ m_packet_data[i][j] = m_packet_data[i + 1][j];
+ }
+ return data;
+ }
+
+ //ICD2 revision
+ if (address == 0x600f)
+ return 0x21;
+
+ //command port
+ if ((address & 0xfff0) == 0x7000)
+ return m_joy_pckt[address & 0x0f];
+
+ //VRAM port
+ if (address == 0x7800)
+ {
+ UINT8 data = m_lcd_output[m_vram_offs];
+ m_vram_offs = (m_vram_offs + 1) % 320;
+ return data;
+ }
+
+ return 0x00; // this should never happen?
+}
+
+void sns_rom_sgb_device::lcd_render(UINT32 *source)
+{
+ memset(m_lcd_output, 0x00, 320 * sizeof(UINT16));
+
+ for (int y = 0; y < 8; y++)
+ {
+ for (int x = 0; x < 160; x++)
+ {
+ UINT32 pixel = *source++;
+ UINT16 addr = y * 2 + (x / 8 * 16);
+ m_lcd_output[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7));
+ m_lcd_output[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7));
+ }
+ }
+}
+
+WRITE8_MEMBER( sns_rom_sgb_device::chip_write )
+{
+ UINT16 address = offset & 0xffff;
+
+ //VRAM port
+ if (address == 0x6001)
+ {
+ m_vram = data;
+ m_vram_offs = 0;
+
+ UINT8 offset = (m_sgb_row - (4 - (m_vram - (m_sgb_ly & 3)))) & 3;
+ lcd_render(m_lcd_buffer + offset * 160 * 8);
+
+ return;
+ }
+
+ //control port
+ if (address == 0x6003)
+ {
+ if ((m_port & 0x80) == 0x00 && (data & 0x80) == 0x80)
+ {
+ //reset
+ }
+
+ switch (data & 3)
+ {
+ //change CPU frequency
+ }
+ m_port = data;
+ return;
+ }
+
+ if (address == 0x6004)
+ {
+ //joypad 1
+ m_joy1 = data;
+ return;
+ }
+ if (address == 0x6005)
+ {
+ //joypad 2
+ m_joy2 = data;
+ return;
+ }
+ if (address == 0x6006)
+ {
+ //joypad 3
+ m_joy3 = data;
+ return;
+ }
+ if (address == 0x6007)
+ {
+ //joypad 4
+ m_joy4 = data;
+ return;
+ }
+
+}
diff --git a/src/emu/bus/snes/sgb.h b/src/emu/bus/snes/sgb.h
new file mode 100644
index 00000000000..fc7c940083e
--- /dev/null
+++ b/src/emu/bus/snes/sgb.h
@@ -0,0 +1,76 @@
+#ifndef __SNS_SGB_H
+#define __SNS_SGB_H
+
+#include "snes_slot.h"
+#include "rom.h"
+
+#include "cpu/lr35902/lr35902.h"
+#include "machine/gb_slot.h"
+#include "machine/gb_rom.h"
+#include "machine/gb_mbc.h"
+#include "video/gb_lcd.h"
+#include "audio/gb.h"
+
+
+// ======================> sns_rom_sgb_device
+
+class sns_rom_sgb_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_sgb_device(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;
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ virtual DECLARE_READ8_MEMBER(gb_cart_r);
+ virtual DECLARE_WRITE8_MEMBER(gb_bank_w);
+ virtual DECLARE_READ8_MEMBER(gb_ram_r);
+ virtual DECLARE_WRITE8_MEMBER(gb_ram_w);
+ virtual DECLARE_READ8_MEMBER(gb_echo_r);
+ virtual DECLARE_WRITE8_MEMBER(gb_echo_w);
+ virtual DECLARE_READ8_MEMBER(gb_io_r);
+ virtual DECLARE_WRITE8_MEMBER(gb_io_w);
+ virtual DECLARE_READ8_MEMBER(gb_ie_r);
+ virtual DECLARE_WRITE8_MEMBER(gb_ie_w);
+ virtual DECLARE_WRITE8_MEMBER(gb_timer_callback);
+
+ required_device<lr35902_cpu_device> m_gb_cpu;
+ required_device<gameboy_sound_device> m_gb_snd;
+ required_device<sgb_lcd_device> m_gb_lcd;
+ required_device<gb_cart_slot_device> m_cartslot;
+
+ void lcd_render(UINT32 *source);
+
+ // ICD2 regs
+ UINT8 m_sgb_ly;
+ UINT8 m_sgb_row;
+ UINT8 m_vram;
+ UINT8 m_port;
+ UINT8 m_joy1, m_joy2, m_joy3, m_joy4;
+ UINT8 m_joy_pckt[16];
+ UINT16 m_vram_offs;
+ UINT8 m_mlt_req;
+
+ UINT32 m_lcd_buffer[4 * 160 * 8];
+ UINT16 m_lcd_output[320];
+ UINT16 m_lcd_row;
+
+ // input bits
+ int m_packetsize;
+ UINT8 m_packet_data[64][16];
+};
+
+
+// device type definition
+extern const device_type SNS_LOROM_SUPERGB;
+
+#endif
diff --git a/src/emu/bus/snes/snes_carts.c b/src/emu/bus/snes/snes_carts.c
new file mode 100644
index 00000000000..121edca8f3b
--- /dev/null
+++ b/src/emu/bus/snes/snes_carts.c
@@ -0,0 +1,50 @@
+/**********************************************************************
+
+ SNES carts
+
+**********************************************************************/
+
+#include "snes_carts.h"
+
+SLOT_INTERFACE_START(snes_cart)
+ SLOT_INTERFACE_INTERNAL("lorom", SNS_LOROM)
+ SLOT_INTERFACE_INTERNAL("lorom_bsx", SNS_LOROM_BSX) // LoROM + BS-X slot - unsupported
+ SLOT_INTERFACE_INTERNAL("lorom_cx4", SNS_LOROM) // Cart + CX4 - unsupported
+ SLOT_INTERFACE_INTERNAL("lorom_dsp", SNS_LOROM_NECDSP)
+ SLOT_INTERFACE_INTERNAL("lorom_dsp4", SNS_LOROM_NECDSP)
+ SLOT_INTERFACE_INTERNAL("lorom_obc1", SNS_LOROM_OBC1)
+ SLOT_INTERFACE_INTERNAL("lorom_sa1", SNS_LOROM_SA1) // Cart + SA1 - unsupported
+ SLOT_INTERFACE_INTERNAL("lorom_sdd1", SNS_LOROM_SDD1)
+ SLOT_INTERFACE_INTERNAL("lorom_sfx", SNS_LOROM_SUPERFX)
+ SLOT_INTERFACE_INTERNAL("lorom_sgb", SNS_LOROM_SUPERGB) // SuperGB base cart - unsupported
+ SLOT_INTERFACE_INTERNAL("lorom_st010", SNS_LOROM_SETA10)
+ SLOT_INTERFACE_INTERNAL("lorom_st011", SNS_LOROM_SETA11)
+ SLOT_INTERFACE_INTERNAL("lorom_st018", SNS_LOROM) // Cart + ST018 - unsupported
+ SLOT_INTERFACE_INTERNAL("lorom_sufami", SNS_LOROM_SUFAMI) // Sufami Turbo base cart
+ SLOT_INTERFACE_INTERNAL("hirom", SNS_HIROM)
+ SLOT_INTERFACE_INTERNAL("hirom_bsx", SNS_HIROM_BSX) // HiROM + BS-X slot - unsupported
+ SLOT_INTERFACE_INTERNAL("hirom_dsp", SNS_HIROM_NECDSP)
+ SLOT_INTERFACE_INTERNAL("hirom_spc7110", SNS_HIROM_SPC7110)
+ SLOT_INTERFACE_INTERNAL("hirom_spcrtc", SNS_HIROM_SPC7110_RTC)
+ SLOT_INTERFACE_INTERNAL("hirom_srtc", SNS_HIROM_SRTC)
+ SLOT_INTERFACE_INTERNAL("bsxrom", SNS_ROM_BSX) // BS-X base cart - partial support only
+ SLOT_INTERFACE_INTERNAL("pfest94", SNS_PFEST94)
+ // pirate carts
+ SLOT_INTERFACE_INTERNAL("lorom_poke", SNS_LOROM_POKEMON)
+ SLOT_INTERFACE_INTERNAL("lorom_tekken2", SNS_LOROM_TEKKEN2)
+ SLOT_INTERFACE_INTERNAL("lorom_sbld", SNS_LOROM_SOULBLAD)
+ SLOT_INTERFACE_INTERNAL("lorom_mcpir1", SNS_LOROM_MCPIR1)
+ SLOT_INTERFACE_INTERNAL("lorom_mcpir2", SNS_LOROM_MCPIR2)
+ SLOT_INTERFACE_INTERNAL("lorom_20col", SNS_LOROM_20COL)
+ SLOT_INTERFACE_INTERNAL("lorom_pija", SNS_LOROM_BANANA) // not working yet
+ SLOT_INTERFACE_INTERNAL("lorom_bugs", SNS_LOROM_BUGSLIFE) // not working yet
+ // legacy slots to support DSPx games from fullpath
+ SLOT_INTERFACE_INTERNAL("lorom_dsp1leg", SNS_LOROM_NECDSP1_LEG)
+ SLOT_INTERFACE_INTERNAL("lorom_dsp1bleg",SNS_LOROM_NECDSP1B_LEG)
+ SLOT_INTERFACE_INTERNAL("lorom_dsp2leg", SNS_LOROM_NECDSP2_LEG)
+ SLOT_INTERFACE_INTERNAL("lorom_dsp3leg", SNS_LOROM_NECDSP3_LEG)
+ SLOT_INTERFACE_INTERNAL("lorom_dsp4leg", SNS_LOROM_NECDSP4_LEG)
+ SLOT_INTERFACE_INTERNAL("hirom_dsp1leg", SNS_HIROM_NECDSP1_LEG)
+ SLOT_INTERFACE_INTERNAL("lorom_st10leg", SNS_LOROM_SETA10_LEG)
+ SLOT_INTERFACE_INTERNAL("lorom_st11leg", SNS_LOROM_SETA11_LEG)
+SLOT_INTERFACE_END
diff --git a/src/emu/bus/snes/snes_carts.h b/src/emu/bus/snes/snes_carts.h
new file mode 100644
index 00000000000..f5f619e272c
--- /dev/null
+++ b/src/emu/bus/snes/snes_carts.h
@@ -0,0 +1,29 @@
+/**********************************************************************
+
+ SNES carts
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SNES_CARTS_H__
+#define __SNES_CARTS_H__
+
+#include "emu.h"
+
+#include "rom.h"
+#include "rom21.h"
+#include "bsx.h"
+#include "sa1.h"
+#include "sdd1.h"
+#include "sfx.h"
+#include "sgb.h"
+#include "spc7110.h"
+#include "sufami.h"
+#include "upd.h"
+#include "event.h"
+
+// supported devices
+SLOT_INTERFACE_EXTERN(snes_cart);
+
+#endif // __SNES_CARTS_H__
diff --git a/src/emu/bus/snes/snes_slot.c b/src/emu/bus/snes/snes_slot.c
new file mode 100644
index 00000000000..6765685841f
--- /dev/null
+++ b/src/emu/bus/snes/snes_slot.c
@@ -0,0 +1,1397 @@
+/***********************************************************************************************************
+
+
+ SNES cart emulation
+ (through slot devices)
+
+
+ Carts can be mapped in memory in several different ways and accesses to carts depend
+ on the presence of add-on chips (which map their I/O to diff memory areas)
+
+ Hence, carts can interface with the main system through the following handlers
+ * read_l : typically used to read ROM from memory range [00-7f][0000-ffff]
+ * read_h : typically used to read ROM from memory range [80-ff][0000-ffff]
+ * read_ram : used to read (NV)RAM at the appropriate offset (masks has to be applied
+ *before* calling it, if dealing with >32K RAM)
+ * write_ram : used to write (NV)RAM at the appropriate offset
+ * read_chip : used to read add-on chip registers
+ * write_chip : used to write to add-on chip registers
+
+ Also, we define two additional ROM access handlers, write_l & write_h for carts with
+ subslots (e.g. BS-X compatible ones), that need to write to subslot (NV)RAM independently
+ to accesses to their own (NV)RAM.
+
+ Notes about add-on detection and handling (useful for future addition of st018, cx4, etc.)
+ ===============================================================================================
+ When loading from softlist, m_type would be enough to take care of add-on chips, because
+ the ones needing a CPU dump have it in the zipfile. However, to support these games also
+ from fullpath, both with files having DSP data appended to the .sfc and with older dumps
+ missing DSP data, a second variable is present in the SNES slot: m_addon.
+ From fullpath, support works as follows
+ - get_default_card_software needs to decide whether to use the main devices or the legacy
+ ones containing DSP dump as device roms, so it gets m_type as the main device should be
+ used and if m_addon is ADDON_DSP* or ADDON_ST*, then it checks if the DSP data is appended
+ or if m_type has to be switched to legacy type
+ - call_load needs to detect faulty dumps too, to alloc m_addon_bios and copy the data from
+ the correct place, so if m_addon is ADDON_DSP* or ADDON_ST* it checks whether DSP data is
+ appended or not: if it is, this data is copied to m_addon_bios; if not, then we are in
+ the legacy device case and data is copied from the device rom
+ After the cart has been loaded and emulation has started, only m_type is needed to later
+ handlers installation and cart accesses
+
+ Also notice that, from softlist, DSP1, 1B, 2, 3 are treated as the same device, because they
+ all have the same I/O and the only difference (i.e. the DSP data) comes from the zipfile itself.
+ OTOH, to support faulty dumps missing DSP content, we need separate legacy devices...
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "snes_slot.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type SNS_CART_SLOT = &device_creator<sns_cart_slot_device>;
+const device_type SNS_SUFAMI_CART_SLOT = &device_creator<sns_sufami_cart_slot_device>;
+const device_type SNS_BSX_CART_SLOT = &device_creator<sns_bsx_cart_slot_device>;
+
+//**************************************************************************
+// SNES Cartridge Interface
+//**************************************************************************
+
+//-------------------------------------------------
+// device_sns_cart_interface - constructor
+//-------------------------------------------------
+
+device_sns_cart_interface::device_sns_cart_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device),
+ m_rom(NULL),
+ m_nvram(NULL),
+ m_bios(NULL),
+ m_rtc_ram(NULL),
+ m_rom_size(0),
+ m_nvram_size(0),
+ m_bios_size(0),
+ m_rtc_ram_size(0)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_sns_cart_interface - destructor
+//-------------------------------------------------
+
+device_sns_cart_interface::~device_sns_cart_interface()
+{
+}
+
+//-------------------------------------------------
+// rom_alloc - alloc the space for the cart
+//-------------------------------------------------
+
+void device_sns_cart_interface::rom_alloc(running_machine &machine, UINT32 size)
+{
+ if (m_rom == NULL)
+ {
+ m_rom = auto_alloc_array_clear(machine, UINT8, size);
+ m_rom_size = size;
+ }
+}
+
+
+//-------------------------------------------------
+// nvram_alloc - alloc the space for the nvram
+//-------------------------------------------------
+
+void device_sns_cart_interface::nvram_alloc(running_machine &machine, UINT32 size)
+{
+ if (m_nvram == NULL)
+ {
+ m_nvram = auto_alloc_array_clear(machine, UINT8, size);
+ m_nvram_size = size;
+ state_save_register_item_pointer(machine, "SNES_CART", this->device().tag(), 0, m_nvram, m_nvram_size);
+ }
+}
+
+
+//-------------------------------------------------
+// rtc_ram_alloc - alloc the space for the rtc_ram
+// (needed to save it to NVRAM, will be removed
+// once the RTCs become devices and NVRAM gets
+// saved by the device itself)
+//-------------------------------------------------
+
+void device_sns_cart_interface::rtc_ram_alloc(running_machine &machine, UINT32 size)
+{
+ if (m_rtc_ram == NULL)
+ {
+ m_rtc_ram = auto_alloc_array_clear(machine, UINT8, size);
+ m_rtc_ram_size = size;
+ state_save_register_item_pointer(machine, "SNES_CART", this->device().tag(), 0, m_rtc_ram, m_rtc_ram_size);
+ }
+}
+
+
+//-------------------------------------------------
+// addon_bios_alloc - alloc the space for the
+// (optional) add-on CPU bios
+//-------------------------------------------------
+
+void device_sns_cart_interface::addon_bios_alloc(running_machine &machine, UINT32 size)
+{
+ if (m_bios == NULL)
+ {
+ m_bios = auto_alloc_array_clear(machine, UINT8, size);
+ m_bios_size = size;
+ }
+}
+
+
+//-------------------------------------------------
+// rom_map_setup - setup map of rom banks in 32K
+// blocks, so to simplify ROM access
+//-------------------------------------------------
+
+void device_sns_cart_interface::rom_map_setup(UINT32 size)
+{
+ int i;
+ // setup the rom_bank_map array to faster ROM read
+ for (i = 0; i < size / 0x8000; i++)
+ rom_bank_map[i] = i;
+
+ // fill up remaining blocks with mirrors
+ while (i % 256)
+ {
+ int j = 0, repeat_banks;
+ while ((i % (256 >> j)) && j < 8)
+ j++;
+ repeat_banks = i % (256 >> (j - 1));
+ for (int k = 0; k < repeat_banks; k++)
+ rom_bank_map[i + k] = rom_bank_map[i + k - repeat_banks];
+ i += repeat_banks;
+ }
+
+// check bank map!
+// for (i = 0; i < 256; i++)
+// {
+// printf("bank %3d = %3d\t", i, rom_bank_map[i]);
+// if ((i%8) == 7)
+// printf("\n");
+// }
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// base_sns_cart_slot_device - constructor
+//-------------------------------------------------
+base_sns_cart_slot_device::base_sns_cart_slot_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),
+ device_image_interface(mconfig, *this),
+ device_slot_interface(mconfig, *this),
+ m_addon(ADDON_NONE),
+ m_type(SNES_MODE20)
+{
+}
+
+sns_cart_slot_device::sns_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ base_sns_cart_slot_device(mconfig, SNS_CART_SLOT, "SNES Cartridge Slot", tag, owner, clock, "sns_cart_slot", __FILE__)
+{
+}
+
+sns_sufami_cart_slot_device::sns_sufami_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ base_sns_cart_slot_device(mconfig, SNS_SUFAMI_CART_SLOT, "SNES Sufami Turbo Cartridge Slot", tag, owner, clock, "sns_sufami_cart_slot", __FILE__)
+{
+}
+
+sns_bsx_cart_slot_device::sns_bsx_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ base_sns_cart_slot_device(mconfig, SNS_BSX_CART_SLOT, "SNES BS-X Cartridge Slot", tag, owner, clock, "sns_bsx_cart_slot", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// base_sns_cart_slot_device - destructor
+//-------------------------------------------------
+
+base_sns_cart_slot_device::~base_sns_cart_slot_device()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void base_sns_cart_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_sns_cart_interface *>(get_card_device());
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void base_sns_cart_slot_device::device_config_complete()
+{
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// SNES PCB
+//-------------------------------------------------
+
+
+struct sns_slot
+{
+ int pcb_id;
+ const char *slot_option;
+};
+
+// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
+static const sns_slot slot_list[] =
+{
+ { SNES_MODE20, "lorom"},
+ { SNES_BSXLO, "lorom_bsx"},
+ { SNES_CX4, "lorom_cx4"},
+ { SNES_DSP, "lorom_dsp"},
+ { SNES_DSP4, "lorom_dsp4"},
+ { SNES_OBC1, "lorom_obc1"},
+ { SNES_SA1, "lorom_sa1"},
+ { SNES_SDD1, "lorom_sdd1"},
+ { SNES_SFX, "lorom_sfx"},
+ { SNES_Z80GB, "lorom_sgb"},
+ { SNES_ST010, "lorom_st010"},
+ { SNES_ST011, "lorom_st011"},
+ { SNES_ST018, "lorom_st018"},
+ { SNES_SUFAMITURBO, "lorom_sufami"},
+ { SNES_MODE21, "hirom"},
+ { SNES_DSP_MODE21, "hirom_dsp"},
+ { SNES_BSXHI, "hirom_bsx"},
+ { SNES_SPC7110, "hirom_spc7110"},
+ { SNES_SPC7110_RTC, "hirom_spcrtc"},
+ { SNES_SRTC, "hirom_srtc"},
+ { SNES_BSX, "bsxrom"},
+ // BS-X memory packs
+ { SNES_BSMEMPAK, "bsmempak"},
+ // Sufami Turbo carts
+ { SNES_STROM, "strom"},
+ // Event carts
+ { SNES_PFEST94, "pfest94" },
+ // pirate carts
+ { SNES_POKEMON, "lorom_poke"},
+ { SNES_TEKKEN2, "lorom_tekken2"},
+ { SNES_SOULBLAD, "lorom_sbld"},
+ { SNES_MCPIR1, "lorom_mcpir1"},
+ { SNES_MCPIR2, "lorom_mcpir2"},
+ { SNES_20COL, "lorom_20col"},
+ { SNES_BANANA, "lorom_pija"}, // wip
+ { SNES_BUGS, "lorom_bugs"}, // wip
+ // legacy slots to support DSPx games from fullpath
+ { SNES_DSP1_LEG, "lorom_dsp1leg"},
+ { SNES_DSP1B_LEG, "lorom_dsp1bleg"},
+ { SNES_DSP2_LEG, "lorom_dsp2leg"},
+ { SNES_DSP3_LEG, "lorom_dsp3leg"},
+ { SNES_DSP4_LEG, "lorom_dsp4leg"},
+ { SNES_DSP1_MODE21_LEG, "hirom_dsp1leg"},
+ { SNES_ST010_LEG, "lorom_st10leg"},
+ { SNES_ST011_LEG, "lorom_st11leg"}
+};
+
+static int sns_get_pcb_id(const char *slot)
+{
+ for (int i = 0; i < ARRAY_LENGTH(slot_list); i++)
+ {
+ if (!mame_stricmp(slot_list[i].slot_option, slot))
+ return slot_list[i].pcb_id;
+ }
+
+ return 0;
+}
+
+static const char *sns_get_slot(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 "lorom";
+}
+
+
+/*-------------------------------------------------
+ SRAM handling
+ -------------------------------------------------*/
+
+/*************************************
+ * Helper functions
+ *************************************/
+
+
+/* Here we add a couple of cart utilities, to avoid duplicating the code in each DEVICE_IMAGE_LOAD */
+UINT32 base_sns_cart_slot_device::snes_skip_header( UINT8 *ROM, UINT32 rom_size )
+{
+ UINT8 header[512];
+ UINT32 offset = 512;
+
+ /* Check for a header (512 bytes) */
+ memcpy(header, ROM, 512);
+
+ if ((header[8] == 0xaa) && (header[9] == 0xbb) && (header[10] == 0x04))
+ {
+ /* Found an SWC identifier */
+ logerror("Found header (SWC) - Skipped\n");
+ }
+ else if ((header[0] | (header[1] << 8)) == (((rom_size - 512) / 1024) / 8))
+ {
+ /* Some headers have the rom size at the start, if this matches with the actual rom size, we probably have a header */
+ logerror("Found header (size) - Skipped\n");
+ }
+ else if ((rom_size % 0x8000) == 512)
+ {
+ /* As a last check we'll see if there's exactly 512 bytes extra to this image. */
+ logerror("Found header (extra) - Skipped\n");
+ }
+ else
+ {
+ /* No header found so go back to the start of the file */
+ logerror("No header found.\n");
+ offset = 0;
+ }
+
+ return offset;
+}
+
+
+/* This function assign a 'score' to data immediately after 'offset' to measure how valid they are
+ as information block (to decide if the image is HiRom, LoRom, ExLoRom or ExHiRom) */
+/* Code from bsnes, courtesy of byuu - http://byuu.org/ , based on previous code by Cowering */
+static int snes_validate_infoblock( UINT8 *infoblock, UINT32 offset )
+{
+ int score = 0;
+ UINT16 reset_vector = infoblock[offset + 0x3c] | (infoblock[offset + 0x3d] << 8);
+ UINT16 checksum = infoblock[offset + 0x1e] | (infoblock[offset + 0x1f] << 8);
+ UINT16 ichecksum = infoblock[offset + 0x1c] | (infoblock[offset + 0x1d] << 8);
+ UINT8 reset_opcode = infoblock[(offset & ~0x7fff) | (reset_vector & 0x7fff)]; //first opcode executed upon reset
+ UINT8 mapper = infoblock[offset + 0x15] & ~0x10; //mask off irrelevant FastROM-capable bit
+
+ /* $00:[000-7fff] contains uninitialized RAM and MMIO.
+ reset vector must point to ROM at $00:[8000-ffff] to be considered valid. */
+ if (reset_vector < 0x8000)
+ return 0;
+
+ /* some images duplicate the header in multiple locations, and others have completely
+ invalid header information that cannot be relied upon. The code below will analyze
+ the first opcode executed at the specified reset vector to determine the probability
+ that this is the correct header. Score is assigned accordingly. */
+
+ /* most likely opcodes */
+ if (reset_opcode == 0x78 //sei
+ || reset_opcode == 0x18 //clc (clc; xce)
+ || reset_opcode == 0x38 //sec (sec; xce)
+ || reset_opcode == 0x9c //stz $nnnn (stz $4200)
+ || reset_opcode == 0x4c //jmp $nnnn
+ || reset_opcode == 0x5c //jml $nnnnnn
+ )
+ score += 8;
+
+ /* plausible opcodes */
+ if (reset_opcode == 0xc2 //rep #$nn
+ || reset_opcode == 0xe2 //sep #$nn
+ || reset_opcode == 0xad //lda $nnnn
+ || reset_opcode == 0xae //ldx $nnnn
+ || reset_opcode == 0xac //ldy $nnnn
+ || reset_opcode == 0xaf //lda $nnnnnn
+ || reset_opcode == 0xa9 //lda #$nn
+ || reset_opcode == 0xa2 //ldx #$nn
+ || reset_opcode == 0xa0 //ldy #$nn
+ || reset_opcode == 0x20 //jsr $nnnn
+ || reset_opcode == 0x22 //jsl $nnnnnn
+ )
+ score += 4;
+
+ /* implausible opcodes */
+ if (reset_opcode == 0x40 //rti
+ || reset_opcode == 0x60 //rts
+ || reset_opcode == 0x6b //rtl
+ || reset_opcode == 0xcd //cmp $nnnn
+ || reset_opcode == 0xec //cpx $nnnn
+ || reset_opcode == 0xcc //cpy $nnnn
+ )
+ score -= 4;
+
+ /* least likely opcodes */
+ if (reset_opcode == 0x00 //brk #$nn
+ || reset_opcode == 0x02 //cop #$nn
+ || reset_opcode == 0xdb //stp
+ || reset_opcode == 0x42 //wdm
+ || reset_opcode == 0xff //sbc $nnnnnn,x
+ )
+ score -= 8;
+
+ /* Sometimes, both the header and reset vector's first opcode will match ...
+ fallback and rely on info validity in these cases to determine more likely header. */
+
+ /* a valid checksum is the biggest indicator of a valid header. */
+ if ((checksum + ichecksum) == 0xffff && (checksum != 0) && (ichecksum != 0))
+ score += 4;
+
+ /* then there are the expected mapper values */
+ if (offset == 0x007fc0 && mapper == 0x20) // 0x20 is usually LoROM
+ score += 2;
+
+ if (offset == 0x00ffc0 && mapper == 0x21) // 0x21 is usually HiROM
+ score += 2;
+
+ if (offset == 0x007fc0 && mapper == 0x22) // 0x22 is usually ExLoROM
+ score += 2;
+
+ if (offset == 0x40ffc0 && mapper == 0x25) // 0x25 is usually ExHiROM
+ score += 2;
+
+ /* finally, there are valid values in the Company, Region etc. fields */
+ if (infoblock[offset + 0x1a] == 0x33) // Company field: 0x33 indicates extended header
+ score += 2;
+
+ if (infoblock[offset + 0x16] < 0x08) // ROM Type field
+ score++;
+
+ if (infoblock[offset + 0x17] < 0x10) // ROM Size field
+ score++;
+
+ if (infoblock[offset + 0x18] < 0x08) // SRAM Size field
+ score++;
+
+ if (infoblock[offset + 0x19] < 14) // Region field
+ score++;
+
+ /* do we still have a positive score? */
+ if (score < 0)
+ score = 0;
+
+ return score;
+}
+
+/* This determines if a cart is in Mode 20, 21, 22 or 25; sets state->m_cart[0].mode and
+ state->m_cart[0].sram accordingly; and returns the offset of the internal header (needed to
+ detect BSX and ST carts) */
+static UINT32 snes_find_hilo_mode( UINT8 *buffer, UINT32 buf_len )
+{
+ UINT8 valid_mode20 = 0;
+ UINT8 valid_mode21 = 0;
+ UINT8 valid_mode25 = 0;
+ UINT32 retvalue;
+
+ /* Now to determine if this is a lo-ROM, a hi-ROM or an extended lo/hi-ROM */
+ if (buf_len > 0x007fc0)
+ valid_mode20 = snes_validate_infoblock(buffer, 0x007fc0);
+ if (buf_len > 0x00ffc0)
+ valid_mode21 = snes_validate_infoblock(buffer, 0x00ffc0);
+ if (buf_len > 0x40ffc0)
+ valid_mode25 = snes_validate_infoblock(buffer, 0x40ffc0);
+
+ /* Images larger than 32mbits are likely ExHiRom */
+ if (valid_mode25)
+ valid_mode25 += 4;
+
+ if ((valid_mode20 >= valid_mode21) && (valid_mode20 >= valid_mode25))
+ retvalue = 0x007fc0;
+ else if (valid_mode21 >= valid_mode25)
+ retvalue = 0x00ffc0;
+ else
+ retvalue = 0x40ffc0;
+
+ logerror( "\t HiROM/LoROM id: %s (LoROM: %d , HiROM: %d, ExHiROM: %d)\n",
+ (retvalue == 0x007fc0) ? "LoROM" :
+ (retvalue == 0x00ffc0) ? "HiROM" :
+ (retvalue == 0x40ffc0) ? "ExHiROM" : "Other",
+ valid_mode20, valid_mode21, valid_mode25);
+
+ return retvalue;
+}
+
+
+static int snes_find_addon_chip( UINT8 *buffer, UINT32 start_offs )
+{
+ /* Info mostly taken from http://snesemu.black-ship.net/misc/hardware/-from%20nsrt.edgeemu.com-chipinfo.htm */
+ switch (buffer[start_offs + 0x16])
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ break;
+
+ case 0x03:
+ if (buffer[start_offs + 0x15] == 0x30)
+ return ADDON_DSP4;
+ else
+ return ADDON_DSP1;
+
+ case 0x04:
+ return ADDON_DSP1;
+
+ case 0x05:
+ // DSP2 can be detected by (buffer[start_offs + 0x15] == 0x20)
+ // DSP3 is harder to detect, and one has to rely on the manufacturer (Bandai)
+ // by checking (buffer[start_offs + 0x15] == 0x30) && (buffer[start_offs + 0x1a] == 0xb2)
+ // in other cases is DSP1, but we do treat all these together...
+ if (buffer[start_offs + 0x15] == 0x20)
+ return ADDON_DSP2;
+ else if ((buffer[start_offs + 0x15] == 0x30) && (buffer[start_offs + 0x1a] == 0xb2))
+ return ADDON_DSP3;
+ else
+ return ADDON_DSP1;
+
+ case 0x13: // Mario Chip 1
+ case 0x14: // GSU-x
+ case 0x15: // GSU-x
+ case 0x1a: // GSU-1 (21 MHz at start)
+ if (buffer[start_offs + 0x15] == 0x20)
+ return ADDON_SFX;
+ break;
+
+ case 0x25:
+ return ADDON_OBC1;
+
+ case 0x32: // needed by a Sample game (according to ZSNES)
+ case 0x34:
+ case 0x35:
+ if (buffer[start_offs + 0x15] == 0x23)
+ return ADDON_SA1;
+ break;
+
+ case 0x43:
+ case 0x45:
+ if (buffer[start_offs + 0x15] == 0x32)
+ return ADDON_SDD1;
+ break;
+
+ case 0x55:
+ if (buffer[start_offs + 0x15] == 0x35)
+ return ADDON_SRTC;
+ break;
+
+ case 0xe3:
+ return ADDON_Z80GB;
+
+ case 0xf3:
+ return ADDON_CX4;
+
+ case 0xf5:
+ if (buffer[start_offs + 0x15] == 0x30)
+ return ADDON_ST018;
+ else if (buffer[start_offs + 0x15] == 0x3a)
+ return ADDON_SPC7110;
+ break;
+
+ case 0xf6:
+ /* These Seta ST-01X chips have both 0x30 at 0xffd5,
+ they only differ for the 'size' at 0xffd7 */
+ if (buffer[start_offs + 0x17] < 0x0a)
+ return ADDON_ST011;
+ else
+ return ADDON_ST010;
+
+ case 0xf9:
+ if (buffer[start_offs + 0x15] == 0x3a)
+ return ADDON_SPC7110_RTC;
+ break;
+
+ default:
+ break;
+ }
+ return -1;
+}
+
+
+/*-------------------------------------------------
+ call load
+ -------------------------------------------------*/
+
+
+bool base_sns_cart_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ UINT8 *ROM;
+ UINT32 len, offset = 0;
+ const char *slot_name;
+
+ /* Check for a header (512 bytes), and skip it if found */
+ if (software_entry() == NULL)
+ {
+ UINT32 tmplen = length();
+ UINT8 *tmpROM = global_alloc_array(UINT8, tmplen);
+ fread(tmpROM, tmplen);
+ offset = snes_skip_header(tmpROM, tmplen);
+ fseek(offset, SEEK_SET);
+ global_free(tmpROM);
+ }
+
+ len = (software_entry() == NULL) ? (length() - offset) : get_software_region_length("rom");
+
+ m_cart->rom_alloc(machine(), len);
+ ROM = m_cart->get_rom_base();
+ if (software_entry() == NULL)
+ fread(ROM, len);
+ else
+ memcpy(ROM, get_software_region("rom"), len);
+
+ m_cart->rom_map_setup(len);
+
+ // check for on-cart CPU bios
+ if (software_entry() != NULL)
+ {
+ if (get_software_region("addon"))
+ {
+ m_cart->addon_bios_alloc(machine(), get_software_region_length("addon"));
+ memcpy(m_cart->get_addon_bios_base(), get_software_region("addon"), get_software_region_length("addon"));
+ }
+ }
+
+ // get pcb type
+ if (software_entry() == NULL)
+ get_cart_type_addon(ROM, len, m_type, m_addon);
+ else
+ {
+ if ((slot_name = get_feature("slot")) == NULL)
+ m_type = SNES_MODE20;
+ else
+ m_type = sns_get_pcb_id(slot_name);
+
+ if (m_type == SNES_DSP && len > 0x100000)
+ m_type = SNES_DSP_2MB;
+ }
+
+ if (software_entry() == NULL)
+ setup_addon_from_fullpath();
+
+ // in carts with an add-on CPU having internal dump, this speeds up access to the internal rom
+ // by installing read_bank in address space and mapping m_bios there
+ m_cart->speedup_addon_bios_access();
+
+
+ setup_nvram();
+
+ if (m_cart->get_nvram_size() || m_cart->get_rtc_ram_size())
+ {
+ UINT32 tot_size = m_cart->get_nvram_size() + m_cart->get_rtc_ram_size();
+ UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size);
+ battery_load(temp_nvram, tot_size, 0xff);
+ if (m_cart->get_nvram_size())
+ memcpy(m_cart->get_nvram_base(), temp_nvram, m_cart->get_nvram_size());
+ if (m_cart->get_rtc_ram_size())
+ memcpy(m_cart->get_rtc_ram_base(), temp_nvram + m_cart->get_nvram_size(), m_cart->get_rtc_ram_size());
+
+ if (temp_nvram)
+ auto_free(machine(), temp_nvram);
+ }
+
+ //printf("Type %d\n", m_type);
+
+ internal_header_logging(ROM, len);
+
+ return IMAGE_INIT_PASS;
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/*-------------------------------------------------
+ call_unload
+ -------------------------------------------------*/
+
+void base_sns_cart_slot_device::call_unload()
+{
+ if (m_cart)
+ {
+ if (m_cart->get_nvram_size() || m_cart->get_rtc_ram_size())
+ {
+ UINT32 tot_size = m_cart->get_nvram_size() + m_cart->get_rtc_ram_size();
+ UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size);
+ if (m_cart->get_nvram_size())
+ memcpy(temp_nvram, m_cart->get_nvram_base(), m_cart->get_nvram_size());
+ if (m_cart->get_rtc_ram_size())
+ memcpy(temp_nvram + m_cart->get_nvram_size(), m_cart->get_rtc_ram_base(), m_cart->get_rtc_ram_size());
+
+ battery_save(temp_nvram, tot_size);
+ if (temp_nvram)
+ auto_free(machine(), temp_nvram);
+ }
+ }
+}
+
+
+void base_sns_cart_slot_device::setup_addon_from_fullpath()
+{
+ // if we already have an add-on bios or if no addon has been detected, we have nothing to do
+ if (m_cart->get_addon_bios_size() || m_addon == ADDON_NONE)
+ return;
+
+ // check if the add-on dump is appended to the file
+ // if this is the case, copy it in m_bios and refresh
+ // the rom_bank_map with correct game rom size
+ switch (m_addon)
+ {
+ case ADDON_DSP1:
+ case ADDON_DSP1B:
+ case ADDON_DSP2:
+ case ADDON_DSP3:
+ case ADDON_DSP4:
+ // check for add-on dump
+ if ((m_cart->get_rom_size() & 0x7fff) == 0x2800)
+ {
+ logerror("Found NEC DSP dump at the bottom of the ROM.\n");
+ m_cart->addon_bios_alloc(machine(), 0x2800);
+ memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2800), 0x2800);
+ m_cart->rom_map_setup(m_cart->get_rom_size() - 0x2800);
+ }
+ // check for byuu's compressed version (swapped order of bytes and stripped fixed 0x00 bytes)
+ if ((m_cart->get_rom_size() & 0x7fff) == 0x2000)
+ {
+ logerror("Found NEC DSP dump (byuu's version) at the bottom of the ROM.\n");
+ m_cart->addon_bios_alloc(machine(), 0x2800);
+ for (int i = 0; i < 0x800; i++)
+ {
+ memcpy(m_cart->get_addon_bios_base() + i * 4 + 2, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 0, 1);
+ memcpy(m_cart->get_addon_bios_base() + i * 4 + 1, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 1, 1);
+ memcpy(m_cart->get_addon_bios_base() + i * 4 + 0, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 2, 1);
+ memset(m_cart->get_addon_bios_base() + i * 4 + 3, 0xff, 1);
+ }
+ memcpy(m_cart->get_addon_bios_base() + 0x2000, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x1800), 0x800);
+ m_cart->rom_map_setup(m_cart->get_rom_size() - 0x2000);
+ }
+ break;
+ case ADDON_ST010:
+ case ADDON_ST011:
+ // check for add-on dump
+ if ((m_cart->get_rom_size() & 0x3ffff) == 0x11000)
+ {
+ logerror("Found Seta DSP dump at the bottom of the ROM.\n");
+ m_cart->addon_bios_alloc(machine(), 0x11000);
+ memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x11000), 0x11000);
+ m_cart->rom_map_setup(m_cart->get_rom_size() - 0x11000);
+ }
+ // check for byuu's compressed version (swapped order of bytes and stripped fixed 0x00 bytes)
+ if ((m_cart->get_rom_size() & 0xffff) == 0xd000)
+ {
+ logerror("Found Seta DSP dump (byuu's version) at the bottom of the ROM.\n");
+ m_cart->addon_bios_alloc(machine(), 0x11000);
+ for (int i = 0; i < 0x4000; i++)
+ {
+ memcpy(m_cart->get_addon_bios_base() + i * 4 + 2, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 0, 1);
+ memcpy(m_cart->get_addon_bios_base() + i * 4 + 1, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 1, 1);
+ memcpy(m_cart->get_addon_bios_base() + i * 4 + 0, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 2, 1);
+ memset(m_cart->get_addon_bios_base() + i * 4 + 3, 0xff, 1);
+ }
+ memcpy(m_cart->get_addon_bios_base() + 0x10000, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xc000), 0x1000);
+ m_cart->rom_map_setup(m_cart->get_rom_size() - 0xd000);
+ }
+ break;
+ case ADDON_CX4:
+ if ((m_cart->get_rom_size() & 0x7fff) == 0x0c00)
+ {
+ logerror("Found CX4 dump at the bottom of the ROM.\n");
+ m_cart->addon_bios_alloc(machine(), 0x0c00);
+ memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x0c00), 0x0c00);
+ m_cart->rom_map_setup(m_cart->get_rom_size() - 0x0c00);
+ }
+ break;
+ case ADDON_ST018:
+ if ((m_cart->get_rom_size() & 0x3ffff) == 0x28000)
+ {
+ logerror("Found ST018 dump at the bottom of the ROM.\n");
+ m_cart->addon_bios_alloc(machine(), 0x28000);
+ memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x28000), 0x28000);
+ m_cart->rom_map_setup(m_cart->get_rom_size() - 0x28000);
+ }
+ break;
+ }
+
+ // otherwise, we need to use the legacy versions including DSP dump in device romset
+ if (!m_cart->get_addon_bios_size())
+ {
+ astring region(m_cart->device().tag(), ":addon");
+ UINT8 *ROM = NULL;
+
+ switch (m_addon)
+ {
+ case ADDON_DSP1:
+ ROM = machine().root_device().memregion(region)->base();
+ m_cart->addon_bios_alloc(machine(), 0x2800);
+ memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800);
+ break;
+ case ADDON_DSP1B:
+ ROM = machine().root_device().memregion(region)->base();
+ m_cart->addon_bios_alloc(machine(), 0x2800);
+ memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800);
+ break;
+ case ADDON_DSP2:
+ ROM = machine().root_device().memregion(region)->base();
+ m_cart->addon_bios_alloc(machine(), 0x2800);
+ memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800);
+ break;
+ case ADDON_DSP3:
+ ROM = machine().root_device().memregion(region)->base();
+ m_cart->addon_bios_alloc(machine(), 0x2800);
+ memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800);
+ break;
+ case ADDON_DSP4:
+ ROM = machine().root_device().memregion(region)->base();
+ m_cart->addon_bios_alloc(machine(), 0x2800);
+ memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800);
+ break;
+ case ADDON_ST010:
+ ROM = machine().root_device().memregion(region)->base();
+ m_cart->addon_bios_alloc(machine(), 0x11000);
+ memcpy(m_cart->get_addon_bios_base(), ROM, 0x11000);
+ break;
+ case ADDON_ST011:
+ ROM = machine().root_device().memregion(region)->base();
+ m_cart->addon_bios_alloc(machine(), 0x11000);
+ memcpy(m_cart->get_addon_bios_base(), ROM, 0x11000);
+ break;
+ }
+ }
+
+}
+
+void base_sns_cart_slot_device::setup_nvram()
+{
+ UINT8 *ROM = (UINT8 *)m_cart->get_rom_base();
+ UINT32 size = 0;
+ if (software_entry() == NULL)
+ {
+ int hilo_mode = snes_find_hilo_mode(ROM, m_cart->get_rom_size());
+ UINT8 sram_size = (m_type == SNES_SFX) ? (ROM[0x00ffbd] & 0x07) : (ROM[hilo_mode + 0x18] & 0x07);
+ if (sram_size)
+ {
+ UINT32 max = (hilo_mode == 0x007fc0) ? 0x80000 : 0x20000; // MODE20 vs MODE21
+ size = 1024 << sram_size;
+ if (size > max)
+ size = max;
+ }
+ }
+ else
+ {
+ if (get_software_region("nvram"))
+ size = get_software_region_length("nvram");
+ }
+
+ if (size)
+ m_cart->nvram_alloc(machine(), size);
+
+ if (m_type == SNES_STROM)
+ m_cart->nvram_alloc(machine(), 0x20000);
+ if (m_type == SNES_BSX)
+ m_cart->nvram_alloc(machine(), 0x8000);
+
+ // setup also RTC SRAM, when needed (to be removed when RTCs are converted to devices)
+ if (m_type == SNES_SRTC)
+ m_cart->rtc_ram_alloc(machine(), 13);
+ if (m_type == SNES_SPC7110_RTC)
+ m_cart->rtc_ram_alloc(machine(), 16);
+}
+
+
+
+/*-------------------------------------------------
+ call softlist load
+ -------------------------------------------------*/
+
+bool base_sns_cart_slot_device::call_softlist_load(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry );
+ return TRUE;
+}
+
+void base_sns_cart_slot_device::get_cart_type_addon(UINT8 *ROM, UINT32 len, int &type, int &addon)
+{
+ // First, look if the cart is HiROM or LoROM (and set snes_cart accordingly)
+ int hilo_mode = snes_find_hilo_mode(ROM, len);
+
+ switch (hilo_mode)
+ {
+ case 0x007fc0: // LoRom & ExLoRom
+ type = SNES_MODE20;
+ break;
+ case 0x00ffc0: // HiRom
+ case 0x40ffc0: // ExHiRom
+ type = SNES_MODE21;
+ break;
+ default:
+ break;
+ }
+
+ // detect Sufami Turbo...
+ if (type == SNES_MODE20 && !memcmp(ROM, "BANDAI SFC-ADX", 14))
+ {
+ if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14))
+ type = SNES_SUFAMITURBO;
+ else
+ type = SNES_STROM;
+ }
+
+ // detect BS-X Base Cart
+ if (!memcmp(ROM + hilo_mode, "Satellaview BS-X ", 21))
+ type = SNES_BSX;
+ // Detect BS-X Flash Cart
+ if ((ROM[hilo_mode + 0x13] == 0x00 || ROM[hilo_mode + 0x13] == 0xff) && ROM[hilo_mode + 0x14] == 0x00)
+ {
+ UINT8 n15 = ROM[hilo_mode + 0x15];
+ if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc)
+ {
+ if (ROM[hilo_mode + 0x1a] == 0x33 || ROM[hilo_mode + 0x1a] == 0xff)
+ type = SNES_BSMEMPAK;
+ }
+ }
+
+ // check for add-on chips...
+ if (len >= hilo_mode + 0x1a)
+ {
+ addon = snes_find_addon_chip(ROM, hilo_mode);
+ if (addon != -1)
+ {
+ // m_type handles DSP1,2,3 in the same way, but snes_add requires them to be separate...
+ switch (addon)
+ {
+ case ADDON_CX4:
+ type = SNES_CX4;
+ break;
+ case ADDON_DSP1:
+ case ADDON_DSP1B:
+ case ADDON_DSP2:
+ case ADDON_DSP3:
+ if (type == SNES_MODE20 && len > 0x100000)
+ type = SNES_DSP_2MB;
+ else if (type == SNES_MODE21)
+ type = SNES_DSP_MODE21;
+ else
+ type = SNES_DSP;
+ break;
+ case ADDON_DSP4:
+ type = SNES_DSP4;
+ break;
+ case ADDON_OBC1:
+ type = SNES_OBC1;
+ break;
+ case ADDON_SA1:
+ type = SNES_SA1;
+ break;
+ case ADDON_SDD1:
+ type = SNES_SDD1;
+ break;
+ case ADDON_SFX:
+ type = SNES_SFX;
+ break;
+ case ADDON_SPC7110:
+ type = SNES_SPC7110;
+ break;
+ case ADDON_SPC7110_RTC:
+ type = SNES_SPC7110_RTC;
+ break;
+ case ADDON_ST010:
+ type = SNES_ST010;
+ break;
+ case ADDON_ST011:
+ type = SNES_ST011;
+ break;
+ case ADDON_ST018:
+ type = SNES_ST018;
+ break;
+ case ADDON_SRTC:
+ type = SNES_SRTC;
+ break;
+ case ADDON_Z80GB:
+ type = SNES_Z80GB;
+ break;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ get default card software
+ -------------------------------------------------*/
+
+const char * base_sns_cart_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ bool fullpath = open_image_file(options);
+
+ if (fullpath)
+ {
+ const char *slot_string = "lorom";
+ UINT32 offset = 0;
+ UINT32 len = core_fsize(m_file);
+ UINT8 *ROM = global_alloc_array(UINT8, len);
+ int type = 0, addon = 0;
+
+ core_fread(m_file, ROM, len);
+
+ offset = snes_skip_header(ROM, len);
+
+ get_cart_type_addon(ROM + offset, len - offset, type, addon);
+ // here we're from fullpath, so check if it's a DSP game which needs legacy device (i.e. it has no appended DSP dump)
+ switch (addon)
+ {
+ case ADDON_DSP1:
+ if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000)
+ {
+ if (type == SNES_DSP_MODE21)
+ type = SNES_DSP1_MODE21_LEG;
+ else
+ type = SNES_DSP1_LEG;
+ }
+ break;
+ case ADDON_DSP1B:
+ if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000)
+ type = SNES_DSP1B_LEG;
+ break;
+ case ADDON_DSP2:
+ if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000)
+ type = SNES_DSP2_LEG;
+ break;
+ case ADDON_DSP3:
+ if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000)
+ type = SNES_DSP3_LEG;
+ break;
+ case ADDON_DSP4:
+ if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000)
+ type = SNES_DSP4_LEG;
+ break;
+ case ADDON_ST010:
+ if ((len & 0x3ffff) != 0x11000 && (len & 0xffff) != 0xd000)
+ type = SNES_ST010_LEG;
+ break;
+ case ADDON_ST011:
+ if ((len & 0x3ffff) != 0x11000 && (len & 0xffff) != 0xd000)
+ type = SNES_ST011_LEG;
+ break;
+ }
+
+ slot_string = sns_get_slot(type);
+
+ global_free(ROM);
+ clear();
+
+ return slot_string;
+ }
+
+ return software_get_default_slot(config, options, this, "lorom");
+}
+
+
+/*-------------------------------------------------
+ read
+ -------------------------------------------------*/
+
+READ8_MEMBER(base_sns_cart_slot_device::read_l)
+{
+ if (m_cart)
+ return m_cart->read_l(space, offset);
+ else
+ return 0xff;
+}
+
+READ8_MEMBER(base_sns_cart_slot_device::read_h)
+{
+ if (m_cart)
+ return m_cart->read_h(space, offset);
+ else
+ return 0xff;
+}
+
+READ8_MEMBER(base_sns_cart_slot_device::read_ram)
+{
+ if (m_cart)
+ return m_cart->read_ram(space, offset);
+ else
+ return 0xff;
+}
+
+READ8_MEMBER(base_sns_cart_slot_device::chip_read)
+{
+ if (m_cart)
+ return m_cart->chip_read(space, offset);
+ else
+ return 0xff;
+}
+
+/*-------------------------------------------------
+ write
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(base_sns_cart_slot_device::write_l)
+{
+ if (m_cart)
+ m_cart->write_l(space, offset, data);
+}
+
+WRITE8_MEMBER(base_sns_cart_slot_device::write_h)
+{
+ if (m_cart)
+ m_cart->write_h(space, offset, data);
+}
+
+WRITE8_MEMBER(base_sns_cart_slot_device::write_ram)
+{
+ if (m_cart)
+ m_cart->write_ram(space, offset, data);
+}
+
+WRITE8_MEMBER(base_sns_cart_slot_device::chip_write)
+{
+ if (m_cart)
+ m_cart->chip_write(space, offset, data);
+}
+
+
+/*-------------------------------------------------
+ Internal header logging
+ -------------------------------------------------*/
+
+/* We use this to convert the company_id in the header to int value to be passed in companies[] */
+static int char_to_int_conv( char id )
+{
+ int value;
+
+ if (id == '1') value = 0x01;
+ else if (id == '2') value = 0x02;
+ else if (id == '3') value = 0x03;
+ else if (id == '4') value = 0x04;
+ else if (id == '5') value = 0x05;
+ else if (id == '6') value = 0x06;
+ else if (id == '7') value = 0x07;
+ else if (id == '8') value = 0x08;
+ else if (id == '9') value = 0x09;
+ else if (id == 'A') value = 0x0a;
+ else if (id == 'B') value = 0x0b;
+ else if (id == 'C') value = 0x0c;
+ else if (id == 'D') value = 0x0d;
+ else if (id == 'E') value = 0x0e;
+ else if (id == 'F') value = 0x0f;
+ else value = 0x00;
+
+ return value;
+}
+
+#define UNK "UNKNOWN"
+
+void base_sns_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 len)
+{
+ static const char *const cart_types[] =
+ {
+ "ROM (LoROM)",
+ "ROM (HiROM)",
+ "ROM (ExLoROM)",
+ "ROM (ExHiROM)",
+ "ROM, CX4",
+ "ROM, DSP-1,2,3 (LoROM)",
+ "ROM, DSP-1 (LoROM 2MB)",
+ "ROM, DSP-1 (HiROM)",
+ "ROM, DSP-4",
+ "ROM, OBC-1",
+ "ROM, SA-1",
+ "ROM, S-DD1",
+ "ROM, Super FX / FX2",
+ "ROM, SPC7110",
+ "ROM, SPC7110, RTC",
+ "ROM, S-RTC",
+ "ROM, Seta ST-010",
+ "ROM, Seta ST-011",
+ "ROM, Seta ST-018",
+ "ROM, Z80GB (Super Game Boy)",
+ "ROM, BS-X Base cart",
+ "ROM, BS-X compatible (LoROM)",
+ "ROM, BS-X compatible (HiROM)",
+ "BS-X memory pack",
+ "ROM, Sufami Turbo",
+ "Sufami Turbo cart",
+ // pirate cart types which are not recognized from fullpath
+ UNK,
+ UNK,
+ UNK
+ };
+
+ /* Some known countries */
+ static const char *const countries[] =
+ {
+ /* 0*/ "Japan (NTSC)", "USA & Canada (NTSC)", "Europe, Oceania & Asia (PAL)", "Sweden (PAL)",
+ /* 4*/ "Finland (PAL)", "Denmark (PAL)", "France (PAL)", "Holland (PAL)",
+ /* 8*/ "Spain (PAL)", "Germany, Austria & Switzerland (PAL)", "Italy (PAL)", "Hong Kong & China (PAL)",
+ /* c*/ "Indonesia (PAL)", "South Korea (NTSC)", UNK, UNK,
+ };
+
+ /* Some known companies (integrations to the list from Snes9x) */
+ static const char *const companies[] =
+ {
+ /* 0*/ "Invalid", "Nintendo", "Ajinomoto", "Imagineer-Zoom", "Chris Gray Enterprises Inc.", "Zamuse", "Falcom", UNK,
+ /* 8*/ "Capcom", "HOT-B", "Jaleco", "Coconuts", "Rage Software", "Micronet", "Technos", "Mebio Software",
+ /*10*/ "SHOUEi System", "Starfish", "Gremlin Graphics", "Electronic Arts", "NCS / Masaya", "COBRA Team", "Human/Field", "KOEI",
+ /*18*/ "Hudson Soft", "Game Village", "Yanoman", UNK, "Tecmo", UNK, "Open System", "Virgin Games",
+ /*20*/ "KSS", "Sunsoft", "POW", "Micro World", UNK, UNK, "Enix", "Loriciel/Electro Brain",
+ /*28*/ "Kemco", "Seta Co.,Ltd.", "Culture Brain", "Irem Japan", "Pal Soft", "Visit Co.,Ltd.", "INTEC Inc.", "System Sacom Corp.",
+ /*30*/ "Viacom New Media", "Carrozzeria", "Dynamic", "Nintendo", "Magifact", "Hect", UNK, UNK,
+ /*38*/ "Capcom Europe", "Accolade Europe", UNK, "Arcade Zone", "Empire Software", "Loriciel", "Gremlin Graphics", UNK,
+ /*40*/ "Seika Corp.", "UBI Soft", UNK, UNK, "LifeFitness Exertainment", UNK, "System 3", "Spectrum Holobyte",
+ /*48*/ UNK, "Irem", UNK, "Raya Systems/Sculptured Software", "Renovation Products", "Malibu Games/Black Pearl", UNK, "U.S. Gold",
+ /*50*/ "Absolute Entertainment", "Acclaim", "Activision", "American Sammy", "GameTek", "Hi Tech Expressions", "LJN Toys", UNK,
+ /*58*/ UNK, UNK, "Mindscape", "Romstar, Inc.", UNK, "Tradewest", UNK, "American Softworks Corp.",
+ /*60*/ "Titus", "Virgin Interactive Entertainment", "Maxis", "Origin/FCI/Pony Canyon", UNK, UNK, UNK, "Ocean",
+ /*68*/ UNK, "Electronic Arts", UNK, "Laser Beam", UNK, UNK, "Elite", "Electro Brain",
+ /*70*/ "Infogrames", "Interplay", "LucasArts", "Parker Brothers", "Konami", "STORM", UNK, UNK,
+ /*78*/ "THQ Software", "Accolade Inc.", "Triffix Entertainment", UNK, "Microprose", UNK, UNK, "Kemco",
+ /*80*/ "Misawa", "Teichio", "Namco Ltd.", "Lozc", "Koei", UNK, "Tokuma Shoten Intermedia", "Tsukuda Original",
+ /*88*/ "DATAM-Polystar", UNK, UNK, "Bullet-Proof Software", "Vic Tokai", UNK, "Character Soft", "I\'\'Max",
+ /*90*/ "Takara", "CHUN Soft", "Video System Co., Ltd.", "BEC", UNK, "Varie", "Yonezawa / S'Pal Corp.", "Kaneco",
+ /*98*/ UNK, "Pack in Video", "Nichibutsu", "TECMO", "Imagineer Co.", UNK, UNK, UNK,
+ /*a0*/ "Telenet", "Hori", UNK, UNK, "Konami", "K.Amusement Leasing Co.", UNK, "Takara",
+ /*a8*/ UNK, "Technos Jap.", "JVC", UNK, "Toei Animation", "Toho", UNK, "Namco Ltd.",
+ /*b0*/ "Media Rings Corp.", "ASCII Co. Activison", "Bandai", UNK, "Enix America", UNK, "Halken", UNK,
+ /*b8*/ UNK, UNK, "Culture Brain", "Sunsoft", "Toshiba EMI", "Sony Imagesoft", UNK, "Sammy",
+ /*c0*/ "Taito", UNK, "Kemco", "Square", "Tokuma Soft", "Data East", "Tonkin House", UNK,
+ /*c8*/ "KOEI", UNK, "Konami USA", "NTVIC", UNK, "Meldac", "Pony Canyon", "Sotsu Agency/Sunrise",
+ /*d0*/ "Disco/Taito", "Sofel", "Quest Corp.", "Sigma", "Ask Kodansha Co., Ltd.", UNK, "Naxat", UNK,
+ /*d8*/ "Capcom Co., Ltd.", "Banpresto", "Tomy", "Acclaim", UNK, "NCS", "Human Entertainment", "Altron",
+ /*e0*/ "Jaleco", UNK, "Yutaka", UNK, "T&ESoft", "EPOCH Co.,Ltd.", UNK, "Athena",
+ /*e8*/ "Asmik", "Natsume", "King Records", "Atlus", "Sony Music Entertainment", UNK, "IGS", UNK,
+ /*f0*/ UNK, "Motown Software", "Left Field Entertainment", "Beam Software", "Tec Magik", UNK, UNK, UNK,
+ /*f8*/ UNK, "Cybersoft", UNK, "Psygnosis", UNK, UNK, "Davidson", UNK,
+ };
+
+ int hilo_mode = snes_find_hilo_mode(ROM, len);
+ char title[21], rom_id[4], company_id[2];
+ int type = 0, company, addon, has_ram = 0, has_sram = 0;
+ switch (hilo_mode)
+ {
+ case 0x007fc0:
+ if ((ROM[0x007fd5] == 0x32) || (len > 0x401000))
+ type = SNES_MODE22; // ExLoRom
+ else
+ type = SNES_MODE20; // LoRom
+ type = SNES_MODE20; // LoRom & ExLoRom
+ break;
+ case 0x00ffc0:
+ type = SNES_MODE21; // HiRom
+ break;
+ case 0x40ffc0:
+ type = SNES_MODE25; // ExHiRom
+ break;
+ default:
+ break;
+ }
+
+ // detect Sufami Turbo...
+ if (type == SNES_MODE20 && !memcmp(ROM, "BANDAI SFC-ADX", 14))
+ {
+ if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14))
+ type = SNES_SUFAMITURBO;
+ else
+ type = SNES_STROM;
+ }
+
+ // detect BS-X Base Cart
+ if (!memcmp(ROM + hilo_mode, "Satellaview BS-X ", 21))
+ type = SNES_BSX;
+ // Detect BS-X Flash Cart
+ if ((ROM[hilo_mode + 0x13] == 0x00 || ROM[hilo_mode + 0x13] == 0xff) && ROM[hilo_mode + 0x14] == 0x00)
+ {
+ UINT8 n15 = ROM[hilo_mode + 0x15];
+ if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc)
+ {
+ if (ROM[hilo_mode + 0x1a] == 0x33 || ROM[hilo_mode + 0x1a] == 0xff)
+ type = SNES_BSMEMPAK;
+ }
+ }
+
+ addon = snes_find_addon_chip(ROM, hilo_mode);
+ if (addon != -1)
+ {
+ if (type == SNES_MODE20 && addon == SNES_DSP)
+ {
+ if (len > 0x100000)
+ type = SNES_DSP_2MB;
+ else
+ type = SNES_DSP;
+ }
+ else if (type == SNES_MODE21 && addon == SNES_DSP)
+ type = SNES_DSP_MODE21;
+ else
+ type = addon;
+ }
+
+ /* Company */
+ for (int i = 0; i < 2; i++)
+ company_id[i] = ROM[hilo_mode - 0x10 + i];
+ company = (char_to_int_conv(company_id[0]) << 4) + char_to_int_conv(company_id[1]);
+ if (company == 0)
+ company = ROM[hilo_mode + 0x1a];
+
+ /* ROM ID */
+ for(int i = 0; i < 4; i++ )
+ rom_id[i] = ROM[hilo_mode - 0x0e + i];
+
+ /* Title */
+ for(int i = 0; i < 21; i++ )
+ title[i] = ROM[hilo_mode + i];
+
+ /* RAM */
+ if (((ROM[hilo_mode + 0x16] & 0xf) == 1) ||
+ ((ROM[hilo_mode + 0x16] & 0xf) == 2) ||
+ ((ROM[hilo_mode + 0x16] & 0xf) == 4) ||
+ ((ROM[hilo_mode + 0x16] & 0xf) == 5))
+ has_ram = 1;
+
+ /* SRAM */
+ if (((ROM[hilo_mode + 0x16] & 0xf) == 2) ||
+ ((ROM[hilo_mode + 0x16] & 0xf) == 5) ||
+ ((ROM[hilo_mode + 0x16] & 0xf) == 6))
+ has_sram = 1;
+
+ logerror( "ROM DETAILS\n" );
+ logerror( "===========\n\n" );
+ logerror( "\tTotal blocks: 0x%x\n", len);
+ logerror( "\tROM bank size: %s \n",
+ (type == SNES_MODE20) ? "LoROM" :
+ (type == SNES_MODE21) ? "HiROM" :
+ (type == SNES_MODE22) ? "ExLoROM" :
+ (type == SNES_MODE25) ? "ExHiROM" : "Other (BSX or ST)" );
+ logerror( "\tCompany: %s [%.2s]\n", companies[company], company_id );
+ logerror( "\tROM ID: %.4s\n\n", rom_id );
+
+ logerror( "HEADER DETAILS\n" );
+ logerror( "==============\n\n" );
+ logerror( "\tName: %.21s\n", title );
+ logerror( "\tSpeed: %s [%d]\n", (ROM[hilo_mode + 0x15] & 0xf0) ? "FastROM" : "SlowROM", (ROM[hilo_mode + 0x15] & 0xf0) >> 4);
+ logerror( "\tBank size: %s [%d]\n", (ROM[hilo_mode + 0x15] & 0xf) ? "HiROM" : "LoROM", ROM[hilo_mode + 0x15] & 0xf);
+
+ logerror( "\tType: %s", cart_types[type]);
+ if (has_ram)
+ logerror( ", RAM");
+ if (has_sram)
+ logerror( ", SRAM");
+ logerror( " [%d]\n", ROM[hilo_mode + 0x16]);
+
+ logerror( "\tSize: %d megabits [%d]\n", 1 << (ROM[hilo_mode + 0x17] - 7), ROM[hilo_mode + 0x17]);
+ logerror( "\tSRAM: %d kilobits [%d]\n", ROM[hilo_mode + 0x18] * 8, ROM[hilo_mode + 0x18] );
+ assert(ROM[hilo_mode + 0x19] >= 0 && ROM[hilo_mode + 0x19] < ARRAY_LENGTH(countries));
+ logerror( "\tCountry: %s [%d]\n", countries[ROM[hilo_mode + 0x19]], ROM[hilo_mode + 0x19]);
+ logerror( "\tLicense: %s [%X]\n", companies[ROM[hilo_mode + 0x1a]], ROM[hilo_mode + 0x1a]);
+ logerror( "\tVersion: 1.%d\n", ROM[hilo_mode + 0x1b]);
+ logerror( "\tInv Checksum: %X %X\n", ROM[hilo_mode + 0x1d], ROM[hilo_mode + 0x1c]);
+ logerror( "\tChecksum: %X %X\n", ROM[hilo_mode + 0x1f], ROM[hilo_mode + 0x1e]);
+ logerror( "\tNMI Address: %2X%2Xh\n", ROM[hilo_mode + 0x3b], ROM[hilo_mode + 0x3a]);
+ logerror( "\tStart Address: %2X%2Xh\n\n", ROM[hilo_mode + 0x3d], ROM[hilo_mode + 0x3c]);
+
+ logerror( "\tMode: %d\n", type);
+}
diff --git a/src/emu/bus/snes/snes_slot.h b/src/emu/bus/snes/snes_slot.h
new file mode 100644
index 00000000000..a5710cda74b
--- /dev/null
+++ b/src/emu/bus/snes/snes_slot.h
@@ -0,0 +1,275 @@
+#ifndef __SNS_SLOT_H
+#define __SNS_SLOT_H
+
+/***************************************************************************
+ TYPE DEFINITIONS
+ ***************************************************************************/
+
+// offset of add-on dumps inside snes_add/snesp_add bios, to support old dumps missing add-on data
+#define SNES_DSP1_OFFSET (0x00000)
+#define SNES_DSP1B_OFFSET (0x03000)
+#define SNES_DSP2_OFFSET (0x06000)
+#define SNES_DSP3_OFFSET (0x09000)
+#define SNES_DSP4_OFFSET (0x0c000)
+#define SNES_ST10_OFFSET (0x0f000)
+#define SNES_ST11_OFFSET (0x20000)
+#define SNES_CX4_OFFSET (0x31000)
+#define SNES_ST18_OFFSET1 (0x32000)
+#define SNES_ST18_OFFSET2 (0x52000)
+
+
+/* PCB */
+enum
+{
+ SNES_MODE20 = 0,
+ SNES_MODE21,
+ SNES_MODE22, // ExLoROM - not used anymore in emulation (only to log info), will be removed
+ SNES_MODE25, // ExHiROM - not used anymore in emulation (only to log info), will be removed
+ SNES_CX4,
+ SNES_DSP,
+ SNES_DSP_2MB,
+ SNES_DSP_MODE21,
+ SNES_DSP4,
+ SNES_OBC1,
+ SNES_SA1,
+ SNES_SDD1,
+ SNES_SFX,
+ SNES_SPC7110,
+ SNES_SPC7110_RTC,
+ SNES_SRTC,
+ SNES_ST010,
+ SNES_ST011,
+ SNES_ST018,
+ SNES_Z80GB,
+ SNES_PFEST94,
+ SNES_BSX,
+ SNES_BSXLO,
+ SNES_BSXHI,
+ SNES_BSMEMPAK,
+ SNES_SUFAMITURBO,
+ SNES_STROM,
+ // pirate carts
+ SNES_POKEMON,
+ SNES_TEKKEN2,
+ SNES_SOULBLAD,
+ SNES_MCPIR1,
+ SNES_MCPIR2,
+ SNES_20COL,
+ SNES_BANANA, // wip
+ SNES_BUGS, // wip
+ // legacy types to support DSPx games from fullpath
+ SNES_DSP1_LEG,
+ SNES_DSP1B_LEG,
+ SNES_DSP2_LEG,
+ SNES_DSP3_LEG,
+ SNES_DSP4_LEG,
+ SNES_DSP1_MODE21_LEG,
+ SNES_ST010_LEG,
+ SNES_ST011_LEG
+};
+
+/* add-ons to handle legacy dumps in snes_add */
+enum
+{
+ ADDON_NONE = 0,
+ ADDON_CX4,
+ ADDON_DSP1,
+ ADDON_DSP1B,
+ ADDON_DSP2,
+ ADDON_DSP3,
+ ADDON_DSP4,
+ ADDON_OBC1,
+ ADDON_SA1,
+ ADDON_SDD1,
+ ADDON_SFX,
+ ADDON_SPC7110,
+ ADDON_SPC7110_RTC,
+ ADDON_ST010,
+ ADDON_ST011,
+ ADDON_ST018,
+ ADDON_SRTC,
+ ADDON_Z80GB
+};
+
+// ======================> sns_cart_interface
+
+struct sns_cart_interface
+{
+};
+
+
+// ======================> device_sns_cart_interface
+
+class device_sns_cart_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_sns_cart_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_sns_cart_interface();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l) { return 0xff; } // ROM access in range [00-7f]
+ virtual DECLARE_READ8_MEMBER(read_h) { return 0xff; } // ROM access in range [80-ff]
+ virtual DECLARE_READ8_MEMBER(read_ram) { if (m_nvram) { UINT32 mask = m_nvram_size - 1; return m_nvram[offset & mask]; } else return 0xff; } // NVRAM access
+ virtual DECLARE_WRITE8_MEMBER(write_l) {} // used by carts with subslots
+ virtual DECLARE_WRITE8_MEMBER(write_h) {} // used by carts with subslots
+ virtual DECLARE_WRITE8_MEMBER(write_ram) { if (m_nvram) { UINT32 mask = m_nvram_size - 1; m_nvram[offset & mask] = data; return; } } // NVRAM access
+ virtual DECLARE_READ8_MEMBER(chip_read) { return 0xff; }
+ virtual DECLARE_WRITE8_MEMBER(chip_write) {}
+ virtual void speedup_addon_bios_access() {};
+
+ void rom_alloc(running_machine &machine, UINT32 size);
+ void nvram_alloc(running_machine &machine, UINT32 size);
+ void rtc_ram_alloc(running_machine &machine, UINT32 size);
+ void addon_bios_alloc(running_machine &machine, UINT32 size);
+ UINT8* get_rom_base() { return m_rom; };
+ UINT8* get_nvram_base() { return m_nvram; };
+ UINT8* get_addon_bios_base() { return m_bios; };
+ UINT8* get_rtc_ram_base() { return m_rtc_ram; };
+ UINT32 get_rom_size() { return m_rom_size; };
+ UINT32 get_nvram_size() { return m_nvram_size; };
+ UINT32 get_addon_bios_size() { return m_bios_size; };
+ UINT32 get_rtc_ram_size() { return m_rtc_ram_size; };
+
+ void rom_map_setup(UINT32 size);
+
+ // internal state
+ UINT8 *m_rom;
+ UINT8 *m_nvram;
+ UINT8 *m_bios;
+ UINT8 *m_rtc_ram; // temp pointer to save RTC ram to nvram (will disappear when RTCs become devices)
+ UINT32 m_rom_size;
+ UINT32 m_nvram_size;
+ UINT32 m_bios_size;
+ UINT32 m_rtc_ram_size; // temp
+
+ UINT8 rom_bank_map[256]; // 32K chunks of rom
+};
+
+
+// ======================> base_sns_cart_slot_device
+
+class base_sns_cart_slot_device : public device_t,
+ public sns_cart_interface,
+ public device_image_interface,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ base_sns_cart_slot_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 ~base_sns_cart_slot_device();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual void call_unload();
+ virtual bool call_softlist_load(char *swlist, char *swname, rom_entry *start_entry);
+
+ void get_cart_type_addon(UINT8 *ROM, UINT32 len, int &type, int &addon);
+ UINT32 snes_skip_header(UINT8 *ROM, UINT32 snes_rom_size);
+ int get_type() { return m_type; }
+
+ void setup_nvram();
+ void internal_header_logging(UINT8 *ROM, UINT32 len);
+
+ virtual iodevice_t image_type() const { return IO_CARTSLOT; }
+ virtual bool is_readable() const { return 1; }
+ virtual bool is_writeable() const { return 0; }
+ virtual bool is_creatable() const { return 0; }
+ virtual bool must_be_loaded() const { return 1; }
+ virtual bool is_reset_on_load() const { return 1; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+
+ // slot interface overrides
+ virtual const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_READ8_MEMBER(read_ram);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual DECLARE_WRITE8_MEMBER(write_ram);
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ // in order to support legacy dumps + add-on CPU dump appended at the end of the file, we
+ // check if the required data is present and update bank map accordingly
+ void setup_addon_from_fullpath();
+
+
+// m_cart cannot be made private yet, because we need to check nvram_size from the driver...
+// more work needed
+//private:
+
+ // this is used to support legacy DSPx/ST0xx/CX4 dumps not including the CPU data...
+ // i.e. it's only used for snes_add/snesp_add
+ int m_addon;
+
+ int m_type;
+ device_sns_cart_interface* m_cart;
+};
+
+// ======================> sns_cart_slot_device
+
+class sns_cart_slot_device : public base_sns_cart_slot_device
+{
+public:
+ // construction/destruction
+ sns_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual const char *image_interface() const { return "snes_cart"; }
+ virtual const char *file_extensions() const { return "sfc"; }
+};
+
+// ======================> sns_sufami_cart_slot_device
+
+class sns_sufami_cart_slot_device : public base_sns_cart_slot_device
+{
+public:
+ // construction/destruction
+ sns_sufami_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual const char *image_interface() const { return "st_cart"; }
+ virtual const char *file_extensions() const { return "st"; }
+ virtual bool must_be_loaded() const { return 0; }
+};
+
+// ======================> sns_sufami_cart_slot_device
+
+class sns_bsx_cart_slot_device : public base_sns_cart_slot_device
+{
+public:
+ // construction/destruction
+ sns_bsx_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual const char *image_interface() const { return "bspack"; }
+ virtual const char *file_extensions() const { return "bs"; }
+ virtual bool must_be_loaded() const { return 0; }
+};
+
+
+// device type definition
+extern const device_type SNS_CART_SLOT;
+extern const device_type SNS_SUFAMI_CART_SLOT;
+extern const device_type SNS_BSX_CART_SLOT;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+ ***************************************************************************/
+
+#define MCFG_SNS_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \
+ MCFG_DEVICE_ADD(_tag, SNS_CART_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false)
+
+#define MCFG_SNS_SUFAMI_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \
+ MCFG_DEVICE_ADD(_tag, SNS_SUFAMI_CART_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false)
+
+#define MCFG_SNS_BSX_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \
+ MCFG_DEVICE_ADD(_tag, SNS_BSX_CART_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false)
+
+
+#endif
diff --git a/src/emu/bus/snes/spc7110.c b/src/emu/bus/snes/spc7110.c
new file mode 100644
index 00000000000..ed7dccc247a
--- /dev/null
+++ b/src/emu/bus/snes/spc7110.c
@@ -0,0 +1,1681 @@
+/***********************************************************************************************************
+
+ SPC-7110 add-on chip emulation (for SNES/SFC)
+
+ Based on C++ implementation by Byuu in BSNES.
+
+ Byuu's code is released under GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ The implementation below is released under the MAME license
+ for use in MAME, MESS and derivatives by permission of Byuu
+
+ Copyright (for the implementation below) MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "spc7110.h"
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type SNS_HIROM_SPC7110 = &device_creator<sns_rom_spc7110_device>;
+const device_type SNS_HIROM_SPC7110_RTC = &device_creator<sns_rom_spc7110rtc_device>;
+
+
+sns_rom_spc7110_device::sns_rom_spc7110_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)
+ : sns_rom21_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+sns_rom_spc7110_device::sns_rom_spc7110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom21_device(mconfig, SNS_HIROM_SPC7110, "SNES Cart + SPC-7110", tag, owner, clock, "sns_rom_spc7110", __FILE__)
+{
+}
+
+sns_rom_spc7110rtc_device::sns_rom_spc7110rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_spc7110_device(mconfig, SNS_HIROM_SPC7110_RTC, "SNES Cart + SPC-7110 + RTC", tag, owner, clock, "sns_rom_spc7110rtc", __FILE__)
+{
+}
+
+
+void sns_rom_spc7110_device::spc7110_start()
+{
+ m_decomp = auto_alloc(machine(), SPC7110_Decomp(machine()));
+
+ // The SPC7110 works in conjunction with 0x2000 of RAM, which is battery backed up (and hence emulated by our m_nvram)
+
+ m_r4801 = 0x00;
+ m_r4802 = 0x00;
+ m_r4803 = 0x00;
+ m_r4804 = 0x00;
+ m_r4805 = 0x00;
+ m_r4806 = 0x00;
+ m_r4807 = 0x00;
+ m_r4808 = 0x00;
+ m_r4809 = 0x00;
+ m_r480a = 0x00;
+ m_r480b = 0x00;
+ m_r480c = 0x00;
+
+ m_r4811 = 0x00;
+ m_r4812 = 0x00;
+ m_r4813 = 0x00;
+ m_r4814 = 0x00;
+ m_r4815 = 0x00;
+ m_r4816 = 0x00;
+ m_r4817 = 0x00;
+ m_r4818 = 0x00;
+
+ m_r481x = 0x00;
+ m_r4814_latch = 0;
+ m_r4815_latch = 0;
+
+ m_r4820 = 0x00;
+ m_r4821 = 0x00;
+ m_r4822 = 0x00;
+ m_r4823 = 0x00;
+ m_r4824 = 0x00;
+ m_r4825 = 0x00;
+ m_r4826 = 0x00;
+ m_r4827 = 0x00;
+ m_r4828 = 0x00;
+ m_r4829 = 0x00;
+ m_r482a = 0x00;
+ m_r482b = 0x00;
+ m_r482c = 0x00;
+ m_r482d = 0x00;
+ m_r482e = 0x00;
+ m_r482f = 0x00;
+
+ m_r4830 = 0x00;
+ m_r4831 = 0;
+ m_dx_offset = spc7110_datarom_addr(0 * 0x100000, 0x200000); // we would need the rom length here...
+ m_r4832 = 1;
+ m_ex_offset = spc7110_datarom_addr(1 * 0x100000, 0x200000); // we would need the rom length here...
+ m_r4833 = 2;
+ m_fx_offset = spc7110_datarom_addr(2 * 0x100000, 0x200000); // we would need the rom length here...
+ m_r4834 = 0x00;
+
+ m_r4840 = 0x00;
+ m_r4841 = 0x00;
+ m_r4842 = 0x00;
+
+ save_item(NAME(m_r4801));
+ save_item(NAME(m_r4802));
+ save_item(NAME(m_r4803));
+ save_item(NAME(m_r4804));
+ save_item(NAME(m_r4805));
+ save_item(NAME(m_r4806));
+ save_item(NAME(m_r4807));
+ save_item(NAME(m_r4808));
+ save_item(NAME(m_r4809));
+ save_item(NAME(m_r480a));
+ save_item(NAME(m_r480b));
+ save_item(NAME(m_r480c));
+ save_item(NAME(m_r4811));
+ save_item(NAME(m_r4812));
+ save_item(NAME(m_r4813));
+ save_item(NAME(m_r4814));
+ save_item(NAME(m_r4815));
+ save_item(NAME(m_r4816));
+ save_item(NAME(m_r4817));
+ save_item(NAME(m_r4818));
+ save_item(NAME(m_r481x));
+ save_item(NAME(m_r4814_latch));
+ save_item(NAME(m_r4815_latch));
+ save_item(NAME(m_r4820));
+ save_item(NAME(m_r4821));
+ save_item(NAME(m_r4822));
+ save_item(NAME(m_r4823));
+ save_item(NAME(m_r4824));
+ save_item(NAME(m_r4825));
+ save_item(NAME(m_r4826));
+ save_item(NAME(m_r4827));
+ save_item(NAME(m_r4828));
+ save_item(NAME(m_r4829));
+ save_item(NAME(m_r482a));
+ save_item(NAME(m_r482b));
+ save_item(NAME(m_r482c));
+ save_item(NAME(m_r482d));
+ save_item(NAME(m_r482e));
+ save_item(NAME(m_r482f));
+ save_item(NAME(m_r4830));
+ save_item(NAME(m_r4831));
+ save_item(NAME(m_r4832));
+ save_item(NAME(m_r4833));
+ save_item(NAME(m_r4834));
+ save_item(NAME(m_r4840));
+ save_item(NAME(m_r4841));
+ save_item(NAME(m_r4842));
+ save_item(NAME(m_dx_offset));
+ save_item(NAME(m_ex_offset));
+ save_item(NAME(m_fx_offset));
+}
+
+void sns_rom_spc7110_device::device_start()
+{
+ spc7110_start();
+}
+
+void sns_rom_spc7110rtc_device::device_start()
+{
+ spc7110_start();
+
+ // RTC
+ m_rtc_state = RTCS_Inactive;
+ m_rtc_mode = RTCM_Linear;
+ m_rtc_index = 0;
+ m_rtc_offset = 0;
+
+// at this stage, rtc_ram is not yet allocated. this will be fixed when converting RTC to be a separate device.
+// spc7110_update_time(0);
+
+ // set basetime for RTC
+ machine().current_datetime(m_rtc_basetime);
+
+ save_item(NAME(m_rtc_state));
+ save_item(NAME(m_rtc_mode));
+ save_item(NAME(m_rtc_index));
+ save_item(NAME(m_rtc_offset));
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+#define SPC7110_DECOMP_BUFFER_SIZE 64
+
+static const UINT8 spc7110_evolution_table[53][4] =
+{
+ { 0x5a, 1, 1, 1 },
+ { 0x25, 6, 2, 0 },
+ { 0x11, 8, 3, 0 },
+ { 0x08, 10, 4, 0 },
+ { 0x03, 12, 5, 0 },
+ { 0x01, 15, 5, 0 },
+
+ { 0x5a, 7, 7, 1 },
+ { 0x3f, 19, 8, 0 },
+ { 0x2c, 21, 9, 0 },
+ { 0x20, 22, 10, 0 },
+ { 0x17, 23, 11, 0 },
+ { 0x11, 25, 12, 0 },
+ { 0x0c, 26, 13, 0 },
+ { 0x09, 28, 14, 0 },
+ { 0x07, 29, 15, 0 },
+ { 0x05, 31, 16, 0 },
+ { 0x04, 32, 17, 0 },
+ { 0x03, 34, 18, 0 },
+ { 0x02, 35, 5, 0 },
+
+ { 0x5a, 20, 20, 1 },
+ { 0x48, 39, 21, 0 },
+ { 0x3a, 40, 22, 0 },
+ { 0x2e, 42, 23, 0 },
+ { 0x26, 44, 24, 0 },
+ { 0x1f, 45, 25, 0 },
+ { 0x19, 46, 26, 0 },
+ { 0x15, 25, 27, 0 },
+ { 0x11, 26, 28, 0 },
+ { 0x0e, 26, 29, 0 },
+ { 0x0b, 27, 30, 0 },
+ { 0x09, 28, 31, 0 },
+ { 0x08, 29, 32, 0 },
+ { 0x07, 30, 33, 0 },
+ { 0x05, 31, 34, 0 },
+ { 0x04, 33, 35, 0 },
+ { 0x04, 33, 36, 0 },
+ { 0x03, 34, 37, 0 },
+ { 0x02, 35, 38, 0 },
+ { 0x02, 36, 5, 0 },
+
+ { 0x58, 39, 40, 1 },
+ { 0x4d, 47, 41, 0 },
+ { 0x43, 48, 42, 0 },
+ { 0x3b, 49, 43, 0 },
+ { 0x34, 50, 44, 0 },
+ { 0x2e, 51, 45, 0 },
+ { 0x29, 44, 46, 0 },
+ { 0x25, 45, 24, 0 },
+
+ { 0x56, 47, 48, 1 },
+ { 0x4f, 47, 49, 0 },
+ { 0x47, 48, 50, 0 },
+ { 0x41, 49, 51, 0 },
+ { 0x3c, 50, 52, 0 },
+ { 0x37, 51, 43, 0 },
+};
+
+static const UINT8 spc7110_mode2_context_table[32][2] =
+{
+ { 1, 2 },
+
+ { 3, 8 },
+ { 13, 14 },
+
+ { 15, 16 },
+ { 17, 18 },
+ { 19, 20 },
+ { 21, 22 },
+ { 23, 24 },
+ { 25, 26 },
+ { 25, 26 },
+ { 25, 26 },
+ { 25, 26 },
+ { 25, 26 },
+ { 27, 28 },
+ { 29, 30 },
+
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+ { 31, 31 },
+
+ { 31, 31 },
+};
+
+SPC7110_Decomp::SPC7110_Decomp(running_machine &machine)
+ : m_machine(machine)
+{
+ m_decomp_buffer = (UINT8*)auto_alloc_array(machine, UINT8, SPC7110_DECOMP_BUFFER_SIZE);
+ reset();
+
+ for (int i = 0; i < 256; i++)
+ {
+#define map(x, y) (((i >> x) & 1) << y)
+ //2x8-bit
+ m_morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6)
+ + map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4);
+ m_morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2)
+ + map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0);
+ //4x8-bit
+ m_morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7)
+ + map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6);
+ m_morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5)
+ + map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4);
+ m_morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3)
+ + map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2);
+ m_morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1)
+ + map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0);
+#undef map
+ }
+
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_decomp_mode);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_decomp_offset);
+ state_save_register_item_pointer(machine, "SNES_SPC7110", NULL, 0, m_decomp_buffer, SPC7110_DECOMP_BUFFER_SIZE);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_decomp_buffer_rdoffset);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_decomp_buffer_wroffset);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_decomp_buffer_length);
+
+ for (int i = 0; i < 32; i++)
+ {
+ state_save_register_item(machine, "SNES_SPC7110", NULL, i, m_context[i].index);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, i, m_context[i].invert);
+ }
+
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m0_val);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m0_in);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m0_span);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m0_out);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m0_inverts);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m0_lps);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m0_in_count);
+
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_pixelorder);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_realorder);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_val);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_in);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_span);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_out);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_inverts);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_lps);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m1_in_count);
+
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_pixelorder);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_realorder);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_bitplanebuffer);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_buffer_index);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_val);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_in);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_span);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_out0);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_out1);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_inverts);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_lps);
+ state_save_register_item(machine, "SNES_SPC7110", NULL, 0, m_m2_in_count);
+}
+
+void SPC7110_Decomp::reset()
+{
+ //mode 3 is invalid; this is treated as a special case to always return 0x00
+ //set to mode 3 so that reading decomp port before starting first decomp will return 0x00
+ m_decomp_mode = 3;
+
+ m_decomp_buffer_rdoffset = 0;
+ m_decomp_buffer_wroffset = 0;
+ m_decomp_buffer_length = 0;
+}
+
+void SPC7110_Decomp::init(running_machine &machine, UINT8 *ROM, UINT32 len, UINT32 mode, UINT32 offset, UINT32 index)
+{
+ m_decomp_mode = mode;
+ m_decomp_offset = offset;
+
+ m_decomp_buffer_rdoffset = 0;
+ m_decomp_buffer_wroffset = 0;
+ m_decomp_buffer_length = 0;
+
+ //reset context states
+ for (int i = 0; i < 32; i++)
+ {
+ m_context[i].index = 0;
+ m_context[i].invert = 0;
+ }
+
+ switch (m_decomp_mode)
+ {
+ case 0: mode0(1, ROM, len); break;
+ case 1: mode1(1, ROM, len); break;
+ case 2: mode2(1, ROM, len); break;
+ }
+
+ //decompress up to requested output data index
+ while (index--)
+ {
+ read(ROM, len);
+ }
+}
+
+UINT8 SPC7110_Decomp::read(UINT8 *ROM, UINT32 len)
+{
+ UINT8 data;
+
+ if (m_decomp_buffer_length == 0)
+ {
+ //decompress at least (SPC7110_DECOMP_BUFFER_SIZE / 2) bytes to the buffer
+ switch (m_decomp_mode)
+ {
+ case 0:
+ mode0(0, ROM, len);
+ break;
+
+ case 1:
+ mode1(0, ROM, len);
+ break;
+
+ case 2:
+ mode2(0, ROM, len);
+ break;
+
+ default:
+ return 0x00;
+ }
+ }
+
+ data = m_decomp_buffer[m_decomp_buffer_rdoffset++];
+ m_decomp_buffer_rdoffset &= SPC7110_DECOMP_BUFFER_SIZE - 1;
+ m_decomp_buffer_length--;
+ return data;
+}
+
+void SPC7110_Decomp::write(UINT8 data)
+{
+ m_decomp_buffer[m_decomp_buffer_wroffset++] = data;
+ m_decomp_buffer_wroffset &= SPC7110_DECOMP_BUFFER_SIZE - 1;
+ m_decomp_buffer_length++;
+}
+
+UINT8 SPC7110_Decomp::dataread(UINT8 *ROM, UINT32 len)
+{
+ UINT32 size = len - 0x100000;
+ while (m_decomp_offset >= size)
+ {
+ m_decomp_offset -= size;
+ }
+ return ROM[0x100000 + m_decomp_offset++];
+}
+
+void SPC7110_Decomp::mode0(UINT8 init, UINT8 *ROM, UINT32 len)
+{
+ if (init == 1)
+ {
+ m_m0_out = m_m0_inverts = m_m0_lps = 0;
+ m_m0_span = 0xff;
+ m_m0_val = dataread(ROM, len);
+ m_m0_in = dataread(ROM, len);
+ m_m0_in_count = 8;
+ return;
+ }
+
+ while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
+ {
+ for (int bit = 0; bit < 8; bit++)
+ {
+ //get context
+ UINT8 mask = (1 << (bit & 3)) - 1;
+ UINT8 con = mask + ((m_m0_inverts & mask) ^ (m_m0_lps & mask));
+ UINT32 prob, mps, flag_lps;
+ UINT32 shift = 0;
+ if (bit > 3)
+ {
+ con += 15;
+ }
+
+ //get prob and mps
+ prob = probability(con);
+ mps = (((m_m0_out >> 15) & 1) ^ m_context[con].invert);
+
+ //get bit
+ if (m_m0_val <= m_m0_span - prob) //mps
+ {
+ m_m0_span = m_m0_span - prob;
+ m_m0_out = (m_m0_out << 1) + mps;
+ flag_lps = 0;
+ }
+ else //lps
+ {
+ m_m0_val = m_m0_val - (m_m0_span - (prob - 1));
+ m_m0_span = prob - 1;
+ m_m0_out = (m_m0_out << 1) + 1 - mps;
+ flag_lps = 1;
+ }
+
+ //renormalize
+ while (m_m0_span < 0x7f)
+ {
+ shift++;
+
+ m_m0_span = (m_m0_span << 1) + 1;
+ m_m0_val = (m_m0_val << 1) + (m_m0_in >> 7);
+
+ m_m0_in <<= 1;
+ if (--m_m0_in_count == 0)
+ {
+ m_m0_in = dataread(ROM, len);
+ m_m0_in_count = 8;
+ }
+ }
+
+ //update processing info
+ m_m0_lps = (m_m0_lps << 1) + flag_lps;
+ m_m0_inverts = (m_m0_inverts << 1) + m_context[con].invert;
+
+ //update context state
+ if (flag_lps & toggle_invert(con))
+ {
+ m_context[con].invert ^= 1;
+ }
+ if (flag_lps)
+ {
+ m_context[con].index = next_lps(con);
+ }
+ else if (shift)
+ {
+ m_context[con].index = next_mps(con);
+ }
+ }
+
+ //save byte
+ write(m_m0_out);
+ }
+}
+
+void SPC7110_Decomp::mode1(UINT8 init, UINT8 *ROM, UINT32 len)
+{
+ if (init == 1)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ m_m1_pixelorder[i] = i;
+ }
+ m_m1_out = m_m1_inverts = m_m1_lps = 0;
+ m_m1_span = 0xff;
+ m_m1_val = dataread(ROM, len);
+ m_m1_in = dataread(ROM, len);
+ m_m1_in_count = 8;
+ return;
+ }
+
+ while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
+ {
+ UINT16 data;
+ for (int pixel = 0; pixel < 8; pixel++)
+ {
+ //get first symbol context
+ UINT32 a = ((m_m1_out >> (1 * 2)) & 3);
+ UINT32 b = ((m_m1_out >> (7 * 2)) & 3);
+ UINT32 c = ((m_m1_out >> (8 * 2)) & 3);
+ UINT32 con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
+
+ //update pixel order
+ UINT32 m, n;
+ for (m = 0; m < 4; m++)
+ {
+ if (m_m1_pixelorder[m] == a)
+ {
+ break;
+ }
+ }
+ for (n = m; n > 0; n--)
+ {
+ m_m1_pixelorder[n] = m_m1_pixelorder[n - 1];
+ }
+ m_m1_pixelorder[0] = a;
+
+ //calculate the real pixel order
+ for (m = 0; m < 4; m++)
+ {
+ m_m1_realorder[m] = m_m1_pixelorder[m];
+ }
+
+ //rotate reference pixel c value to top
+ for (m = 0; m < 4; m++)
+ {
+ if (m_m1_realorder[m] == c)
+ {
+ break;
+ }
+ }
+ for (n = m; n > 0; n--)
+ {
+ m_m1_realorder[n] = m_m1_realorder[n - 1];
+ }
+ m_m1_realorder[0] = c;
+
+ //rotate reference pixel b value to top
+ for (m = 0; m < 4; m++)
+ {
+ if (m_m1_realorder[m] == b)
+ {
+ break;
+ }
+ }
+ for (n = m; n > 0; n--)
+ {
+ m_m1_realorder[n] = m_m1_realorder[n - 1];
+ }
+ m_m1_realorder[0] = b;
+
+ //rotate reference pixel a value to top
+ for (m = 0; m < 4; m++)
+ {
+ if (m_m1_realorder[m] == a)
+ {
+ break;
+ }
+ }
+ for (n = m; n > 0; n--)
+ {
+ m_m1_realorder[n] = m_m1_realorder[n - 1];
+ }
+ m_m1_realorder[0] = a;
+
+ //get 2 symbols
+ for (int bit = 0; bit < 2; bit++)
+ {
+ //get prob
+ UINT32 prob = probability(con);
+ UINT32 shift = 0;
+
+ //get symbol
+ UINT32 flag_lps;
+ if (m_m1_val <= m_m1_span - prob) //mps
+ {
+ m_m1_span = m_m1_span - prob;
+ flag_lps = 0;
+ }
+ else //lps
+ {
+ m_m1_val = m_m1_val - (m_m1_span - (prob - 1));
+ m_m1_span = prob - 1;
+ flag_lps = 1;
+ }
+
+ //renormalize
+ while (m_m1_span < 0x7f)
+ {
+ shift++;
+
+ m_m1_span = (m_m1_span << 1) + 1;
+ m_m1_val = (m_m1_val << 1) + (m_m1_in >> 7);
+
+ m_m1_in <<= 1;
+ if (--m_m1_in_count == 0)
+ {
+ m_m1_in = dataread(ROM, len);
+ m_m1_in_count = 8;
+ }
+ }
+
+ //update processing info
+ m_m1_lps = (m_m1_lps << 1) + flag_lps;
+ m_m1_inverts = (m_m1_inverts << 1) + m_context[con].invert;
+
+ //update context state
+ if (flag_lps & toggle_invert(con))
+ {
+ m_context[con].invert ^= 1;
+ }
+ if (flag_lps)
+ {
+ m_context[con].index = next_lps(con);
+ }
+ else if (shift)
+ {
+ m_context[con].index = next_mps(con);
+ }
+
+ //get next context
+ con = 5 + (con << 1) + ((m_m1_lps ^ m_m1_inverts) & 1);
+ }
+
+ //get pixel
+ b = m_m1_realorder[(m_m1_lps ^ m_m1_inverts) & 3];
+ m_m1_out = (m_m1_out << 2) + b;
+ }
+
+ //turn pixel data into bitplanes
+ data = morton_2x8(m_m1_out);
+ write(data >> 8);
+ write(data >> 0);
+ }
+}
+
+void SPC7110_Decomp::mode2(UINT8 init, UINT8 *ROM, UINT32 len)
+{
+ if (init == 1)
+ {
+ for (int i = 0; i < 16; i++)
+ {
+ m_m2_pixelorder[i] = i;
+ }
+ m_m2_buffer_index = 0;
+ m_m2_out0 = m_m2_out1 = m_m2_inverts = m_m2_lps = 0;
+ m_m2_span = 0xff;
+ m_m2_val = dataread(ROM, len);
+ m_m2_in = dataread(ROM, len);
+ m_m2_in_count = 8;
+ return;
+ }
+
+ while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
+ {
+ UINT32 data;
+ for (int pixel = 0; pixel < 8; pixel++)
+ {
+ //get first symbol context
+ UINT32 a = ((m_m2_out0 >> (0 * 4)) & 15);
+ UINT32 b = ((m_m2_out0 >> (7 * 4)) & 15);
+ UINT32 c = ((m_m2_out1 >> (0 * 4)) & 15);
+ UINT32 con = 0;
+ UINT32 refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
+
+ //update pixel order
+ UINT32 m, n;
+ for (m = 0; m < 16; m++)
+ {
+ if (m_m2_pixelorder[m] == a)
+ {
+ break;
+ }
+ }
+ for (n = m; n > 0; n--)
+ {
+ m_m2_pixelorder[n] = m_m2_pixelorder[n - 1];
+ }
+ m_m2_pixelorder[0] = a;
+
+ //calculate the real pixel order
+ for (m = 0; m < 16; m++)
+ {
+ m_m2_realorder[m] = m_m2_pixelorder[m];
+ }
+
+ //rotate reference pixel c value to top
+ for (m = 0; m < 16; m++)
+ {
+ if (m_m2_realorder[m] == c)
+ {
+ break;
+ }
+ }
+ for (n = m; n > 0; n--)
+ {
+ m_m2_realorder[n] = m_m2_realorder[n - 1];
+ }
+ m_m2_realorder[0] = c;
+
+ //rotate reference pixel b value to top
+ for (m = 0; m < 16; m++)
+ {
+ if (m_m2_realorder[m] == b)
+ {
+ break;
+ }
+ }
+ for (n = m; n > 0; n--)
+ {
+ m_m2_realorder[n] = m_m2_realorder[n - 1];
+ }
+ m_m2_realorder[0] = b;
+
+ //rotate reference pixel a value to top
+ for (m = 0; m < 16; m++)
+ {
+ if (m_m2_realorder[m] == a)
+ {
+ break;
+ }
+ }
+ for (n = m; n > 0; n--)
+ {
+ m_m2_realorder[n] = m_m2_realorder[n - 1];
+ }
+ m_m2_realorder[0] = a;
+
+ //get 4 symbols
+ for (int bit = 0; bit < 4; bit++)
+ {
+ UINT32 invertbit, shift;
+
+ //get prob
+ UINT32 prob = probability(con);
+
+ //get symbol
+ UINT32 flag_lps;
+ if (m_m2_val <= m_m2_span - prob) //mps
+ {
+ m_m2_span = m_m2_span - prob;
+ flag_lps = 0;
+ }
+ else //lps
+ {
+ m_m2_val = m_m2_val - (m_m2_span - (prob - 1));
+ m_m2_span = prob - 1;
+ flag_lps = 1;
+ }
+
+ //renormalize
+ shift = 0;
+ while (m_m2_span < 0x7f)
+ {
+ shift++;
+
+ m_m2_span = (m_m2_span << 1) + 1;
+ m_m2_val = (m_m2_val << 1) + (m_m2_in >> 7);
+
+ m_m2_in <<= 1;
+ if (--m_m2_in_count == 0)
+ {
+ m_m2_in = dataread(ROM, len);
+ m_m2_in_count = 8;
+ }
+ }
+
+ //update processing info
+ m_m2_lps = (m_m2_lps << 1) + flag_lps;
+ invertbit = m_context[con].invert;
+ m_m2_inverts = (m_m2_inverts << 1) + invertbit;
+
+ //update context state
+ if (flag_lps & toggle_invert(con))
+ {
+ m_context[con].invert ^= 1;
+ }
+ if (flag_lps)
+ {
+ m_context[con].index = next_lps(con);
+ }
+ else if (shift)
+ {
+ m_context[con].index = next_mps(con);
+ }
+
+ //get next context
+ con = spc7110_mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0);
+ }
+
+ //get pixel
+ b = m_m2_realorder[(m_m2_lps ^ m_m2_inverts) & 0x0f];
+ m_m2_out1 = (m_m2_out1 << 4) + ((m_m2_out0 >> 28) & 0x0f);
+ m_m2_out0 = (m_m2_out0 << 4) + b;
+ }
+
+ //convert pixel data into bitplanes
+ data = morton_4x8(m_m2_out0);
+ write(data >> 24);
+ write(data >> 16);
+ m_m2_bitplanebuffer[m_m2_buffer_index++] = data >> 8;
+ m_m2_bitplanebuffer[m_m2_buffer_index++] = data >> 0;
+
+ if (m_m2_buffer_index == 16)
+ {
+ for (int i = 0; i < 16; i++)
+ {
+ write(m_m2_bitplanebuffer[i]);
+ }
+ m_m2_buffer_index = 0;
+ }
+ }
+}
+
+UINT8 SPC7110_Decomp::probability(UINT32 n)
+{
+ return spc7110_evolution_table[m_context[n].index][0];
+}
+
+UINT8 SPC7110_Decomp::next_lps(UINT32 n)
+{
+ return spc7110_evolution_table[m_context[n].index][1];
+}
+
+UINT8 SPC7110_Decomp::next_mps(UINT32 n)
+{
+ return spc7110_evolution_table[m_context[n].index][2];
+}
+
+UINT8 SPC7110_Decomp::toggle_invert(UINT32 n)
+{
+ return spc7110_evolution_table[m_context[n].index][3];
+}
+
+UINT32 SPC7110_Decomp::morton_2x8(UINT32 data)
+{
+ //reverse morton lookup: de-interleave two 8-bit values
+ //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8
+ //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0
+ return m_morton16[0][(data >> 0) & 255] + m_morton16[1][(data >> 8) & 255];
+}
+
+UINT32 SPC7110_Decomp::morton_4x8(UINT32 data)
+{
+ //reverse morton lookup: de-interleave four 8-bit values
+ //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24
+ //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16
+ //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8
+ //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0
+ return m_morton32[0][(data >> 0) & 255] + m_morton32[1][(data >> 8) & 255]
+ + m_morton32[2][(data >> 16) & 255] + m_morton32[3][(data >> 24) & 255];
+}
+
+
+static const UINT32 spc7110_months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+UINT32 sns_rom_spc7110_device::spc7110_datarom_addr(UINT32 addr, UINT32 rom_len)
+{
+ UINT32 size = rom_len - 0x100000;
+ while (addr >= size)
+ {
+ addr -= size;
+ }
+ return addr + 0x100000;
+}
+
+UINT32 sns_rom_spc7110_device::spc7110_data_pointer(void)
+{
+ return m_r4811 + (m_r4812 << 8) + (m_r4813 << 16);
+}
+
+UINT32 sns_rom_spc7110_device::spc7110_data_adjust(void)
+{
+ return m_r4814 + (m_r4815 << 8);
+}
+
+UINT32 sns_rom_spc7110_device::spc7110_data_increment(void)
+{
+ return m_r4816 + (m_r4817 << 8);
+}
+
+void sns_rom_spc7110_device::spc7110_set_data_pointer(UINT32 addr)
+{
+ m_r4811 = addr;
+ m_r4812 = addr >> 8;
+ m_r4813 = addr >> 16;
+}
+
+void sns_rom_spc7110_device::spc7110_set_data_adjust(UINT32 addr)
+{
+ m_r4814 = addr;
+ m_r4815 = addr >> 8;
+}
+
+// FIXME: SPC7110 RTC is capable of rounding/adding/zero-ing seconds, so
+// we should probably keep track internally of the time rather than updating
+// to the system time at each call with a "offset" tracking as we do now...
+// (and indeed current code fails to pass Tengai Makyou Zero tests)
+void sns_rom_spc7110_device::spc7110_update_time(UINT8 offset)
+{
+ system_time curtime;
+ machine().current_datetime(curtime);
+ INT64 diff = curtime.time - m_rtc_basetime.time - offset;
+// printf("diff %llx\n", diff);
+ bool update = TRUE;
+
+ // TEST: can we go beyond 24hrs of rounding?!? I doubt it will ever go beyond 3600, but I could be wrong...
+ assert(diff < 86400);
+
+ /* do not update if CR0 or CR2 timer disable flags are set */
+ if ((m_rtc_ram[13] & 0x01) || (m_rtc_ram[15] & 0x03))
+ update = FALSE;
+
+ if (update && diff > 0)
+ {
+ /* update time with offset, assuming offset < 3600s */
+ UINT32 second = m_rtc_ram[0] + m_rtc_ram[1] * 10;
+ UINT8 minute = m_rtc_ram[2] + m_rtc_ram[3] * 10;
+ UINT8 hour = m_rtc_ram[4] + m_rtc_ram[5] * 10;
+ UINT8 day = m_rtc_ram[6] + m_rtc_ram[7] * 10;
+ UINT8 month = m_rtc_ram[8] + m_rtc_ram[9] * 10;
+ UINT8 year = m_rtc_ram[10] + m_rtc_ram[11] * 10;
+ UINT8 weekday = m_rtc_ram[12];
+ day--;
+ month--;
+ year += (year >= 90) ? 1900 : 2000;
+
+ second += (UINT32)diff;
+ while (second >= 60)
+ {
+ second -= 60;
+ minute++;
+
+ // are we below 60 minutes?
+ if (minute < 60)
+ continue;
+ // otherwise we have to increase hour!
+ minute = 0;
+ hour++;
+
+ // are we below 24 hours?
+ if (hour < 24)
+ continue;
+ // otherwise we have to increase day!
+ hour = 0;
+ day++;
+
+ weekday = (weekday + 1) % 7;
+
+ UINT8 days = spc7110_months[month % 12];
+ // check for feb 29th
+ if (days == 28)
+ {
+ bool leap = FALSE;
+ if ((year % 4) == 0)
+ {
+ if(year % 100 || !(year % 400))
+ leap = TRUE;
+ }
+ if (leap)
+ days++;
+ }
+
+ // are we below end of month?
+ if (day < days)
+ continue;
+ // otherwise we have to increase month!
+ day = 0;
+ month++;
+
+ // are we below end of year?
+ if (month < 12)
+ continue;
+ // otherwise we have to increase year!
+ month = 0;
+ year++;
+ }
+
+ day++;
+ month++;
+ year %= 100;
+
+ m_rtc_ram[0] = second % 10;
+ m_rtc_ram[1] = second / 10;
+ m_rtc_ram[2] = minute % 10;
+ m_rtc_ram[3] = minute / 10;
+ m_rtc_ram[4] = hour % 10;
+ m_rtc_ram[5] = hour / 10;
+ m_rtc_ram[6] = day % 10;
+ m_rtc_ram[7] = day / 10;
+ m_rtc_ram[8] = month % 10;
+ m_rtc_ram[9] = month / 10;
+ m_rtc_ram[10] = year % 10;
+ m_rtc_ram[11] = (year / 10) % 10;
+ m_rtc_ram[12] = weekday % 7;
+ m_rtc_basetime = curtime;
+ }
+}
+
+READ8_MEMBER(sns_rom_spc7110_device::chip_read)
+{
+ UINT8 *ROM = get_rom_base();
+ UINT32 len = get_rom_size();
+ UINT16 addr = offset & 0xffff;
+
+ switch (addr)
+ {
+ //==================
+ //decompression unit
+ //==================
+
+ case 0x4800:
+ {
+ UINT16 counter = (m_r4809 + (m_r480a << 8));
+ counter--;
+ m_r4809 = counter;
+ m_r480a = counter >> 8;
+ return m_decomp->read(ROM, len);
+ }
+ case 0x4801: return m_r4801;
+ case 0x4802: return m_r4802;
+ case 0x4803: return m_r4803;
+ case 0x4804: return m_r4804;
+ case 0x4805: return m_r4805;
+ case 0x4806: return m_r4806;
+ case 0x4807: return m_r4807;
+ case 0x4808: return m_r4808;
+ case 0x4809: return m_r4809;
+ case 0x480a: return m_r480a;
+ case 0x480b: return m_r480b;
+ case 0x480c:
+ {
+ UINT8 status = m_r480c;
+ m_r480c &= 0x7f;
+ return status;
+ }
+
+ //==============
+ //data port unit
+ //==============
+
+ case 0x4810:
+ {
+ UINT8 data;
+ UINT32 address, adjust, adjustaddr;
+
+ if (m_r481x != 0x07) return 0x00;
+
+ address = spc7110_data_pointer();
+ adjust = spc7110_data_adjust();
+ if (m_r4818 & 8)
+ {
+ adjust = (INT16)adjust; //16-bit sign extend
+ }
+
+ adjustaddr = address;
+ if (m_r4818 & 2)
+ {
+ adjustaddr += adjust;
+ spc7110_set_data_adjust(adjust + 1);
+ }
+
+ data = ROM[spc7110_datarom_addr(adjustaddr, len)];
+ if (!(m_r4818 & 2))
+ {
+ UINT32 increment = (m_r4818 & 1) ? spc7110_data_increment() : 1;
+ if (m_r4818 & 4)
+ {
+ increment = (INT16)increment; //16-bit sign extend
+ }
+
+ if ((m_r4818 & 16) == 0)
+ {
+ spc7110_set_data_pointer(address + increment);
+ }
+ else
+ {
+ spc7110_set_data_adjust(adjust + increment);
+ }
+ }
+
+ return data;
+ }
+ case 0x4811: return m_r4811;
+ case 0x4812: return m_r4812;
+ case 0x4813: return m_r4813;
+ case 0x4814: return m_r4814;
+ case 0x4815: return m_r4815;
+ case 0x4816: return m_r4816;
+ case 0x4817: return m_r4817;
+ case 0x4818: return m_r4818;
+ case 0x481a:
+ {
+ UINT8 data;
+ UINT32 address, adjust;
+ if (m_r481x != 0x07)
+ {
+ return 0x00;
+ }
+
+ address = spc7110_data_pointer();
+ adjust = spc7110_data_adjust();
+ if (m_r4818 & 8)
+ {
+ adjust = (INT16)adjust; //16-bit sign extend
+ }
+
+ data = ROM[spc7110_datarom_addr(address + adjust, len)];
+ if ((m_r4818 & 0x60) == 0x60)
+ {
+ if ((m_r4818 & 16) == 0)
+ {
+ spc7110_set_data_pointer(address + adjust);
+ }
+ else
+ {
+ spc7110_set_data_adjust(adjust + adjust);
+ }
+ }
+
+ return data;
+ }
+
+ //=========
+ //math unit
+ //=========
+
+ case 0x4820: return m_r4820;
+ case 0x4821: return m_r4821;
+ case 0x4822: return m_r4822;
+ case 0x4823: return m_r4823;
+ case 0x4824: return m_r4824;
+ case 0x4825: return m_r4825;
+ case 0x4826: return m_r4826;
+ case 0x4827: return m_r4827;
+ case 0x4828: return m_r4828;
+ case 0x4829: return m_r4829;
+ case 0x482a: return m_r482a;
+ case 0x482b: return m_r482b;
+ case 0x482c: return m_r482c;
+ case 0x482d: return m_r482d;
+ case 0x482e: return m_r482e;
+ case 0x482f:
+ {
+ UINT8 status = m_r482f;
+ m_r482f &= 0x7f;
+ return status;
+ }
+
+ //===================
+ //memory mapping unit
+ //===================
+
+ case 0x4830: return m_r4830;
+ case 0x4831: return m_r4831;
+ case 0x4832: return m_r4832;
+ case 0x4833: return m_r4833;
+ case 0x4834: return m_r4834;
+
+ //====================
+ //real-time clock unit
+ //====================
+ case 0x4840: return m_r4840;
+ case 0x4841:
+ {
+ UINT8 data = 0;
+ if (m_rtc_state == RTCS_Inactive || m_rtc_state == RTCS_ModeSelect)
+ return 0x00;
+
+ m_r4842 = 0x80;
+ data = m_rtc_ram[m_rtc_index];
+ m_rtc_index = (m_rtc_index + 1) & 15;
+ return data;
+ }
+ case 0x4842:
+ {
+ UINT8 status = m_r4842;
+ m_r4842 &= 0x7f;
+ return status;
+ }
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(sns_rom_spc7110_device::chip_write)
+{
+ UINT8 *ROM = get_rom_base();
+ UINT32 len = get_rom_size();
+ UINT16 addr = offset & 0xffff;
+
+ switch (addr)
+ {
+ //==================
+ //decompression unit
+ //==================
+
+ case 0x4801: m_r4801 = data; break;
+ case 0x4802: m_r4802 = data; break;
+ case 0x4803: m_r4803 = data; break;
+ case 0x4804: m_r4804 = data; break;
+ case 0x4805: m_r4805 = data; break;
+ case 0x4806:
+ {
+ UINT32 table, index, address, mode, offset;
+ m_r4806 = data;
+
+ table = (m_r4801 + (m_r4802 << 8) + (m_r4803 << 16));
+ index = (m_r4804 << 2);
+ //length = (m_r4809 + (m_r480a << 8));
+ address = spc7110_datarom_addr(table + index, len);
+ mode = (ROM[address + 0]);
+ offset = (ROM[address + 1] << 16)
+ + (ROM[address + 2] << 8)
+ + (ROM[address + 3] << 0);
+
+ m_decomp->init(machine(), ROM, len, mode, offset, (m_r4805 + (m_r4806 << 8)) << mode);
+ m_r480c = 0x80;
+ }
+ break;
+
+ case 0x4807: m_r4807 = data; break;
+ case 0x4808: m_r4808 = data; break;
+ case 0x4809: m_r4809 = data; break;
+ case 0x480a: m_r480a = data; break;
+ case 0x480b: m_r480b = data; break;
+
+ //==============
+ //data port unit
+ //==============
+
+ case 0x4811: m_r4811 = data; m_r481x |= 0x01; break;
+ case 0x4812: m_r4812 = data; m_r481x |= 0x02; break;
+ case 0x4813: m_r4813 = data; m_r481x |= 0x04; break;
+ case 0x4814:
+ {
+ m_r4814 = data;
+ m_r4814_latch = 1;
+ if (!m_r4815_latch)
+ {
+ break;
+ }
+ if (!(m_r4818 & 2))
+ {
+ break;
+ }
+ if (m_r4818 & 0x10)
+ {
+ break;
+ }
+
+ if ((m_r4818 & 0x60) == 0x20)
+ {
+ UINT32 increment = spc7110_data_adjust() & 0xff;
+ if (m_r4818 & 8)
+ {
+ increment = (INT8)increment; //8-bit sign extend
+ }
+ spc7110_set_data_pointer(spc7110_data_pointer() + increment);
+ }
+ else if ((m_r4818 & 0x60) == 0x40)
+ {
+ UINT32 increment = spc7110_data_adjust();
+ if (m_r4818 & 8)
+ {
+ increment = (INT16)increment; //16-bit sign extend
+ }
+ spc7110_set_data_pointer(spc7110_data_pointer() + increment);
+ }
+ break;
+ }
+
+ case 0x4815:
+ {
+ m_r4815 = data;
+ m_r4815_latch = 1;
+ if (!m_r4814_latch)
+ {
+ break;
+ }
+ if (!(m_r4818 & 2))
+ {
+ break;
+ }
+ if (m_r4818 & 0x10)
+ {
+ break;
+ }
+
+ if ((m_r4818 & 0x60) == 0x20)
+ {
+ UINT32 increment = spc7110_data_adjust() & 0xff;
+ if (m_r4818 & 8)
+ {
+ increment = (INT8)increment; //8-bit sign extend
+ }
+ spc7110_set_data_pointer(spc7110_data_pointer() + increment);
+ }
+ else if ((m_r4818 & 0x60) == 0x40)
+ {
+ UINT32 increment = spc7110_data_adjust();
+ if (m_r4818 & 8)
+ {
+ increment = (INT16)increment; //16-bit sign extend
+ }
+ spc7110_set_data_pointer(spc7110_data_pointer() + increment);
+ }
+ break;
+ }
+
+ case 0x4816: m_r4816 = data; break;
+ case 0x4817: m_r4817 = data; break;
+ case 0x4818:
+ {
+ if (m_r481x != 0x07)
+ break;
+
+ m_r4818 = data;
+ m_r4814_latch = m_r4815_latch = 0;
+ break;
+ }
+
+ //=========
+ //math unit
+ //=========
+
+ case 0x4820: m_r4820 = data; break;
+ case 0x4821: m_r4821 = data; break;
+ case 0x4822: m_r4822 = data; break;
+ case 0x4823: m_r4823 = data; break;
+ case 0x4824: m_r4824 = data; break;
+ case 0x4825:
+ {
+ m_r4825 = data;
+
+ if (m_r482e & 1)
+ {
+ //signed 16-bit x 16-bit multiplication
+ INT16 r0 = (INT16)(m_r4824 + (m_r4825 << 8));
+ INT16 r1 = (INT16)(m_r4820 + (m_r4821 << 8));
+
+ INT32 result = r0 * r1;
+ m_r4828 = result;
+ m_r4829 = result >> 8;
+ m_r482a = result >> 16;
+ m_r482b = result >> 24;
+ }
+ else
+ {
+ //unsigned 16-bit x 16-bit multiplication
+ UINT16 r0 = (UINT16)(m_r4824 + (m_r4825 << 8));
+ UINT16 r1 = (UINT16)(m_r4820 + (m_r4821 << 8));
+
+ UINT32 result = r0 * r1;
+ m_r4828 = result;
+ m_r4829 = result >> 8;
+ m_r482a = result >> 16;
+ m_r482b = result >> 24;
+ }
+
+ m_r482f = 0x80;
+ break;
+ }
+
+ case 0x4826: m_r4826 = data; break;
+ case 0x4827:
+ {
+ m_r4827 = data;
+
+ if (m_r482e & 1)
+ {
+ //signed 32-bit x 16-bit division
+ INT32 dividend = (INT32)(m_r4820 + (m_r4821 << 8) + (m_r4822 << 16) + (m_r4823 << 24));
+ INT16 divisor = (INT16)(m_r4826 + (m_r4827 << 8));
+
+ INT32 quotient;
+ INT16 remainder;
+
+ if (divisor)
+ {
+ quotient = (INT32)(dividend / divisor);
+ remainder = (INT32)(dividend % divisor);
+ }
+ else
+ {
+ //illegal division by zero
+ quotient = 0;
+ remainder = dividend & 0xffff;
+ }
+
+ m_r4828 = quotient;
+ m_r4829 = quotient >> 8;
+ m_r482a = quotient >> 16;
+ m_r482b = quotient >> 24;
+
+ m_r482c = remainder;
+ m_r482d = remainder >> 8;
+ }
+ else
+ {
+ //unsigned 32-bit x 16-bit division
+ UINT32 dividend = (UINT32)(m_r4820 + (m_r4821 << 8) + (m_r4822 << 16) + (m_r4823 << 24));
+ UINT16 divisor = (UINT16)(m_r4826 + (m_r4827 << 8));
+
+ UINT32 quotient;
+ UINT16 remainder;
+
+ if (divisor)
+ {
+ quotient = (UINT32)(dividend / divisor);
+ remainder = (UINT16)(dividend % divisor);
+ }
+ else
+ {
+ //illegal division by zero
+ quotient = 0;
+ remainder = dividend & 0xffff;
+ }
+
+ m_r4828 = quotient;
+ m_r4829 = quotient >> 8;
+ m_r482a = quotient >> 16;
+ m_r482b = quotient >> 24;
+
+ m_r482c = remainder;
+ m_r482d = remainder >> 8;
+ }
+
+ m_r482f = 0x80;
+ break;
+ }
+
+ case 0x482e:
+ {
+ //reset math unit
+ m_r4820 = m_r4821 = m_r4822 = m_r4823 = 0;
+ m_r4824 = m_r4825 = m_r4826 = m_r4827 = 0;
+ m_r4828 = m_r4829 = m_r482a = m_r482b = 0;
+ m_r482c = m_r482d = 0;
+
+ m_r482e = data;
+ break;
+ }
+
+ //===================
+ //memory mapping unit
+ //===================
+
+ case 0x4830: m_r4830 = data; break;
+
+ case 0x4831:
+ {
+ m_r4831 = data;
+ m_dx_offset = spc7110_datarom_addr(data * 0x100000, len);
+ break;
+ }
+
+ case 0x4832:
+ {
+ m_r4832 = data;
+ m_ex_offset = spc7110_datarom_addr(data * 0x100000, len);
+ break;
+ }
+
+ case 0x4833:
+ {
+ m_r4833 = data;
+ m_fx_offset = spc7110_datarom_addr(data * 0x100000, len);
+ break;
+ }
+
+ case 0x4834: m_r4834 = data; break;
+
+ //====================
+ //real-time clock unit
+ //====================
+
+ case 0x4840:
+ {
+ m_r4840 = data;
+
+ if (!(m_r4840 & 1))
+ {
+ //disable RTC
+ m_rtc_state = RTCS_Inactive;
+ spc7110_update_time(0);
+ }
+ else
+ {
+ //enable RTC
+ m_r4842 = 0x80;
+ m_rtc_state = RTCS_ModeSelect;
+ }
+ }
+ break;
+
+ case 0x4841:
+ {
+ m_r4841 = data;
+
+ switch (m_rtc_state)
+ {
+ case RTCS_ModeSelect:
+ if (data == RTCM_Linear || data == RTCM_Indexed)
+ {
+ m_r4842 = 0x80;
+ m_rtc_state = RTCS_IndexSelect;
+ m_rtc_mode = (RTC_Mode)data;
+ m_rtc_index = 0;
+ }
+ break;
+
+ case RTCS_IndexSelect:
+ m_r4842 = 0x80;
+ m_rtc_index = data & 15;
+ if (m_rtc_mode == RTCM_Linear)
+ m_rtc_state = RTCS_Write;
+ break;
+
+ case RTCS_Write:
+ m_r4842 = 0x80;
+
+ //control register 0
+ if (m_rtc_index == 13)
+ {
+ //increment second counter
+ if (data & 2)
+ spc7110_update_time(1);
+
+ //round minute counter
+ if (data & 8)
+ {
+ spc7110_update_time(0);
+
+ UINT8 second = m_rtc_ram[0] + m_rtc_ram[1] * 10;
+ //clear seconds
+ m_rtc_ram[0] = 0;
+ m_rtc_ram[1] = 0;
+
+ if (second >= 30)
+ spc7110_update_time(60);
+ }
+ }
+
+ //control register 2
+ if (m_rtc_index == 15)
+ {
+ //disable timer and clear second counter
+ if ((data & 1) && !(m_rtc_ram[15] & 1))
+ {
+ spc7110_update_time(0);
+
+ //clear seconds
+ m_rtc_ram[0] = 0;
+ m_rtc_ram[1] = 0;
+ }
+
+ //disable timer
+ if ((data & 2) && !(m_rtc_ram[15] & 2))
+ spc7110_update_time(0);
+ }
+
+ m_rtc_ram[m_rtc_index] = data & 15;
+ m_rtc_index = (m_rtc_index + 1) & 15;
+ break;
+ }
+ }
+ break;
+ }
+}
+
+READ8_MEMBER(sns_rom_spc7110_device::read_l)
+{
+ if (offset < 0x400000)
+ return m_rom[rom_bank_map[offset / 0x8000] * 0x8000 + (offset & 0x7fff)];
+
+ return 0xff;
+}
+
+READ8_MEMBER(sns_rom_spc7110_device::read_h)
+{
+ UINT16 address = offset & 0xfffff;
+
+ if (offset < 0x400000)
+ return m_rom[rom_bank_map[offset / 0x8000] * 0x8000 + (offset & 0x7fff)];
+ else
+ {
+ switch (offset & 0x300000)
+ {
+ case 0x000000:
+ return m_rom[rom_bank_map[(offset - 0x400000) / 0x8000] * 0x8000 + (offset & 0x7fff)];
+ case 0x100000:
+ return m_rom[m_dx_offset + address];
+ case 0x200000:
+ return m_rom[m_ex_offset + address];
+ case 0x300000:
+ return m_rom[m_fx_offset + address];
+ default:
+ break;
+ }
+ }
+
+ return 0xff;
+}
+
+
+READ8_MEMBER( sns_rom_spc7110_device::read_ram )
+{
+ return m_nvram[offset & 0x1fff];
+}
+
+WRITE8_MEMBER( sns_rom_spc7110_device::write_ram )
+{
+ m_nvram[offset & 0x1fff] = data;
+}
diff --git a/src/emu/bus/snes/spc7110.h b/src/emu/bus/snes/spc7110.h
new file mode 100644
index 00000000000..c18bb16eaad
--- /dev/null
+++ b/src/emu/bus/snes/spc7110.h
@@ -0,0 +1,224 @@
+#ifndef __SNS_SPC7110_H
+#define __SNS_SPC7110_H
+
+#include "snes_slot.h"
+#include "rom21.h"
+
+
+enum RTC_State
+{
+ RTCS_Inactive,
+ RTCS_ModeSelect,
+ RTCS_IndexSelect,
+ RTCS_Write
+};
+
+enum RTC_Mode
+{
+ RTCM_Linear = 0x03,
+ RTCM_Indexed = 0x0c
+};
+
+class SPC7110_Decomp
+{
+public:
+ SPC7110_Decomp(running_machine &machine);
+
+ running_machine &machine() const { return m_machine; }
+
+ void init(running_machine &machine, UINT8 *ROM, UINT32 len, UINT32 mode, UINT32 offset, UINT32 index);
+ void reset();
+
+ UINT8 read(UINT8 *ROM, UINT32 len);
+ void write(UINT8 data);
+ void mode0(UINT8 init, UINT8 *ROM, UINT32 len);
+ void mode1(UINT8 init, UINT8 *ROM, UINT32 len);
+ void mode2(UINT8 init, UINT8 *ROM, UINT32 len);
+
+private:
+
+ UINT8 dataread(UINT8 *ROM, UINT32 len);
+ UINT8 probability(UINT32 n);
+ UINT8 next_lps(UINT32 n);
+ UINT8 next_mps(UINT32 n);
+ UINT8 toggle_invert(UINT32 n);
+ UINT32 morton_2x8(UINT32 data);
+ UINT32 morton_4x8(UINT32 data);
+
+ UINT32 m_decomp_mode;
+ UINT32 m_decomp_offset;
+
+ UINT8 *m_decomp_buffer;
+ UINT32 m_decomp_buffer_rdoffset;
+ UINT32 m_decomp_buffer_wroffset;
+ UINT32 m_decomp_buffer_length;
+
+ struct ContextState
+ {
+ UINT8 index;
+ UINT8 invert;
+ } m_context[32];
+
+ UINT32 m_morton16[2][256];
+ UINT32 m_morton32[4][256];
+
+ // mode 0 vars
+ UINT8 m_m0_val, m_m0_in, m_m0_span;
+ INT32 m_m0_out, m_m0_inverts, m_m0_lps, m_m0_in_count;
+
+ // mode 1 vars
+ INT32 m_m1_pixelorder[4], m_m1_realorder[4];
+ UINT8 m_m1_in, m_m1_val, m_m1_span;
+ INT32 m_m1_out, m_m1_inverts, m_m1_lps, m_m1_in_count;
+
+ // mode 2 vars
+ INT32 m_m2_pixelorder[16], m_m2_realorder[16];
+ UINT8 m_m2_bitplanebuffer[16], m_m2_buffer_index;
+ UINT8 m_m2_in, m_m2_val, m_m2_span;
+ INT32 m_m2_out0, m_m2_out1, m_m2_inverts, m_m2_lps, m_m2_in_count;
+
+ running_machine& m_machine;
+ //UINT32 m_rom_size;
+};
+
+// ======================> sns_rom_spc7110_device
+
+class sns_rom_spc7110_device : public sns_rom21_device
+{
+public:
+ // construction/destruction
+ sns_rom_spc7110_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);
+ sns_rom_spc7110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_READ8_MEMBER(read_ram);
+ virtual DECLARE_WRITE8_MEMBER(write_ram);
+
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ void spc7110_start();
+ UINT32 spc7110_datarom_addr(UINT32 addr, UINT32 len);
+ UINT32 spc7110_data_pointer();
+ UINT32 spc7110_data_adjust();
+ UINT32 spc7110_data_increment();
+ void spc7110_set_data_pointer(UINT32 addr);
+ void spc7110_set_data_adjust(UINT32 addr);
+ void spc7110_update_time(UINT8 offset);
+
+
+ //==================
+ //decompression unit
+ //==================
+ UINT8 m_r4801; // compression table low
+ UINT8 m_r4802; // compression table high
+ UINT8 m_r4803; // compression table bank
+ UINT8 m_r4804; // compression table index
+ UINT8 m_r4805; // decompression buffer index low
+ UINT8 m_r4806; // decompression buffer index high
+ UINT8 m_r4807; // ???
+ UINT8 m_r4808; // ???
+ UINT8 m_r4809; // compression length low
+ UINT8 m_r480a; // compression length high
+ UINT8 m_r480b; // decompression control register
+ UINT8 m_r480c; // decompression status
+
+ SPC7110_Decomp* m_decomp;
+
+ UINT8 m_r4811; // data pointer low
+ UINT8 m_r4812; // data pointer high
+ UINT8 m_r4813; // data pointer bank
+ UINT8 m_r4814; // data adjust low
+ UINT8 m_r4815; // data adjust high
+ UINT8 m_r4816; // data increment low
+ UINT8 m_r4817; // data increment high
+ UINT8 m_r4818; // data port control register
+
+ UINT8 m_r481x;
+
+ UINT8 m_r4814_latch;
+ UINT8 m_r4815_latch;
+
+ //=========
+ //math unit
+ //=========
+ UINT8 m_r4820; // 16-bit multiplicand B0, 32-bit dividend B0
+ UINT8 m_r4821; // 16-bit multiplicand B1, 32-bit dividend B1
+ UINT8 m_r4822; // 32-bit dividend B2
+ UINT8 m_r4823; // 32-bit dividend B3
+ UINT8 m_r4824; // 16-bit multiplier B0
+ UINT8 m_r4825; // 16-bit multiplier B1
+ UINT8 m_r4826; // 16-bit divisor B0
+ UINT8 m_r4827; // 16-bit divisor B1
+ UINT8 m_r4828; // 32-bit product B0, 32-bit quotient B0
+ UINT8 m_r4829; // 32-bit product B1, 32-bit quotient B1
+ UINT8 m_r482a; // 32-bit product B2, 32-bit quotient B2
+ UINT8 m_r482b; // 32-bit product B3, 32-bit quotient B3
+ UINT8 m_r482c; // 16-bit remainder B0
+ UINT8 m_r482d; // 16-bit remainder B1
+ UINT8 m_r482e; // math control register
+ UINT8 m_r482f; // math status
+
+ //===================
+ //memory mapping unit
+ //===================
+ UINT8 m_r4830; // SRAM write enable
+ UINT8 m_r4831; // $[d0-df]:[0000-ffff] mapping
+ UINT8 m_r4832; // $[e0-ef]:[0000-ffff] mapping
+ UINT8 m_r4833; // $[f0-ff]:[0000-ffff] mapping
+ UINT8 m_r4834; // ???
+
+ UINT32 m_dx_offset;
+ UINT32 m_ex_offset;
+ UINT32 m_fx_offset;
+
+ //====================
+ //real-time clock unit
+ //====================
+ UINT8 m_r4840; // RTC latch
+ UINT8 m_r4841; // RTC index/data port
+ UINT8 m_r4842; // RTC status
+
+ UINT32 m_rtc_state;
+ UINT32 m_rtc_mode;
+ UINT32 m_rtc_index;
+
+ UINT64 m_rtc_offset;
+
+ system_time m_rtc_basetime;
+
+ //this is now allocated in the main snes cart class, to allow saving to nvram
+ //UINT8 m_rtc_ram[16]; // 0-12 secs, min, hrs, etc.; 13-14-15 control registers
+};
+
+// ======================> sns_rom_spc7110_device
+
+class sns_rom_spc7110rtc_device : public sns_rom_spc7110_device
+{
+public:
+ // construction/destruction
+ sns_rom_spc7110rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // reading and writing
+
+// we just use the spc7110 ones for the moment, pending the split of regs 0x4840-0x4842 (RTC) from the base add-on
+// virtual DECLARE_READ8_MEMBER(read_l);
+// virtual DECLARE_READ8_MEMBER(read_h);
+
+// virtual DECLARE_READ8_MEMBER(chip_read);
+// virtual DECLARE_WRITE8_MEMBER(chip_write);
+};
+
+// device type definition
+extern const device_type SNS_HIROM_SPC7110;
+extern const device_type SNS_HIROM_SPC7110_RTC;
+
+#endif
diff --git a/src/emu/bus/snes/sufami.c b/src/emu/bus/snes/sufami.c
new file mode 100644
index 00000000000..f4f388bbfae
--- /dev/null
+++ b/src/emu/bus/snes/sufami.c
@@ -0,0 +1,163 @@
+/***********************************************************************************************************
+
+ Bandai Sufami Turbo cartridge emulation (for SNES/SFC)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ This is basically a standard LoROM cart with two slots for ST minicarts
+ The content of each slot (with ROM and RAM) is mapped to a separate memory range
+ Slot 1: ROM [20-3f][8000-ffff], RAM [60-63][8000-ffff]
+ Slot 2: ROM [40-5f][8000-ffff], RAM [70-73][8000-ffff]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "sufami.h"
+
+
+//-------------------------------------------------
+// sns_rom_sufami_device - constructor
+//-------------------------------------------------
+
+const device_type SNS_LOROM_SUFAMI = &device_creator<sns_rom_sufami_device>;
+const device_type SNS_STROM = &device_creator<sns_rom_strom_device>;
+
+
+sns_rom_sufami_device::sns_rom_sufami_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_SUFAMI, "SNES Sufami Turbo Cart", tag, owner, clock, "sns_rom_sufami", __FILE__),
+ m_slot1(*this, "st_slot1"),
+ m_slot2(*this, "st_slot2")
+{
+}
+
+sns_rom_strom_device::sns_rom_strom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_STROM, "SNES Sufami Turbo Minicart", tag, owner, clock, "sns_strom", __FILE__)
+{
+}
+
+
+void sns_rom_sufami_device::device_start()
+{
+}
+
+void sns_rom_strom_device::device_start()
+{
+}
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( st_slot )
+//-------------------------------------------------
+
+static SLOT_INTERFACE_START(sufamiturbo_cart)
+ SLOT_INTERFACE_INTERNAL("strom", SNS_STROM)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( st_slot )
+ MCFG_SNS_SUFAMI_CARTRIDGE_ADD("st_slot1", sufamiturbo_cart, NULL)
+ MCFG_SNS_SUFAMI_CARTRIDGE_ADD("st_slot2", sufamiturbo_cart, NULL)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor sns_rom_sufami_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( st_slot );
+}
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+READ8_MEMBER(sns_rom_sufami_device::read_l)
+{
+ return read_h(space, offset);
+}
+
+READ8_MEMBER(sns_rom_sufami_device::read_h)
+{
+ int bank;
+
+ if (offset < 0x200000) // SUFAMI TURBO ROM
+ {
+ bank = offset / 0x10000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ if (offset >= 0x200000 && offset < 0x400000) // SLOT1 STROM
+ {
+ return m_slot1->read_l(space, offset - 0x200000);
+ }
+ if (offset >= 0x400000 && offset < 0x600000) // SLOT2 STROM
+ {
+ return m_slot2->read_l(space, offset - 0x400000);
+ }
+ if (offset >= 0x600000 && offset < 0x640000) // SLOT1 RAM
+ {
+ if ((offset & 0xffff) >= 0x8000)
+ {
+ offset -= 0x600000;
+ bank = offset / 0x10000;
+ return m_slot1->read_ram(space, bank * 0x8000 + (offset & 0x7fff));
+ }
+ }
+ if (offset >= 0x700000 && offset < 0x740000) // SLOT2 RAM
+ {
+ if ((offset & 0xffff) >= 0x8000)
+ {
+ offset -= 0x700000;
+ bank = offset / 0x10000;
+ return m_slot2->read_ram(space, bank * 0x8000 + (offset & 0x7fff));
+ }
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(sns_rom_sufami_device::write_l)
+{
+ write_h(space, offset, data);
+}
+
+WRITE8_MEMBER(sns_rom_sufami_device::write_h)
+{
+ int bank;
+ if (offset >= 0x600000 && offset < 0x640000) // SLOT1 RAM
+ {
+ if ((offset & 0xffff) >= 0x8000)
+ {
+ offset -= 0x600000;
+ bank = offset / 0x10000;
+ m_slot1->write_ram(space, bank * 0x8000 + (offset & 0x7fff), data);
+ }
+ }
+
+ if (offset >= 0x700000 && offset < 0x740000) // SLOT2 RAM
+ {
+ if ((offset & 0xffff) >= 0x8000)
+ {
+ offset -= 0x700000;
+ bank = offset / 0x10000;
+ m_slot2->write_ram(space, bank * 0x8000 + (offset & 0x7fff), data);
+ }
+ }
+
+}
+
+/*-------------------------------------------------
+ Sufami Turbo 'minicart' emulation
+ -------------------------------------------------*/
+
+READ8_MEMBER(sns_rom_strom_device::read_l)
+{
+ if (offset < 0x200000)
+ {
+ int bank = offset / 0x10000;
+ return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
+ }
+ return 0xff;
+}
diff --git a/src/emu/bus/snes/sufami.h b/src/emu/bus/snes/sufami.h
new file mode 100644
index 00000000000..5e8572a953b
--- /dev/null
+++ b/src/emu/bus/snes/sufami.h
@@ -0,0 +1,51 @@
+#ifndef __SNS_SUFAMI_H
+#define __SNS_SUFAMI_H
+
+#include "snes_slot.h"
+#include "rom.h"
+
+
+// ======================> sns_rom_sufami_device
+
+class sns_rom_sufami_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_sufami_device(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;
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+private:
+ required_device<sns_sufami_cart_slot_device> m_slot1;
+ required_device<sns_sufami_cart_slot_device> m_slot2;
+};
+
+// ======================> sns_rom_strom_device
+
+class sns_rom_strom_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_strom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(read_l);
+};
+
+
+// device type definition
+extern const device_type SNS_LOROM_SUFAMI;
+extern const device_type SNS_STROM;
+
+#endif
diff --git a/src/emu/bus/snes/upd.c b/src/emu/bus/snes/upd.c
new file mode 100644
index 00000000000..9f73f9539d7
--- /dev/null
+++ b/src/emu/bus/snes/upd.c
@@ -0,0 +1,567 @@
+/***********************************************************************************************************
+
+ UPD7725 / UPD96050 add-on chip emulation (for SNES/SFC)
+ used in carts with DSP-1, DSP-1A, DSP-1B, DSP-2, DSP-3, DSP-4, ST-010 & ST-011 add-on chips
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "upd.h"
+
+
+// helpers
+inline UINT32 get_prg(UINT8 *CPU, UINT32 addr)
+{
+ return ((CPU[addr * 4] << 24) | (CPU[addr * 4 + 1] << 16) | (CPU[addr * 4 + 2] << 8) | 0x00);
+}
+inline UINT16 get_data(UINT8 *CPU, UINT32 addr)
+{
+ return ((CPU[addr * 2] << 8) | CPU[addr * 2 + 1]);
+}
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type SNS_LOROM_NECDSP = &device_creator<sns_rom20_necdsp_device>;
+const device_type SNS_HIROM_NECDSP = &device_creator<sns_rom21_necdsp_device>;
+const device_type SNS_LOROM_SETA10 = &device_creator<sns_rom_seta10dsp_device>;
+const device_type SNS_LOROM_SETA11 = &device_creator<sns_rom_seta11dsp_device>;
+
+
+sns_rom20_necdsp_device::sns_rom20_necdsp_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)
+ : sns_rom_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_upd7725(*this, "dsp")
+{
+}
+
+sns_rom20_necdsp_device::sns_rom20_necdsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_device(mconfig, SNS_LOROM_NECDSP, "SNES Cart (LoROM) + NEC DSP", tag, owner, clock, "sns_rom_necdsp", __FILE__),
+ m_upd7725(*this, "dsp")
+{
+}
+
+sns_rom21_necdsp_device::sns_rom21_necdsp_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)
+ : sns_rom21_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_upd7725(*this, "dsp")
+{
+}
+
+sns_rom21_necdsp_device::sns_rom21_necdsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom21_device(mconfig, SNS_HIROM_NECDSP, "SNES Cart (HiROM) + NEC DSP", tag, owner, clock, "sns_rom21_necdsp", __FILE__),
+ m_upd7725(*this, "dsp")
+{
+}
+
+sns_rom_setadsp_device::sns_rom_setadsp_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)
+ : sns_rom_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_upd96050(*this, "dsp")
+{
+}
+
+sns_rom_seta10dsp_device::sns_rom_seta10dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_setadsp_device(mconfig, SNS_LOROM_SETA10, "SNES Cart (LoROM) + Seta ST010 DSP", tag, owner, clock, "sns_rom_seta10", __FILE__)
+{
+}
+
+sns_rom_seta11dsp_device::sns_rom_seta11dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_setadsp_device(mconfig, SNS_LOROM_SETA11, "SNES Cart (LoROM) + Seta ST011 DSP", tag, owner, clock, "sns_rom_seta11", __FILE__)
+{
+}
+
+
+void sns_rom20_necdsp_device::device_start()
+{
+ m_dsp_prg = auto_alloc_array(machine(), UINT32, 0x2000/4);
+ m_dsp_data = auto_alloc_array(machine(), UINT16, 0x800/2);
+}
+
+void sns_rom21_necdsp_device::device_start()
+{
+ m_dsp_prg = auto_alloc_array(machine(), UINT32, 0x2000/4);
+ m_dsp_data = auto_alloc_array(machine(), UINT16, 0x800/2);
+}
+
+void sns_rom_setadsp_device::device_start()
+{
+ m_dsp_prg = auto_alloc_array(machine(), UINT32, 0x10000/4);
+ m_dsp_data = auto_alloc_array(machine(), UINT16, 0x1000/2);
+}
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+//-------------------------------------------------
+// NEC DSP
+//-------------------------------------------------
+
+// Lo-ROM
+
+// DSP dump contains prg at offset 0 and data at offset 0x2000
+READ32_MEMBER( sns_rom20_necdsp_device::necdsp_prg_r )
+{
+ return get_prg(m_bios, offset);
+}
+
+READ16_MEMBER( sns_rom20_necdsp_device::necdsp_data_r )
+{
+ return get_data(m_bios, offset + 0x2000/2);
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( dsp_prg_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( dsp_prg_map_lorom, AS_PROGRAM, 32, sns_rom20_necdsp_device )
+ AM_RANGE(0x0000, 0x07ff) AM_READ(necdsp_prg_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( dsp_data_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( dsp_data_map_lorom, AS_DATA, 16, sns_rom20_necdsp_device )
+ AM_RANGE(0x0000, 0x03ff) AM_READ(necdsp_data_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( snes_dsp )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( snes_dsp_lorom )
+ MCFG_CPU_ADD("dsp", UPD7725, 8000000)
+ MCFG_CPU_PROGRAM_MAP(dsp_prg_map_lorom)
+ MCFG_CPU_DATA_MAP(dsp_data_map_lorom)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor sns_rom20_necdsp_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_lorom );
+}
+
+READ8_MEMBER( sns_rom20_necdsp_device::chip_read )
+{
+ offset &= 0x7fff;
+ return m_upd7725->snesdsp_read(offset < 0x4000);
+}
+
+
+WRITE8_MEMBER( sns_rom20_necdsp_device::chip_write )
+{
+ offset &= 0x7fff;
+ m_upd7725->snesdsp_write(offset < 0x4000, data);
+}
+
+
+// Hi-ROM
+
+// DSP dump contains prg at offset 0 and data at offset 0x2000
+READ32_MEMBER( sns_rom21_necdsp_device::necdsp_prg_r )
+{
+ return get_prg(m_bios, offset);
+}
+
+READ16_MEMBER( sns_rom21_necdsp_device::necdsp_data_r )
+{
+ return get_data(m_bios, offset + 0x2000/2);
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( dsp_prg_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( dsp_prg_map_hirom, AS_PROGRAM, 32, sns_rom21_necdsp_device )
+ AM_RANGE(0x0000, 0x07ff) AM_READ(necdsp_prg_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( dsp_data_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( dsp_data_map_hirom, AS_DATA, 16, sns_rom21_necdsp_device )
+ AM_RANGE(0x0000, 0x03ff) AM_READ(necdsp_data_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( snes_dsp )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( snes_dsp_hirom )
+ MCFG_CPU_ADD("dsp", UPD7725, 8000000)
+ MCFG_CPU_PROGRAM_MAP(dsp_prg_map_hirom)
+ MCFG_CPU_DATA_MAP(dsp_data_map_hirom)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor sns_rom21_necdsp_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_hirom );
+}
+
+READ8_MEMBER( sns_rom21_necdsp_device::chip_read )
+{
+ offset &= 0x1fff;
+ return m_upd7725->snesdsp_read(offset < 0x1000);
+}
+
+
+WRITE8_MEMBER( sns_rom21_necdsp_device::chip_write )
+{
+ offset &= 0x1fff;
+ m_upd7725->snesdsp_write(offset < 0x1000, data);
+}
+
+
+//-------------------------------------------------
+// Seta DSP
+//-------------------------------------------------
+
+// same as above but additional read/write handling for the add-on chip
+
+READ8_MEMBER( sns_rom_setadsp_device::chip_read )
+{
+ if (offset >= 0x600000 && offset < 0x680000 && (offset & 0xffff) < 0x4000)
+ m_upd96050->snesdsp_read((offset & 0x01) ? FALSE : TRUE);
+
+ if (offset >= 0x680000 && offset < 0x700000 && (offset & 0xffff) < 0x8000)
+ {
+ UINT16 address = offset & 0xffff;
+ UINT16 temp = m_upd96050->dataram_r(address/2);
+ if (offset & 1)
+ return temp >> 8;
+ else
+ return temp & 0xff;
+ }
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER( sns_rom_setadsp_device::chip_write )
+{
+ if (offset >= 0x600000 && offset < 0x680000 && (offset & 0xffff) < 0x4000)
+ {
+ m_upd96050->snesdsp_write((offset & 0x01) ? FALSE : TRUE, data);
+ return;
+ }
+
+ if (offset >= 0x680000 && offset < 0x700000 && (offset & 0xffff) < 0x8000)
+ {
+ UINT16 address = offset & 0xffff;
+ UINT16 temp = m_upd96050->dataram_r(address/2);
+
+ if (offset & 1)
+ {
+ temp &= 0xff;
+ temp |= data << 8;
+ }
+ else
+ {
+ temp &= 0xff00;
+ temp |= data;
+ }
+
+ m_upd96050->dataram_w(address/2, temp);
+ return;
+ }
+}
+
+
+// DSP dump contains prg at offset 0 and data at offset 0x10000
+READ32_MEMBER( sns_rom_setadsp_device::setadsp_prg_r )
+{
+ return get_prg(m_bios, offset);
+}
+
+READ16_MEMBER( sns_rom_setadsp_device::setadsp_data_r )
+{
+ return get_data(m_bios, offset + 0x10000/2);
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( st01x_prg_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( st01x_prg_map, AS_PROGRAM, 32, sns_rom_setadsp_device )
+ AM_RANGE(0x0000, 0x3fff) AM_READ(setadsp_prg_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( st01x_data_map )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( st01x_data_map, AS_DATA, 16, sns_rom_setadsp_device )
+ AM_RANGE(0x0000, 0x07ff) AM_READ(setadsp_data_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( snes_st010 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( snes_st010 )
+ MCFG_CPU_ADD("dsp", UPD96050, 10000000)
+ MCFG_CPU_PROGRAM_MAP(st01x_prg_map)
+ MCFG_CPU_DATA_MAP(st01x_data_map)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// MACHINE_DRIVER( snes_st011 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( snes_st011 )
+ MCFG_CPU_ADD("dsp", UPD96050, 15000000)
+ MCFG_CPU_PROGRAM_MAP(st01x_prg_map)
+ MCFG_CPU_DATA_MAP(st01x_data_map)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor sns_rom_seta10dsp_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_st010 );
+}
+
+machine_config_constructor sns_rom_seta11dsp_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_st011 );
+}
+
+
+// To make faster DSP access to its internal rom, let's install read banks and map m_bios there with correct byte order
+
+void sns_rom20_necdsp_device::speedup_addon_bios_access()
+{
+ m_upd7725->space(AS_PROGRAM).install_read_bank(0x0000, 0x07ff, "dsp_prg");
+ m_upd7725->space(AS_DATA).install_read_bank(0x0000, 0x03ff, "dsp_data");
+ membank("dsp_prg")->set_base(m_dsp_prg);
+ membank("dsp_data")->set_base(m_dsp_data);
+ // copy data in the correct format
+ for (int x = 0; x < 0x800; x++)
+ m_dsp_prg[x] = (m_bios[x * 4] << 24) | (m_bios[x * 4 + 1] << 16) | (m_bios[x * 4 + 2] << 8) | 0x00;
+ for (int x = 0; x < 0x400; x++)
+ m_dsp_data[x] = (m_bios[0x2000 + x * 2] << 8) | m_bios[0x2000 + x * 2 + 1];
+}
+
+void sns_rom21_necdsp_device::speedup_addon_bios_access()
+{
+ m_upd7725->space(AS_PROGRAM).install_read_bank(0x0000, 0x07ff, "dsp_prg");
+ m_upd7725->space(AS_DATA).install_read_bank(0x0000, 0x03ff, "dsp_data");
+ membank("dsp_prg")->set_base(m_dsp_prg);
+ membank("dsp_data")->set_base(m_dsp_data);
+ // copy data in the correct format
+ for (int x = 0; x < 0x800; x++)
+ m_dsp_prg[x] = (m_bios[x * 4] << 24) | (m_bios[x * 4 + 1] << 16) | (m_bios[x * 4 + 2] << 8) | 0x00;
+ for (int x = 0; x < 0x400; x++)
+ m_dsp_data[x] = (m_bios[0x2000 + x * 2] << 8) | m_bios[0x2000 + x * 2 + 1];
+}
+
+void sns_rom_setadsp_device::speedup_addon_bios_access()
+{
+ m_upd96050->space(AS_PROGRAM).install_read_bank(0x0000, 0x3fff, "dsp_prg");
+ m_upd96050->space(AS_DATA).install_read_bank(0x0000, 0x07ff, "dsp_data");
+ membank("dsp_prg")->set_base(m_dsp_prg);
+ membank("dsp_data")->set_base(m_dsp_data);
+ // copy data in the correct format
+ for (int x = 0; x < 0x3fff; x++)
+ m_dsp_prg[x] = (m_bios[x * 4] << 24) | (m_bios[x * 4 + 1] << 16) | (m_bios[x * 4 + 2] << 8) | 0x00;
+ for (int x = 0; x < 0x07ff; x++)
+ m_dsp_data[x] = (m_bios[0x10000 + x * 2] << 8) | m_bios[0x10000 + x * 2 + 1];
+}
+
+
+
+
+// Legacy versions including DSP dump roms, in order to support faulty dumps missing DSP data...
+
+const device_type SNS_LOROM_NECDSP1_LEG = &device_creator<sns_rom20_necdsp1_legacy_device>;
+const device_type SNS_LOROM_NECDSP1B_LEG = &device_creator<sns_rom20_necdsp1b_legacy_device>;
+const device_type SNS_LOROM_NECDSP2_LEG = &device_creator<sns_rom20_necdsp2_legacy_device>;
+const device_type SNS_LOROM_NECDSP3_LEG = &device_creator<sns_rom20_necdsp3_legacy_device>;
+const device_type SNS_LOROM_NECDSP4_LEG = &device_creator<sns_rom20_necdsp4_legacy_device>;
+const device_type SNS_HIROM_NECDSP1_LEG = &device_creator<sns_rom21_necdsp1_legacy_device>;
+const device_type SNS_LOROM_SETA10_LEG = &device_creator<sns_rom_seta10dsp_legacy_device>;
+const device_type SNS_LOROM_SETA11_LEG = &device_creator<sns_rom_seta11dsp_legacy_device>;
+
+
+sns_rom20_necdsp1_legacy_device::sns_rom20_necdsp1_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP1_LEG, "SNES Cart (LoROM) + NEC DSP1 Legacy", tag, owner, clock, "dsp1leg", __FILE__)
+{
+}
+
+sns_rom20_necdsp1b_legacy_device::sns_rom20_necdsp1b_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP1B_LEG, "SNES Cart (LoROM) + NEC DSP1B Legacy", tag, owner, clock, "dsp1bleg", __FILE__)
+{
+}
+
+sns_rom20_necdsp2_legacy_device::sns_rom20_necdsp2_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP2_LEG, "SNES Cart (LoROM) + NEC DSP2 Legacy", tag, owner, clock, "dsp2leg", __FILE__)
+{
+}
+
+sns_rom20_necdsp3_legacy_device::sns_rom20_necdsp3_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP3_LEG, "SNES Cart (LoROM) + NEC DSP3 Legacy", tag, owner, clock, "dsp3leg", __FILE__)
+{
+}
+
+sns_rom20_necdsp4_legacy_device::sns_rom20_necdsp4_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP4_LEG, "SNES Cart (LoROM) + NEC DSP4 Legacy", tag, owner, clock, "dsp4leg", __FILE__)
+{
+}
+
+sns_rom21_necdsp1_legacy_device::sns_rom21_necdsp1_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom21_necdsp_device(mconfig, SNS_HIROM_NECDSP1_LEG, "SNES Cart (HiROM) + NEC DSP1 Legacy", tag, owner, clock, "dsp1leg_hi", __FILE__)
+{
+}
+
+sns_rom_seta10dsp_legacy_device::sns_rom_seta10dsp_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_setadsp_device(mconfig, SNS_LOROM_SETA10_LEG, "SNES Cart (LoROM) + Seta ST010 DSP Legacy", tag, owner, clock, "seta10leg", __FILE__)
+{
+}
+
+sns_rom_seta11dsp_legacy_device::sns_rom_seta11dsp_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : sns_rom_setadsp_device(mconfig, SNS_LOROM_SETA11_LEG, "SNES Cart (LoROM) + Seta ST011 DSP Legacy", tag, owner, clock, "seta11leg", __FILE__)
+{
+}
+
+
+machine_config_constructor sns_rom20_necdsp1_legacy_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_lorom );
+}
+
+machine_config_constructor sns_rom20_necdsp1b_legacy_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_lorom );
+}
+
+machine_config_constructor sns_rom20_necdsp2_legacy_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_lorom );
+}
+
+machine_config_constructor sns_rom20_necdsp3_legacy_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_lorom );
+}
+
+machine_config_constructor sns_rom20_necdsp4_legacy_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_lorom );
+}
+
+machine_config_constructor sns_rom21_necdsp1_legacy_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_dsp_hirom );
+}
+
+machine_config_constructor sns_rom_seta10dsp_legacy_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_st010 );
+}
+
+machine_config_constructor sns_rom_seta11dsp_legacy_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_st011 );
+}
+
+
+ROM_START( snes_dsp1 )
+ ROM_REGION(0x2800, "addon", 0)
+ ROM_LOAD( "dsp1.bin", 0, 0x02800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) )
+ROM_END
+
+ROM_START( snes_dsp1b )
+ ROM_REGION(0x2800, "addon", 0)
+ ROM_LOAD( "dsp1b.bin", 0, 0x02800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) )
+ROM_END
+
+ROM_START( snes_dsp2 )
+ ROM_REGION(0x2800, "addon", 0)
+ ROM_LOAD( "dsp2.bin", 0, 0x02800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) )
+ROM_END
+
+ROM_START( snes_dsp3 )
+ ROM_REGION(0x2800, "addon", 0)
+ ROM_LOAD( "dsp3.bin", 0, 0x02800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) )
+ROM_END
+
+ROM_START( snes_dsp4 )
+ ROM_REGION(0x2800, "addon", 0)
+ ROM_LOAD( "dsp4.bin", 0, 0x02800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) )
+ROM_END
+
+ROM_START( snes_st010 )
+ ROM_REGION(0x11000, "addon", 0)
+ ROM_LOAD( "st010.bin", 0, 0x11000, CRC(aa11ee2d) SHA1(cc1984e989cb94e3dcbb5f99e085b5414e18a017) )
+ROM_END
+
+ROM_START( snes_st011 )
+ ROM_REGION(0x11000, "addon", 0)
+ ROM_LOAD( "st011.bin", 0, 0x11000, CRC(34d2952c) SHA1(1375b8c1efc8cae4962b57dfe22f6b78e1ddacc8) )
+ROM_END
+
+const rom_entry *sns_rom20_necdsp1_legacy_device::device_rom_region() const
+{
+ return ROM_NAME( snes_dsp1 );
+}
+
+const rom_entry *sns_rom20_necdsp1b_legacy_device::device_rom_region() const
+{
+ return ROM_NAME( snes_dsp1b );
+}
+
+const rom_entry *sns_rom20_necdsp2_legacy_device::device_rom_region() const
+{
+ return ROM_NAME( snes_dsp2 );
+}
+
+const rom_entry *sns_rom20_necdsp3_legacy_device::device_rom_region() const
+{
+ return ROM_NAME( snes_dsp3 );
+}
+
+const rom_entry *sns_rom20_necdsp4_legacy_device::device_rom_region() const
+{
+ return ROM_NAME( snes_dsp4 );
+}
+
+const rom_entry *sns_rom21_necdsp1_legacy_device::device_rom_region() const
+{
+ return ROM_NAME( snes_dsp1 );
+}
+
+const rom_entry *sns_rom_seta10dsp_legacy_device::device_rom_region() const
+{
+ return ROM_NAME( snes_st010 );
+}
+
+const rom_entry *sns_rom_seta11dsp_legacy_device::device_rom_region() const
+{
+ return ROM_NAME( snes_st011 );
+}
diff --git a/src/emu/bus/snes/upd.h b/src/emu/bus/snes/upd.h
new file mode 100644
index 00000000000..ad084c672fc
--- /dev/null
+++ b/src/emu/bus/snes/upd.h
@@ -0,0 +1,221 @@
+#ifndef __SNS_UPD_H
+#define __SNS_UPD_H
+
+#include "snes_slot.h"
+#include "rom.h"
+#include "rom21.h"
+#include "cpu/upd7725/upd7725.h"
+
+// ======================> sns_rom_necdsp_device
+
+class sns_rom20_necdsp_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom20_necdsp_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);
+ sns_rom20_necdsp_device(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 speedup_addon_bios_access();
+
+ required_device<upd7725_device> m_upd7725;
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ virtual DECLARE_READ32_MEMBER(necdsp_prg_r);
+ virtual DECLARE_READ16_MEMBER(necdsp_data_r);
+
+ UINT32 *m_dsp_prg;
+ UINT16 *m_dsp_data;
+};
+
+// ======================> sns_rom21_necdsp_device
+
+class sns_rom21_necdsp_device : public sns_rom21_device
+{
+public:
+ // construction/destruction
+ sns_rom21_necdsp_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);
+ sns_rom21_necdsp_device(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 speedup_addon_bios_access();
+
+ required_device<upd7725_device> m_upd7725;
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ virtual DECLARE_READ32_MEMBER(necdsp_prg_r);
+ virtual DECLARE_READ16_MEMBER(necdsp_data_r);
+
+ UINT32 *m_dsp_prg;
+ UINT16 *m_dsp_data;
+};
+
+// ======================> sns_rom_setadsp_device
+
+class sns_rom_setadsp_device : public sns_rom_device
+{
+public:
+ // construction/destruction
+ sns_rom_setadsp_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-level overrides
+ virtual void device_start();
+ virtual void speedup_addon_bios_access();
+
+ required_device<upd96050_device> m_upd96050;
+
+ // additional reading and writing
+ virtual DECLARE_READ8_MEMBER(chip_read);
+ virtual DECLARE_WRITE8_MEMBER(chip_write);
+
+ virtual DECLARE_READ32_MEMBER(setadsp_prg_r);
+ virtual DECLARE_READ16_MEMBER(setadsp_data_r);
+
+ UINT32 *m_dsp_prg;
+ UINT16 *m_dsp_data;
+};
+
+// ======================> sns_rom_seta10dsp_device
+
+class sns_rom_seta10dsp_device : public sns_rom_setadsp_device
+{
+public:
+ // construction/destruction
+ sns_rom_seta10dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+// ======================> sns_rom_seta11dsp_device [Faster CPU than ST010]
+
+class sns_rom_seta11dsp_device : public sns_rom_setadsp_device
+{
+public:
+ // construction/destruction
+ sns_rom_seta11dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+
+// device type definition
+extern const device_type SNS_LOROM_NECDSP;
+extern const device_type SNS_HIROM_NECDSP;
+extern const device_type SNS_LOROM_SETA10;
+extern const device_type SNS_LOROM_SETA11;
+
+
+
+
+// Devices including DSP dumps to support faulty .sfc dumps missing DSP data
+
+class sns_rom20_necdsp1_legacy_device : public sns_rom20_necdsp_device
+{
+public:
+ // construction/destruction
+ sns_rom20_necdsp1_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class sns_rom20_necdsp1b_legacy_device : public sns_rom20_necdsp_device
+{
+public:
+ // construction/destruction
+ sns_rom20_necdsp1b_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class sns_rom20_necdsp2_legacy_device : public sns_rom20_necdsp_device
+{
+public:
+ // construction/destruction
+ sns_rom20_necdsp2_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class sns_rom20_necdsp3_legacy_device : public sns_rom20_necdsp_device
+{
+public:
+ // construction/destruction
+ sns_rom20_necdsp3_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class sns_rom20_necdsp4_legacy_device : public sns_rom20_necdsp_device
+{
+public:
+ // construction/destruction
+ sns_rom20_necdsp4_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class sns_rom21_necdsp1_legacy_device : public sns_rom21_necdsp_device
+{
+public:
+ // construction/destruction
+ sns_rom21_necdsp1_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class sns_rom_seta10dsp_legacy_device : public sns_rom_setadsp_device
+{
+public:
+ // construction/destruction
+ sns_rom_seta10dsp_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class sns_rom_seta11dsp_legacy_device : public sns_rom_setadsp_device
+{
+public:
+ // construction/destruction
+ sns_rom_seta11dsp_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+};
+
+extern const device_type SNS_LOROM_NECDSP1_LEG;
+extern const device_type SNS_LOROM_NECDSP1B_LEG;
+extern const device_type SNS_LOROM_NECDSP2_LEG;
+extern const device_type SNS_LOROM_NECDSP3_LEG;
+extern const device_type SNS_LOROM_NECDSP4_LEG;
+extern const device_type SNS_HIROM_NECDSP1_LEG;
+extern const device_type SNS_LOROM_SETA10_LEG;
+extern const device_type SNS_LOROM_SETA11_LEG;
+
+#endif