funtech/supracan.cpp: preliminary cart interface, add NVRAM support for games requiring it

This commit is contained in:
angelosa 2024-09-10 15:13:32 +02:00
parent 55c9a2722e
commit 1f06e6bdf5
7 changed files with 409 additions and 44 deletions

View File

@ -15,7 +15,7 @@ license:CC0-1.0
]]></notes>
<info name="serial" value="F001" />
<info name="alt_title" value="福爾摩沙大對決" />
<part name="cart" interface="supracan_cart">
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="0x100000">
<rom loadflag="load16_word_swap" name="Formosa Duel (Taiwan).bin" size="0x100000" crc="b2bf31dc" sha1="8d0680e1322af21b20d5cee2c100b05cf4217815" offset="0" />
</dataarea>
@ -33,7 +33,7 @@ license:CC0-1.0
]]></notes>
<info name="serial" value="F002" />
<info name="alt_title" value="三國志 武將爭霸" />
<part name="cart" interface="supracan_cart">
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="3145728">
<rom loadflag="load16_word_swap" name="sangofgt.bin" size="3145728" crc="a4de6dde" sha1="f4bed63775130a75eb9c50b32e0cf50d1a7b8f50" offset="0" />
</dataarea>
@ -53,11 +53,13 @@ Broken [video] during intro, uses bitmap mode
]]></notes>
<info name="serial" value="F003" />
<info name="alt_title" value="邪惡之子" />
<part name="cart" interface="supracan_cart">
<!-- TODO: sram -->
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="2097152">
<rom loadflag="load16_word_swap" name="16005.cu5" size="2097152" crc="9f6119a7" sha1="67ae9e7f99e1c3054ea54d53dbbba7792ef45134" offset="0" />
</dataarea>
<!-- TODO: unconfirmed size -->
<dataarea name="nvram" size="0x8000">
</dataarea>
</part>
</software>
@ -74,7 +76,7 @@ Broken [video] during intro, uses bitmap mode
]]></notes>
<info name="serial" value="F004" />
<info name="alt_title" value="音速飛龍" />
<part name="cart" interface="supracan_cart">
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="2097152">
<rom loadflag="load16_word_swap" name="speedydgn.bin" size="2097152" crc="f631383c" sha1="fbd62b5d287aa82ef27f400ab2a6b3da0308192a" offset="0" />
</dataarea>
@ -92,11 +94,13 @@ Broken [video] during intro, uses bitmap mode
]]></notes>
<info name="serial" value="F005" />
<info name="alt_title" value="超級中華職棒聯盟" />
<part name="cart" interface="supracan_cart">
<!-- TODO: sram -->
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="2097152">
<rom loadflag="load16_word_swap" name="16005.0" size="2097152" crc="ccf6829b" sha1="17a413803d8749fbe9643ca56d703afd64569b9f" offset="0" />
</dataarea>
<!-- TODO: unconfirmed size -->
<dataarea name="nvram" size="0x8000">
</dataarea>
</part>
</software>
@ -109,7 +113,7 @@ Can potentially hang, [maincpu] tight loops for $e80300 bit 7 high (verify)
]]></notes>
<info name="serial" value="F006" />
<info name="alt_title" value="嘻遊記" />
<part name="cart" interface="supracan_cart">
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="2097152">
<rom loadflag="load16_word_swap" name="16002.cu2" size="2097152" crc="cee25eea" sha1="fc82fc3a7d55571494cd62d8807160e22cf437bc" offset="0" />
</dataarea>
@ -126,12 +130,15 @@ Can potentially hang, [maincpu] tight loops for $e80300 bit 7 high (verify)
]]></notes>
<info name="serial" value="F007" />
<info name="alt_title" value="超級光明戰史" />
<part name="cart" interface="supracan_cart">
<!-- TODO: sram -->
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="3145728">
<rom loadflag="load16_word_swap" name="16007.0" size="2097152" crc="56c1c3fb" sha1="249e2ad6d8d40ecd31eda5a1bd5e5d0f47174a27" offset="000000" />
<rom loadflag="load16_word_swap" name="08007.1" size="1048576" crc="fc79f05f" sha1="7ce2e23ea3fd25764935708be4d47bf1a9843938" offset="0x200000" />
</dataarea>
<!-- TODO: unconfirmed size -->
<dataarea name="nvram" size="0x8000">
</dataarea>
</part>
</software>
@ -141,11 +148,14 @@ Can potentially hang, [maincpu] tight loops for $e80300 bit 7 high (verify)
<publisher>Panda Entertainment Technology</publisher>
<info name="serial" value="F008" />
<info name="alt_title" value="非洲探險" />
<part name="cart" interface="supracan_cart">
<!-- TODO: sram -->
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="1048576">
<rom loadflag="load16_word_swap" name="08003.bin" size="1048576" crc="dc3b7b84" sha1="6dcbd7923203da7892915595d65ee668afbf0339" offset="0" />
</dataarea>
<!-- TODO: unconfirmed size -->
<dataarea name="nvram" size="0x8000">
</dataarea>
</part>
</software>
@ -160,10 +170,15 @@ Erratic gameplay speed, controls [irq 3] as FRC, show [video] missing/glitched t
]]></notes>
<info name="serial" value="F009" />
<info name="alt_title" value="賭霸" />
<part name="cart" interface="supracan_cart">
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="2097152">
<rom loadflag="load16_word_swap" name="16006.bin" size="2097152" crc="ac4fa721" sha1="0fda223817f0b50f0ce9687076d29df3d1b86960" offset="0" />
</dataarea>
<!-- TODO: unconfirmed size and actual presence -->
<!-- Story mode would be impossible to run in one setting otherwise? -->
<dataarea name="nvram" size="0x8000">
</dataarea>
</part>
</software>
@ -179,7 +194,7 @@ Erratic gameplay speed, controls [irq 3] as FRC
]]></notes>
<info name="serial" value="F010" />
<info name="alt_title" value="魔棒撞球" />
<part name="cart" interface="supracan_cart">
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="2097152">
<rom loadflag="load16_word_swap" name="08004.bin" size="2097152" crc="aed4e4f8" sha1="6be79db9006c46ea21f5dbe1add755ce2e413796" offset="0" />
</dataarea>
@ -196,7 +211,7 @@ Uses [video] clipping for layer 1 during intro
<info name="serial" value="F011" />
<info name="alt_title" value="爆爆動物園" />
<part name="cart" interface="supracan_cart">
<part name="cart" interface="superacan_cart">
<dataarea name="rom" width="16" endianness="big" size="524288">
<rom loadflag="load16_word_swap" name="boomzoo.bin" size="524288" crc="6099bb44" sha1="0b5fbe2117bb77a827453c5489b3af691e5c7ade" offset="0" />
</dataarea>

View File

@ -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
---------------------------------------------------
--

View File

@ -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<const u16 *>(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<u8 *>(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;
}

View File

@ -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

View File

@ -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<superacan_cart_slot_device *>(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<device_superacan_cart_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<std::error_condition, std::string> 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<u16 *>(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");
}

View File

@ -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 <system_error>
#include <utility>
/***************************************************************************
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<device_superacan_cart_interface>
{
public:
// construction/destruction
template <typename T>
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<std::error_condition, std::string> 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

View File

@ -65,8 +65,8 @@ STATUS:
#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 @@ private:
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_soundcpu;
required_device<generic_slot_device> m_cart;
required_device<superacan_cart_slot_device> m_cart;
required_device<umc6650_device> m_lockout;
required_region_ptr<uint16_t> m_internal68;
memory_view m_main_loview;
@ -265,7 +265,6 @@ private:
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");
}