From 69e33bcb5ed9a375db6e7f3bc5a266f6731cc8d0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 10 Mar 2014 08:29:46 +0000 Subject: snes and nes slot devices moved into bus folder (nw) --- src/emu/bus/snes/bsx.c | 545 +++++++++++++ src/emu/bus/snes/bsx.h | 149 ++++ src/emu/bus/snes/event.c | 286 +++++++ src/emu/bus/snes/event.h | 55 ++ src/emu/bus/snes/rom.c | 517 +++++++++++++ src/emu/bus/snes/rom.h | 207 +++++ src/emu/bus/snes/rom21.c | 265 +++++++ src/emu/bus/snes/rom21.h | 65 ++ src/emu/bus/snes/sa1.c | 1141 ++++++++++++++++++++++++++++ src/emu/bus/snes/sa1.h | 111 +++ src/emu/bus/snes/sdd1.c | 618 +++++++++++++++ src/emu/bus/snes/sdd1.h | 185 +++++ src/emu/bus/snes/sfx.c | 149 ++++ src/emu/bus/snes/sfx.h | 48 ++ src/emu/bus/snes/sgb.c | 293 +++++++ src/emu/bus/snes/sgb.h | 76 ++ src/emu/bus/snes/snes_carts.c | 50 ++ src/emu/bus/snes/snes_carts.h | 29 + src/emu/bus/snes/snes_slot.c | 1397 ++++++++++++++++++++++++++++++++++ src/emu/bus/snes/snes_slot.h | 275 +++++++ src/emu/bus/snes/spc7110.c | 1681 +++++++++++++++++++++++++++++++++++++++++ src/emu/bus/snes/spc7110.h | 224 ++++++ src/emu/bus/snes/sufami.c | 163 ++++ src/emu/bus/snes/sufami.h | 51 ++ src/emu/bus/snes/upd.c | 567 ++++++++++++++ src/emu/bus/snes/upd.h | 221 ++++++ 26 files changed, 9368 insertions(+) create mode 100644 src/emu/bus/snes/bsx.c create mode 100644 src/emu/bus/snes/bsx.h create mode 100644 src/emu/bus/snes/event.c create mode 100644 src/emu/bus/snes/event.h create mode 100644 src/emu/bus/snes/rom.c create mode 100644 src/emu/bus/snes/rom.h create mode 100644 src/emu/bus/snes/rom21.c create mode 100644 src/emu/bus/snes/rom21.h create mode 100644 src/emu/bus/snes/sa1.c create mode 100644 src/emu/bus/snes/sa1.h create mode 100644 src/emu/bus/snes/sdd1.c create mode 100644 src/emu/bus/snes/sdd1.h create mode 100644 src/emu/bus/snes/sfx.c create mode 100644 src/emu/bus/snes/sfx.h create mode 100644 src/emu/bus/snes/sgb.c create mode 100644 src/emu/bus/snes/sgb.h create mode 100644 src/emu/bus/snes/snes_carts.c create mode 100644 src/emu/bus/snes/snes_carts.h create mode 100644 src/emu/bus/snes/snes_slot.c create mode 100644 src/emu/bus/snes/snes_slot.h create mode 100644 src/emu/bus/snes/spc7110.c create mode 100644 src/emu/bus/snes/spc7110.h create mode 100644 src/emu/bus/snes/sufami.c create mode 100644 src/emu/bus/snes/sufami.h create mode 100644 src/emu/bus/snes/upd.c create mode 100644 src/emu/bus/snes/upd.h (limited to 'src/emu/bus/snes') 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; +const device_type SNS_LOROM_BSX = &device_creator; +const device_type SNS_HIROM_BSX = &device_creator; +const device_type SNS_BSMEMPAK = &device_creator; + + +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 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 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 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(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 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; +const device_type SNS_LOROM_OBC1 = &device_creator; +// LoROM pirate carts with protection +const device_type SNS_LOROM_POKEMON = &device_creator; +const device_type SNS_LOROM_TEKKEN2 = &device_creator; +const device_type SNS_LOROM_SOULBLAD = &device_creator; +const device_type SNS_LOROM_BANANA = &device_creator; +const device_type SNS_LOROM_BUGSLIFE = &device_creator; +// LoROM pirate multicarts +const device_type SNS_LOROM_MCPIR1 = &device_creator; +const device_type SNS_LOROM_MCPIR2 = &device_creator; +const device_type SNS_LOROM_20COL = &device_creator; + + +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; +const device_type SNS_HIROM_SRTC = &device_creator; + + +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(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 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(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(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 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(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 m_gb_cpu; + required_device m_gb_snd; + required_device m_gb_lcd; + required_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; +const device_type SNS_SUFAMI_CART_SLOT = &device_creator; +const device_type SNS_BSX_CART_SLOT = &device_creator; + +//************************************************************************** +// 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(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; +const device_type SNS_HIROM_SPC7110_RTC = &device_creator; + + +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; +const device_type SNS_STROM = &device_creator; + + +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 m_slot1; + required_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; +const device_type SNS_HIROM_NECDSP = &device_creator; +const device_type SNS_LOROM_SETA10 = &device_creator; +const device_type SNS_LOROM_SETA11 = &device_creator; + + +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; +const device_type SNS_LOROM_NECDSP1B_LEG = &device_creator; +const device_type SNS_LOROM_NECDSP2_LEG = &device_creator; +const device_type SNS_LOROM_NECDSP3_LEG = &device_creator; +const device_type SNS_LOROM_NECDSP4_LEG = &device_creator; +const device_type SNS_HIROM_NECDSP1_LEG = &device_creator; +const device_type SNS_LOROM_SETA10_LEG = &device_creator; +const device_type SNS_LOROM_SETA11_LEG = &device_creator; + + +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 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 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 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 -- cgit v1.2.3-70-g09d2