diff --git a/hash/supracan.xml b/hash/supracan.xml
index 46cb6ac0adaa5..7eeb366dd8199 100644
--- a/hash/supracan.xml
+++ b/hash/supracan.xml
@@ -15,7 +15,7 @@ license:CC0-1.0
]]>
-
+
@@ -33,7 +33,7 @@ license:CC0-1.0
]]>
-
+
@@ -53,11 +53,13 @@ Broken [video] during intro, uses bitmap mode
]]>
-
-
+
+
+
+
@@ -74,7 +76,7 @@ Broken [video] during intro, uses bitmap mode
]]>
-
+
@@ -92,11 +94,13 @@ Broken [video] during intro, uses bitmap mode
]]>
-
-
+
+
+
+
@@ -109,7 +113,7 @@ Can potentially hang, [maincpu] tight loops for $e80300 bit 7 high (verify)
]]>
-
+
@@ -126,12 +130,15 @@ Can potentially hang, [maincpu] tight loops for $e80300 bit 7 high (verify)
]]>
-
-
+
+
+
+
+
@@ -141,11 +148,14 @@ Can potentially hang, [maincpu] tight loops for $e80300 bit 7 high (verify)
Panda Entertainment Technology
-
-
+
+
+
+
+
@@ -160,10 +170,15 @@ Erratic gameplay speed, controls [irq 3] as FRC, show [video] missing/glitched t
]]>
-
+
+
+
+
+
+
@@ -179,7 +194,7 @@ Erratic gameplay speed, controls [irq 3] as FRC
]]>
-
+
@@ -196,7 +211,7 @@ Uses [video] clipping for layer 1 during intro
-
+
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index c6d4b7f1cb5c5..b1043154c3eb9 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -2576,6 +2576,20 @@ if (BUSES["SS50"]~=null) then
}
end
+---------------------------------------------------
+--
+--@src/devices/bus/supracan/slot.h,BUSES["SUPRACAN"] = true
+---------------------------------------------------
+
+if (BUSES["SUPRACAN"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/bus/supracan/slot.cpp",
+ MAME_DIR .. "src/devices/bus/supracan/slot.h",
+ MAME_DIR .. "src/devices/bus/supracan/rom.cpp",
+ MAME_DIR .. "src/devices/bus/supracan/rom.h",
+ }
+end
+
---------------------------------------------------
--
diff --git a/src/devices/bus/supracan/rom.cpp b/src/devices/bus/supracan/rom.cpp
new file mode 100644
index 0000000000000..ca3be333df60d
--- /dev/null
+++ b/src/devices/bus/supracan/rom.cpp
@@ -0,0 +1,96 @@
+// license:BSD-3-Clause
+// copyright-holders:
+
+#include "emu.h"
+#include "rom.h"
+
+
+//-------------------------------------------------
+// superacan_rom_device - constructor
+//-------------------------------------------------
+
+DEFINE_DEVICE_TYPE(SUPERACAN_ROM_STD, superacan_rom_device, "superacan_rom", "Super A'Can Standard Cart")
+
+
+superacan_rom_device::superacan_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock), device_superacan_cart_interface(mconfig, *this)
+ , m_rom_base(nullptr)
+ , m_nvram_base(nullptr)
+ , m_rom_size(0)
+ , m_nvram_size(0)
+{
+}
+
+superacan_rom_device::superacan_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : superacan_rom_device(mconfig, SUPERACAN_ROM_STD, tag, owner, clock)
+{
+}
+
+
+void superacan_rom_device::device_start()
+{
+}
+
+void superacan_rom_device::device_add_mconfig(machine_config &config)
+{
+ // TODO: move UM6650 from funtech folder
+}
+
+std::error_condition superacan_rom_device::load()
+{
+ memory_region *const romregion = memregion("^rom");
+ m_rom_base = reinterpret_cast(romregion->base());
+ m_rom_size = romregion->bytes() / 2;
+
+// if (m_rom_size > 0x40'0000)
+// return std::make_pair(image_error::INVALIDLENGTH, "Unsupported cartridge size (must be no larger than 4M)");
+
+ memory_region *const nvramregion = memregion("^nvram");
+ if (nvramregion)
+ {
+ m_nvram_base = reinterpret_cast(nvramregion->base());
+ m_nvram_size = nvramregion->bytes();
+
+ if (m_nvram_size & (m_nvram_size - 1))
+ return image_error::BADSOFTWARE;
+
+ save_pointer(NAME(m_nvram_base), m_nvram_size);
+ battery_load(m_nvram_base, m_nvram_size, 0xff);
+ }
+
+ return std::error_condition();
+}
+
+
+void superacan_rom_device::unload()
+{
+ if (m_nvram_base)
+ battery_save(m_nvram_base, m_nvram_size);
+}
+
+
+/*-------------------------------------------------
+ read/write
+ -------------------------------------------------*/
+
+u16 superacan_rom_device::rom_r(offs_t offset)
+{
+ if (offset < m_rom_size)
+ return m_rom_base[offset];
+ else
+ return 0xffff;
+}
+
+u8 superacan_rom_device::nvram_r(offs_t offset)
+{
+ if (m_nvram_base)
+ return m_nvram_base[offset & (m_nvram_size - 1)];
+ else
+ return 0xff;
+}
+
+void superacan_rom_device::nvram_w(offs_t offset, u8 data)
+{
+ if (m_nvram_base)
+ m_nvram_base[offset & (m_nvram_size - 1)] = data;
+}
diff --git a/src/devices/bus/supracan/rom.h b/src/devices/bus/supracan/rom.h
new file mode 100644
index 0000000000000..a75cb26fa6654
--- /dev/null
+++ b/src/devices/bus/supracan/rom.h
@@ -0,0 +1,46 @@
+// license:BSD-3-Clause
+// copyright-holders:
+#ifndef MAME_BUS_SUPERACAN_ROM_H
+#define MAME_BUS_SUPERACAN_ROM_H
+
+#pragma once
+
+#include "slot.h"
+
+
+// ======================> superacan_rom_device
+
+class superacan_rom_device : public device_t,
+ public device_superacan_cart_interface
+{
+public:
+ // construction/destruction
+ superacan_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ // load/unload
+ virtual std::error_condition load() override;
+ virtual void unload() override;
+
+ // read/write
+ virtual u16 rom_r(offs_t offset) override;
+ virtual u8 nvram_r(offs_t offset) override;
+ virtual void nvram_w(offs_t offset, u8 data) override;
+
+protected:
+ superacan_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
+ virtual void device_start() override;
+
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ const u16 *m_rom_base;
+ u8 *m_nvram_base;
+ u32 m_rom_size;
+ u32 m_nvram_size;
+};
+
+
+DECLARE_DEVICE_TYPE(SUPERACAN_ROM_STD, superacan_rom_device)
+
+#endif // MAME_BUS_SUPERACAN_ROM_H
diff --git a/src/devices/bus/supracan/slot.cpp b/src/devices/bus/supracan/slot.cpp
new file mode 100644
index 0000000000000..19f10c449f6b4
--- /dev/null
+++ b/src/devices/bus/supracan/slot.cpp
@@ -0,0 +1,116 @@
+// license:BSD-3-Clause
+// copyright-holders:
+
+#include "emu.h"
+#include "slot.h"
+
+
+DEFINE_DEVICE_TYPE(SUPERACAN_CART_SLOT, superacan_cart_slot_device, "superacan_cart_slot", "Super A'Can Cartridge Slot")
+
+
+device_superacan_cart_interface::device_superacan_cart_interface(const machine_config &mconfig, device_t &device)
+ : device_interface(device, "superacan_cart")
+ , m_slot(dynamic_cast(device.owner()))
+{
+}
+
+
+device_superacan_cart_interface::~device_superacan_cart_interface()
+{
+}
+
+
+void device_superacan_cart_interface::battery_load(void *buffer, int length, int fill)
+{
+ assert(m_slot);
+ m_slot->battery_load(buffer, length, fill);
+}
+
+void device_superacan_cart_interface::battery_load(void *buffer, int length, void *def_buffer)
+{
+ assert(m_slot);
+ m_slot->battery_load(buffer, length, def_buffer);
+}
+
+void device_superacan_cart_interface::battery_save(const void *buffer, int length)
+{
+ assert(m_slot);
+ m_slot->battery_save(buffer, length);
+}
+
+
+superacan_cart_slot_device::superacan_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SUPERACAN_CART_SLOT, tag, owner, clock),
+ device_cartrom_image_interface(mconfig, *this),
+ device_single_card_slot_interface(mconfig, *this),
+ m_cart(nullptr)
+{
+}
+
+
+//-------------------------------------------------
+// superacan_cart_slot_device - destructor
+//-------------------------------------------------
+
+superacan_cart_slot_device::~superacan_cart_slot_device()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void superacan_cart_slot_device::device_start()
+{
+ m_cart = get_card_device();
+}
+
+
+
+/*-------------------------------------------------
+ call load
+ -------------------------------------------------*/
+
+std::pair superacan_cart_slot_device::call_load()
+{
+ if (!m_cart)
+ return std::make_pair(std::error_condition(), std::string());
+
+ memory_region *romregion = loaded_through_softlist() ? memregion("rom") : nullptr;
+ if (loaded_through_softlist() && !romregion)
+ return std::make_pair(image_error::INVALIDLENGTH, "Software list item has no 'rom' data area");
+
+ const u32 len = loaded_through_softlist() ? romregion->bytes() : length();
+
+ if (!loaded_through_softlist())
+ {
+ romregion = machine().memory().region_alloc(subtag("rom"), len, 2, ENDIANNESS_BIG);
+ u16 *const rombase = reinterpret_cast(romregion->base());
+ const u32 cnt = fread(rombase, len);
+ if (cnt != len)
+ return std::make_pair(std::errc::io_error, "Error reading cartridge file");
+ }
+
+ return std::make_pair(m_cart->load(), std::string());
+}
+
+
+/*-------------------------------------------------
+ call unload
+ -------------------------------------------------*/
+
+void superacan_cart_slot_device::call_unload()
+{
+ if (m_cart)
+ m_cart->unload();
+}
+
+
+/*-------------------------------------------------
+ get default card software
+ -------------------------------------------------*/
+
+std::string superacan_cart_slot_device::get_default_card_software(get_default_card_software_hook &hook) const
+{
+ return software_get_default_slot("std");
+}
diff --git a/src/devices/bus/supracan/slot.h b/src/devices/bus/supracan/slot.h
new file mode 100644
index 0000000000000..2c28537780705
--- /dev/null
+++ b/src/devices/bus/supracan/slot.h
@@ -0,0 +1,90 @@
+// license:BSD-3-Clause
+// copyright-holders:
+
+#ifndef MAME_BUS_SUPERACAN_SLOT_H
+#define MAME_BUS_SUPERACAN_SLOT_H
+
+#include "imagedev/cartrom.h"
+
+#include
+#include
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+ ***************************************************************************/
+
+class superacan_cart_slot_device;
+
+
+class device_superacan_cart_interface : public device_interface
+{
+public:
+ virtual ~device_superacan_cart_interface();
+
+ // load/unload
+ virtual std::error_condition load() = 0;
+ virtual void unload() = 0;
+
+ // read/write
+ virtual u16 rom_r(offs_t offset) = 0;
+ virtual u8 nvram_r(offs_t offset) = 0;
+ virtual void nvram_w(offs_t offset, u8 data) = 0;
+
+protected:
+ // construction/destruction
+ device_superacan_cart_interface(const machine_config &mconfig, device_t &device);
+
+ // helpers for slot stuff
+ void battery_load(void *buffer, int length, int fill);
+ void battery_load(void *buffer, int length, void *def_buffer);
+ void battery_save(const void *buffer, int length);
+
+private:
+ superacan_cart_slot_device *const m_slot;
+};
+
+
+class superacan_cart_slot_device : public device_t,
+ public device_cartrom_image_interface,
+ public device_single_card_slot_interface
+{
+public:
+ // construction/destruction
+ template
+ superacan_cart_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, T &&opts, char const *dflt)
+ : superacan_cart_slot_device(mconfig, tag, owner, clock)
+ {
+ option_reset();
+ opts(*this);
+ set_default_option(dflt);
+ set_fixed(false);
+ }
+ superacan_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ virtual ~superacan_cart_slot_device();
+
+ // device_image_interface implementation
+ virtual std::pair call_load() override;
+ virtual void call_unload() override;
+
+ virtual bool is_reset_on_load() const noexcept override { return true; }
+ virtual const char *image_interface() const noexcept override { return "superacan_cart"; }
+ virtual const char *file_extensions() const noexcept override { return "bin"; }
+
+ virtual std::string get_default_card_software(get_default_card_software_hook &hook) const override;
+
+ // reading and writing
+ u16 rom_r(offs_t offset) { return m_cart ? m_cart->rom_r(offset) : 0xffff; }
+ u8 nvram_r(offs_t offset) { return m_cart ? m_cart->nvram_r(offset) : 0xff; }
+ void nvram_w(offs_t offset, u8 data) { if (m_cart) m_cart->nvram_w(offset, data); }
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+
+ device_superacan_cart_interface *m_cart;
+};
+
+DECLARE_DEVICE_TYPE(SUPERACAN_CART_SLOT, superacan_cart_slot_device)
+
+#endif // MAME_BUS_SUPERACAN_SLOT_H
diff --git a/src/mame/funtech/supracan.cpp b/src/mame/funtech/supracan.cpp
index b72028b056139..1ce7320e39c40 100644
--- a/src/mame/funtech/supracan.cpp
+++ b/src/mame/funtech/supracan.cpp
@@ -65,8 +65,8 @@ Super A'Can (c) 1995 Funtech
#include "emu.h"
-#include "bus/generic/slot.h"
-#include "bus/generic/carts.h"
+#include "bus/supracan/rom.h"
+#include "bus/supracan/slot.h"
#include "cpu/m68000/m68000.h"
#include "cpu/m6502/m65c02.h"
@@ -179,7 +179,7 @@ class supracan_state : public driver_device
required_device m_maincpu;
required_device m_soundcpu;
- required_device m_cart;
+ required_device m_cart;
required_device m_lockout;
required_region_ptr m_internal68;
memory_view m_main_loview;
@@ -265,7 +265,6 @@ class supracan_state : public driver_device
TIMER_CALLBACK_MEMBER(line_on_cb);
TIMER_CALLBACK_MEMBER(line_off_cb);
TIMER_CALLBACK_MEMBER(scanline_cb);
- DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load);
int get_tilemap_region(int layer);
void get_tilemap_info_common(int layer, tile_data &tileinfo, int count);
void get_roz_tilemap_info(int layer, tile_data &tileinfo, int count);
@@ -308,7 +307,7 @@ int supracan_state::get_tilemap_region(int layer)
}
// TODO: 4th layer at $f00160 (gfx mode 0 only, ignored for everything else)
- throw new emu_fatalerror("Error: layer = %d not defined", layer);
+ throw emu_fatalerror("Error: layer = %d not defined", layer);
}
void supracan_state::get_tilemap_info_common(int layer, tile_data &tileinfo, int count)
@@ -1349,9 +1348,9 @@ void supracan_state::vram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
void supracan_state::main_map(address_map &map)
{
map(0x000000, 0x3fffff).view(m_main_loview);
- m_main_loview[0](0x000000, 0x3fffff).r(m_cart, FUNC(generic_slot_device::read16_rom));
+ m_main_loview[0](0x000000, 0x3fffff).r(m_cart, FUNC(superacan_cart_slot_device::rom_r)),
m_main_loview[0](0x000000, 0x000fff).rom().region(m_internal68, 0);
- m_main_loview[1](0x000000, 0x3fffff).r(m_cart, FUNC(generic_slot_device::read16_rom));
+ m_main_loview[1](0x000000, 0x3fffff).r(m_cart, FUNC(superacan_cart_slot_device::rom_r));
map(0xe80000, 0xe8ffff).rw(FUNC(supracan_state::_68k_soundram_r), FUNC(supracan_state::_68k_soundram_w));
map(0xe90000, 0xe9001f).m(*this, FUNC(supracan_state::host_um6619_map));
map(0xe90020, 0xe9002f).w(FUNC(supracan_state::dma_w<0>));
@@ -1361,15 +1360,15 @@ void supracan_state::main_map(address_map &map)
map(0xeb0d00, 0xeb0d03).rw(m_lockout, FUNC(umc6650_device::read), FUNC(umc6650_device::write)).umask16(0x00ff);
-// map(0xec0000, 0xec*fff) Cart NVRAM, 8-bit interface
+ map(0xec0000, 0xecffff).rw(m_cart, FUNC(superacan_cart_slot_device::nvram_r), FUNC(superacan_cart_slot_device::nvram_w)).umask16(0x00ff);
map(0xf00000, 0xf001ff).rw(FUNC(supracan_state::video_r), FUNC(supracan_state::video_w));
map(0xf00200, 0xf003ff).ram().w("palette", FUNC(palette_device::write16)).share("palette");
map(0xf40000, 0xf5ffff).ram().w(FUNC(supracan_state::vram_w)).share("vram");
map(0xf80000, 0xfbffff).view(m_main_hiview);
- m_main_hiview[0](0xf80000, 0xfbffff).r(m_cart, FUNC(generic_slot_device::read16_rom));
+ m_main_hiview[0](0xf80000, 0xfbffff).r(m_cart, FUNC(superacan_cart_slot_device::rom_r));
m_main_hiview[0](0xf80000, 0xf80fff).rom().region(m_internal68, 0);
- m_main_hiview[1](0xf80000, 0xfbffff).r(m_cart, FUNC(generic_slot_device::read16_rom));
+ m_main_hiview[1](0xf80000, 0xfbffff).r(m_cart, FUNC(superacan_cart_slot_device::rom_r));
map(0xfc0000, 0xfcffff).mirror(0x30000).ram(); /* System work ram */
}
@@ -2060,20 +2059,6 @@ void supracan_state::video_w(offs_t offset, uint16_t data, uint16_t mem_mask)
// m_video_regs[offset] = data;
}
-
-DEVICE_IMAGE_LOAD_MEMBER(supracan_state::cart_load)
-{
- uint32_t size = m_cart->common_get_size("rom");
-
- if (size > 0x40'0000)
- return std::make_pair(image_error::INVALIDLENGTH, "Unsupported cartridge size (must be no larger than 4M)");
-
- m_cart->rom_alloc(size, GENERIC_ROM16_WIDTH, ENDIANNESS_BIG);
- m_cart->common_load_rom(m_cart->get_rom_base(), size, "rom");
-
- return std::make_pair(std::error_condition(), std::string());
-}
-
static INPUT_PORTS_START( supracan )
PORT_START("P1")
PORT_BIT(0x000f, IP_ACTIVE_LOW, IPT_UNUSED)
@@ -2275,6 +2260,12 @@ static GFXDECODE_START( gfx_supracan )
GFXDECODE_RAM( "vram", 0, supracan_gfx1bpp_alt, 0, 0x80 )
GFXDECODE_END
+static void superacan_cart_types(device_slot_interface &device)
+{
+ device.option_add_internal("std", SUPERACAN_ROM_STD);
+}
+
+
void supracan_state::supracan(machine_config &config)
{
// M68000P10
@@ -2311,11 +2302,8 @@ void supracan_state::supracan(machine_config &config)
m_sound->add_route(0, "lspeaker", 1.0);
m_sound->add_route(1, "rspeaker", 1.0);
- generic_cartslot_device &cartslot(GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "supracan_cart"));
- cartslot.set_must_be_loaded(true);
- cartslot.set_width(GENERIC_ROM16_WIDTH);
- cartslot.set_endian(ENDIANNESS_BIG);
- cartslot.set_device_load(FUNC(supracan_state::cart_load));
+ // TODO: clock for cart is (again) unconfirmed
+ SUPERACAN_CART_SLOT(config, m_cart, U13_CLOCK / 6, superacan_cart_types, nullptr).set_must_be_loaded(true);
SOFTWARE_LIST(config, "cart_list").set_original("supracan");
}