From b8feed79290f0a6e347416db31f6dc0e765fc244 Mon Sep 17 00:00:00 2001 From: David Haywood Date: Fri, 20 Oct 2017 01:43:09 +0100 Subject: use slot device for gamate cartridge slot, do protection handling there (it's a mapper chip in the cartridge) protection handled etc. written from scratch based on notes from Kevtris and Peter banking in the slot system seems somewhat archaic compared to proper modern banking, but this is how all other drivers I saw using slot roms did it. --- src/devices/bus/gamate/gamate_protection.cpp | 113 ++++++++++++ src/devices/bus/gamate/gamate_protection.h | 39 +++++ src/devices/bus/gamate/rom.cpp | 184 ++++++++++++++++++++ src/devices/bus/gamate/rom.h | 86 ++++++++++ src/devices/bus/gamate/slot.cpp | 248 +++++++++++++++++++++++++++ src/devices/bus/gamate/slot.h | 104 +++++++++++ 6 files changed, 774 insertions(+) create mode 100644 src/devices/bus/gamate/gamate_protection.cpp create mode 100644 src/devices/bus/gamate/gamate_protection.h create mode 100644 src/devices/bus/gamate/rom.cpp create mode 100644 src/devices/bus/gamate/rom.h create mode 100644 src/devices/bus/gamate/slot.cpp create mode 100644 src/devices/bus/gamate/slot.h (limited to 'src/devices/bus/gamate') diff --git a/src/devices/bus/gamate/gamate_protection.cpp b/src/devices/bus/gamate/gamate_protection.cpp new file mode 100644 index 00000000000..d3c257c53fa --- /dev/null +++ b/src/devices/bus/gamate/gamate_protection.cpp @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "emu.h" +#include "gamate_protection.h" + +DEFINE_DEVICE_TYPE(GAMATE_PROT, gamate_protection_device, "gamate_prot", "Gamate Protection Mapper") + +gamate_protection_device::gamate_protection_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, GAMATE_PROT, tag, owner, clock), + m_is_protection_passed(0), + m_has_failed(0), + m_passed_write(0), + m_inpos(0), + m_inbyte(0), + m_inseq(0) +{ +} + +void gamate_protection_device::device_start() +{ + save_item(NAME(m_is_protection_passed)); + save_item(NAME(m_has_failed)); + save_item(NAME(m_passed_write)); + save_item(NAME(m_inpos)); + save_item(NAME(m_inbyte)); + save_item(NAME(m_inseq)); +} + +void gamate_protection_device::device_reset() +{ + m_is_protection_passed = 0; + m_has_failed = 0; + m_passed_write = 0; + m_inpos = 0; + m_inbyte = 0; + m_inseq = 0; +} + +bool gamate_protection_device::is_protection_passed() +{ + return m_is_protection_passed; +} + +WRITE_LINE_MEMBER(gamate_protection_device::prot_w) +{ + logerror("write to protection %01x\n", state); + + if (m_inpos < 8) + { + m_inbyte |= state << (7 - m_inpos); + m_inpos++; + } + else + { + logerror("byte in was %c\n", m_inbyte); + + if (!m_has_failed) + { + if (m_inseq < 15) + { + if (m_inbyte == m_prot_string[m_inseq]) + { + logerror("OK\n"); + } + else + { + m_has_failed = 1; + } + } + } + + m_inpos = 0; + m_inbyte = 0; + + m_inseq++; + + if (!m_has_failed && m_inseq == 15) + { + m_inbyte = 0x47; + logerror("setting byte to output\n"); + m_passed_write = 1; + } + } +} + +READ_LINE_MEMBER(gamate_protection_device::prot_r) +{ + + if (m_passed_write) + { + int retval = (m_inbyte >> (7 - m_inpos)) & 1; + m_inpos++; + + logerror("read from protection %01x\n", retval); + + if (m_inpos == 8) + { + logerror("unlocking ROM\n"); + m_is_protection_passed = 1; + m_inpos = 0; + m_inbyte = 0; + } + + return retval; + } + else + { + logerror("read from protection when not ready\n"); + } + + return 0x0; +} diff --git a/src/devices/bus/gamate/gamate_protection.h b/src/devices/bus/gamate/gamate_protection.h new file mode 100644 index 00000000000..006307af344 --- /dev/null +++ b/src/devices/bus/gamate/gamate_protection.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#ifndef MAME_BUS_GAMATE_PROTECTION_H +#define MAME_BUS_GAMATE_PROTECTION_H + +#pragma once + +DECLARE_DEVICE_TYPE(GAMATE_PROT, gamate_protection_device) + +class gamate_protection_device : public device_t +{ +public: + // construction/destruction + gamate_protection_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + bool is_protection_passed(); + + DECLARE_WRITE_LINE_MEMBER( prot_w ); + DECLARE_READ_LINE_MEMBER( prot_r ); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + +private: + int m_is_protection_passed; + int m_has_failed; + int m_passed_write; + int m_inpos; + uint8_t m_inbyte; + uint8_t m_inseq; + + // this string is contained within the protection mapper, you must write it to unlock the cartridge + const uint8_t m_prot_string[15] = { 0x42, 0x49, 0x54, 0x20, 0x43, 0x4F, 0x52, 0x50, 0x4F, 0x52, 0x41, 0x54, 0x49, 0x4F, 0x4E }; // "BIT CORPORATION" +}; + +#endif // MAME_BUS_GAMATE_PROTECTION_H + diff --git a/src/devices/bus/gamate/rom.cpp b/src/devices/bus/gamate/rom.cpp new file mode 100644 index 00000000000..59a70b3a9a9 --- /dev/null +++ b/src/devices/bus/gamate/rom.cpp @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +// this assumes that the regular banked carts don't also have the 4-in-1 logic. + +#include "emu.h" +#include "rom.h" + +//------------------------------------------------- +// gamate_rom_device - constructor +//------------------------------------------------- + +DEFINE_DEVICE_TYPE(GAMATE_ROM_PLAIN, gamate_rom_plain_device, "gamate_rom_plain", "GAMATE Cartridge") +DEFINE_DEVICE_TYPE(GAMATE_ROM_BANKED, gamate_rom_banked_device, "gamate_rom_banked", "GAMATE Cartridge with banking") +DEFINE_DEVICE_TYPE(GAMATE_ROM_4IN1, gamate_rom_4in1_device, "gamate_rom_4in1", "GAMATE 4-in-1 Cartridge") + + +gamate_rom_plain_device::gamate_rom_plain_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, type, tag, owner, clock), device_gamate_cart_interface(mconfig, *this), + m_protection(*this, "protection") +{ +} + +gamate_rom_plain_device::gamate_rom_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + gamate_rom_plain_device(mconfig, GAMATE_ROM_PLAIN, tag, owner, clock) +{ +} + +gamate_rom_banked_device::gamate_rom_banked_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + gamate_rom_plain_device(mconfig, GAMATE_ROM_BANKED, tag, owner, clock), + m_bank(0) +{ +} + +gamate_rom_banked_device::gamate_rom_banked_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + gamate_rom_plain_device(mconfig, type, tag, owner, clock), + m_bank(0) +{ +} + + +gamate_rom_4in1_device::gamate_rom_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + gamate_rom_banked_device(mconfig, GAMATE_ROM_4IN1, tag, owner, clock), + m_multibank(0) +{ +} + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void gamate_rom_banked_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void gamate_rom_4in1_device::device_start() +{ + gamate_rom_banked_device::device_start(); + save_item(NAME(m_multibank)); +} + + +void gamate_rom_banked_device::device_reset() +{ + m_bank = 0; +} + +void gamate_rom_4in1_device::device_reset() +{ + gamate_rom_banked_device::device_reset(); + m_multibank = 0; +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + + +READ8_MEMBER(gamate_rom_plain_device::read_cart) +{ + if (m_protection->is_protection_passed()) + { + return read_rom(space, offset, mem_mask); + } + else + { + return m_protection->prot_r() << 1; + } + + return 0xff; +} + +READ8_MEMBER(gamate_rom_plain_device::read_rom) +{ + return m_rom[offset & (m_rom_size-1)]; +} + +READ8_MEMBER(gamate_rom_banked_device::read_rom) +{ + if (offset < 0x4000) + { + return m_rom[offset & (m_rom_size - 1)]; + } + else + { + return m_rom[((m_bank * 0x4000) + (offset & 0x3fff)) & (m_rom_size - 1)]; + } + + return 0xff; +} + +READ8_MEMBER(gamate_rom_4in1_device::read_rom) +{ + if (offset < 0x4000) + { + return m_rom[((m_multibank * 0x4000) + (offset & 0x3fff)) & (m_rom_size - 1)]; + } + else + { + return m_rom[((m_bank * 0x4000) + (offset & 0x3fff)) & (m_rom_size - 1)]; + } +} + +WRITE8_MEMBER(gamate_rom_plain_device::write_cart) +{ + if (m_protection->is_protection_passed()) + { + write_rom(space, offset, data, mem_mask); + } + else + { + m_protection->prot_w((data & 0x04) >> 2); + } +} + +WRITE8_MEMBER(gamate_rom_plain_device::write_rom) +{ + // shouldn't be any write on an unbanked game + logerror("gamate_rom_plain_device::write_rom %04x %02x\n", offset, data); +} + +WRITE8_MEMBER(gamate_rom_banked_device::write_rom) +{ + if (offset == 0x6000) + { + m_bank = data; + } + else + { + logerror("gamate_rom_banked_device::write_rom %04x %02x\n", offset, data); + } +} + +WRITE8_MEMBER(gamate_rom_4in1_device::write_rom) +{ + if (offset == 0x2000) + { + m_multibank = data; + } + else if (offset == 0x6000) + { + m_bank = data; + } + else + { + logerror("gamate_rom_4in1_device::write_rom %04x %02x\n", offset, data); + } +} + +MACHINE_CONFIG_MEMBER( gamate_rom_plain_device::device_add_mconfig ) + MCFG_DEVICE_ADD("protection", GAMATE_PROT, 0) +MACHINE_CONFIG_END + + +/*------------------------------------------------- + slot interface + -------------------------------------------------*/ + +SLOT_INTERFACE_START(gamate_cart) + SLOT_INTERFACE_INTERNAL("plain", GAMATE_ROM_PLAIN) + SLOT_INTERFACE_INTERNAL("banked", GAMATE_ROM_BANKED) + SLOT_INTERFACE_INTERNAL("4in1", GAMATE_ROM_4IN1) +SLOT_INTERFACE_END diff --git a/src/devices/bus/gamate/rom.h b/src/devices/bus/gamate/rom.h new file mode 100644 index 00000000000..1d500082e36 --- /dev/null +++ b/src/devices/bus/gamate/rom.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#ifndef MAME_BUS_GAMATE_ROM_H +#define MAME_BUS_GAMATE_ROM_H + +#pragma once + +#include "slot.h" +#include "gamate_protection.h" + +// ======================> gamate_rom_plain_device + +class gamate_rom_plain_device : public device_t, + public device_gamate_cart_interface +{ +public: + // construction/destruction + gamate_rom_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart) override; + virtual DECLARE_WRITE8_MEMBER(write_cart) override; + virtual READ8_MEMBER(read_rom); + virtual WRITE8_MEMBER(write_rom); + +protected: + gamate_rom_plain_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_add_mconfig(machine_config &config) override; + + // device-level overrides + virtual void device_start() override { } + virtual void device_reset() override { } + + optional_device m_protection; +}; + +// ======================> gamate_rom_banked_device + +class gamate_rom_banked_device : public gamate_rom_plain_device +{ +public: + // construction/destruction + gamate_rom_banked_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + gamate_rom_banked_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // reading and writing + virtual READ8_MEMBER(read_rom) override; + virtual WRITE8_MEMBER(write_rom) override; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + + int m_bank; +}; + + +// ======================> gamate_rom_4in1_device + +class gamate_rom_4in1_device : public gamate_rom_banked_device +{ +public: + // construction/destruction + gamate_rom_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // reading and writing + virtual READ8_MEMBER(read_rom) override; + virtual WRITE8_MEMBER(write_rom) override; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + +private: + int m_multibank; +}; + +// device type definition +DECLARE_DEVICE_TYPE(GAMATE_ROM_PLAIN, gamate_rom_plain_device) +DECLARE_DEVICE_TYPE(GAMATE_ROM_BANKED, gamate_rom_banked_device) +DECLARE_DEVICE_TYPE(GAMATE_ROM_4IN1, gamate_rom_4in1_device) + +#endif // MAME_BUS_GAMATE_ROM_H diff --git a/src/devices/bus/gamate/slot.cpp b/src/devices/bus/gamate/slot.cpp new file mode 100644 index 00000000000..a74b4569b6e --- /dev/null +++ b/src/devices/bus/gamate/slot.cpp @@ -0,0 +1,248 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +DEFINE_DEVICE_TYPE(GAMATE_CART_SLOT, gamate_cart_slot_device, "gamate_cart_slot", "Gamate Cartridge Slot") + +//************************************************************************** +// GAMATE cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_gamate_cart_interface - constructor +//------------------------------------------------- + +device_gamate_cart_interface::device_gamate_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(nullptr), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_gamate_cart_interface - destructor +//------------------------------------------------- + +device_gamate_cart_interface::~device_gamate_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_gamate_cart_interface::rom_alloc(uint32_t size, const char *tag) +{ + if (m_rom == nullptr) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(GAMATESLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_BIG)->base(); + m_rom_size = size; + } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// gamate_cart_slot_device - constructor +//------------------------------------------------- +gamate_cart_slot_device::gamate_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, GAMATE_CART_SLOT, tag, owner, clock), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(GAMATE_PLAIN), + m_cart(nullptr) +{ +} + +//------------------------------------------------- +// gamate_cart_slot_device - destructor +//------------------------------------------------- + +gamate_cart_slot_device::~gamate_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gamate_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// GAMATE PCB +//------------------------------------------------- + +struct gamate_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 gamate_slot slot_list[] = +{ + { GAMATE_PLAIN, "plain" }, + { GAMATE_BANKED, "banked" }, + { GAMATE_4IN1, "4in1" }, +}; + +static int gamate_get_pcb_id(const char *slot) +{ + for (auto & elem : slot_list) + { + if (!core_stricmp(elem.slot_option, slot)) + return elem.pcb_id; + } + + return 0; +} + +static const char *gamate_get_slot(int type) +{ + for (auto & elem : slot_list) + { + if (elem.pcb_id == type) + return elem.slot_option; + } + + return "plain"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +image_init_result gamate_cart_slot_device::call_load() +{ + if (m_cart) + { + uint8_t *ROM; + uint32_t len = !loaded_through_softlist() ? length() : get_software_region_length("rom"); + + if (len > 0x80000) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported cartridge size"); + return image_init_result::FAIL; + } + + m_cart->rom_alloc(len, tag()); + + ROM = m_cart->get_rom_base(); + + if (!loaded_through_softlist()) + fread(ROM, len); + else + memcpy(ROM, get_software_region("rom"), len); + + if (!loaded_through_softlist()) + { + // attempt to detect cart type without softlist assistance + m_type = get_cart_type(ROM, len); + } + else + { + // or for softlist loading, use the type specified + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = gamate_get_pcb_id(pcb_name); + } + + return image_init_result::PASS; + } + + return image_init_result::PASS; +} + + +/*------------------------------------------------- + get_cart_type - code to detect cart type from + fullpath + -------------------------------------------------*/ + +int gamate_cart_slot_device::get_cart_type(const uint8_t *ROM, uint32_t len) +{ + int type = GAMATE_PLAIN; + + switch (len) + { + case 0x4000: + case 0x8000: + type = GAMATE_PLAIN; + break; + + case 0x10000: + case 0x20000: + case 0x40000: + case 0x80000: + type = GAMATE_BANKED; + break; + } + + return type; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +std::string gamate_cart_slot_device::get_default_card_software(get_default_card_software_hook &hook) const +{ + if (hook.image_file()) + { + const char *slot_string; + uint32_t len = hook.image_file()->size(); + std::vector rom(len); + int type; + + hook.image_file()->read(&rom[0], len); + + type = get_cart_type(&rom[0], len); + slot_string = gamate_get_slot(type); + + //printf("type: %s\n", slot_string); + + return std::string(slot_string); + } + + return software_get_default_slot("plain"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(gamate_cart_slot_device::read_cart) +{ + if (m_cart) + { + return m_cart->read_cart(space, offset); + } + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(gamate_cart_slot_device::write_cart) +{ + if (m_cart) + { + m_cart->write_cart(space, offset, data); + } +} diff --git a/src/devices/bus/gamate/slot.h b/src/devices/bus/gamate/slot.h new file mode 100644 index 00000000000..802fdb360e3 --- /dev/null +++ b/src/devices/bus/gamate/slot.h @@ -0,0 +1,104 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#ifndef MAME_BUS_GAMATE_SLOT_H +#define MAME_BUS_GAMATE_SLOT_H + +#pragma once + +#include "softlist_dev.h" + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +/* PCB */ +enum +{ + GAMATE_PLAIN = 0, + GAMATE_BANKED, + GAMATE_4IN1, +}; + +// ======================> device_gamate_cart_interface + +class device_gamate_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + virtual ~device_gamate_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_cart) { } + + void rom_alloc(uint32_t size, const char *tag); + uint8_t* get_rom_base() { return m_rom; } + uint32_t get_rom_size() { return m_rom_size; } + +protected: + device_gamate_cart_interface(const machine_config &mconfig, device_t &device); + + // internal state + uint8_t *m_rom; + uint32_t m_rom_size; +}; + +// ======================> gamate_cart_slot_device + +class gamate_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + gamate_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + virtual ~gamate_cart_slot_device(); + + // image-level overrides + virtual image_init_result call_load() override; + virtual void call_unload() override {} + virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); } + + int get_type() { return m_type; } + static int get_cart_type(const uint8_t *ROM, uint32_t len); + + virtual iodevice_t image_type() const override { return IO_CARTSLOT; } + virtual bool is_readable() const override { return 1; } + virtual bool is_writeable() const override { return 0; } + virtual bool is_creatable() const override { return 0; } + virtual bool must_be_loaded() const override { return 0; } + virtual bool is_reset_on_load() const override { return 1; } + virtual const char *image_interface() const override { return "gamate_cart"; } + virtual const char *file_extensions() const override { return "bin"; } + + // slot interface overrides + virtual std::string get_default_card_software(get_default_card_software_hook &hook) const override; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + +protected: + // device-level overrides + virtual void device_start() override; + + int m_type; + device_gamate_cart_interface* m_cart; +}; + +// device type definition +DECLARE_DEVICE_TYPE(GAMATE_CART_SLOT, gamate_cart_slot_device) + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define GAMATESLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_GAMATE_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, GAMATE_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +SLOT_INTERFACE_EXTERN( gamate_cart ); + +#endif // MAME_BUS_GAMATE_SLOT_H -- cgit v1.2.3-70-g09d2