diff --git a/src/mame/sinclair/specnext_divmmc.cpp b/src/mame/sinclair/specnext_divmmc.cpp new file mode 100644 index 0000000000000..c3741877bb567 --- /dev/null +++ b/src/mame/sinclair/specnext_divmmc.cpp @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub +/********************************************************************** + Spectrum Next DivMMC +**********************************************************************/ + +#include "emu.h" +#include "specnext_divmmc.h" + + +specnext_divmmc_device::specnext_divmmc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, SPECNEXT_DIVMMC, tag, owner, clock) +{ +} + +bool specnext_divmmc_device::conmem() const noexcept +{ + return BIT(m_divmmc_reg, 7); +} + +bool specnext_divmmc_device::mapram() const noexcept +{ + return BIT(m_divmmc_reg, 6); +} + +bool specnext_divmmc_device::page0() const noexcept +{ + return m_cpu_a_15_13 == 0; +} + +bool specnext_divmmc_device::page1() const noexcept +{ + return m_cpu_a_15_13 == 1; +} + +bool specnext_divmmc_device::rom_en() const noexcept +{ + return page0() && (conmem() || automap()) && !mapram(); +} + +bool specnext_divmmc_device::ram_en() const noexcept +{ + return (page0() && (conmem() || automap()) && mapram()) || (page1() && (conmem() || automap())); +} + +u8 specnext_divmmc_device::ram_bank() const noexcept +{ + return page0() ? 3 : (m_divmmc_reg & 0x0f); +} + +bool specnext_divmmc_device::automap_nmi_instant_on() const noexcept +{ + return m_automap_nmi_instant_on && m_button_nmi; +} + +bool specnext_divmmc_device::automap_nmi_delayed_on() const noexcept +{ + return m_automap_nmi_delayed_on && m_button_nmi; +} + +bool specnext_divmmc_device::automap() const noexcept +{ + return !m_automap_reset && (m_automap_held + || (m_automap_active && (m_automap_instant_on || automap_nmi_instant_on())) + || (m_automap_rom3_active && m_automap_rom3_instant_on)); +} + +void specnext_divmmc_device::clock_w() noexcept +{ + // Rising edge + if (m_automap_reset || m_retn_seen) + m_button_nmi = 0; + else if (m_divmmc_button) + m_button_nmi = 1; + else if (m_automap_held) + m_button_nmi = 0; + + if (m_automap_reset || m_retn_seen) + { + m_automap_hold = 0; + } + else if (!m_cpu_mreq_n && !m_cpu_m1_n) + { + m_automap_hold = (m_automap_active && (m_automap_instant_on || m_automap_delayed_on || automap_nmi_instant_on() || automap_nmi_delayed_on())) + || (m_automap_rom3_active && (m_automap_rom3_instant_on || m_automap_rom3_delayed_on)) + || (m_automap_held && !(m_automap_active && m_automap_delayed_off)); + } + + if (m_automap_reset || m_retn_seen) + m_automap_held = 0; + else if (m_cpu_mreq_n) + m_automap_held = m_automap_hold; +} + + +void specnext_divmmc_device::device_start() +{ + save_item(NAME(m_cpu_a_15_13)); + save_item(NAME(m_cpu_mreq_n)); + save_item(NAME(m_cpu_m1_n)); + save_item(NAME(m_en)); + save_item(NAME(m_automap_reset)); + save_item(NAME(m_automap_active)); + save_item(NAME(m_automap_rom3_active)); + save_item(NAME(m_retn_seen)); + save_item(NAME(m_divmmc_button)); + save_item(NAME(m_divmmc_reg)); + save_item(NAME(m_automap_instant_on)); + save_item(NAME(m_automap_delayed_on)); + save_item(NAME(m_automap_delayed_off)); + save_item(NAME(m_automap_rom3_instant_on)); + save_item(NAME(m_automap_rom3_delayed_on)); + save_item(NAME(m_automap_nmi_instant_on)); + save_item(NAME(m_automap_nmi_delayed_on)); + save_item(NAME(m_button_nmi)); + save_item(NAME(m_automap_hold)); + save_item(NAME(m_automap_held)); +} + +void specnext_divmmc_device::device_reset() +{ + m_cpu_mreq_n = 0; + m_cpu_m1_n = 0; + + m_automap_instant_on = 0; + m_automap_delayed_on = 0; + m_automap_delayed_off = 0; + m_automap_rom3_instant_on = 0; + m_automap_rom3_delayed_on = 0; + m_automap_nmi_instant_on = 0; + m_automap_nmi_delayed_on = 0; + + m_automap_hold = 0; + m_automap_held = 0; + m_button_nmi = 0; +} + + +// device type definition +DEFINE_DEVICE_TYPE(SPECNEXT_DIVMMC, specnext_divmmc_device, "specnext_divmmc", "Spectrum Next DivMMC") diff --git a/src/mame/sinclair/specnext_divmmc.h b/src/mame/sinclair/specnext_divmmc.h new file mode 100644 index 0000000000000..27d6023e18879 --- /dev/null +++ b/src/mame/sinclair/specnext_divmmc.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub +#ifndef MAME_SINCLAIR_SPECNEXT_DIVMMC_H +#define MAME_SINCLAIR_SPECNEXT_DIVMMC_H + +#pragma once + +class specnext_divmmc_device : public device_t +{ +public: + specnext_divmmc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + void cpu_a_15_13_w(u8 data) { m_cpu_a_15_13 = data & 0x07; }; + void cpu_mreq_n_w(bool data) { m_cpu_mreq_n = data; } + void cpu_m1_n_w(bool data) { m_cpu_m1_n = data; } + void automap_active_w(bool data) { m_automap_active = data; } + void automap_rom3_active_w(bool data) { m_automap_rom3_active = data; } + + void en_w(bool data) { m_en = data; } + void automap_reset_w(bool data) { m_automap_reset = data; } + void retn_seen_w(bool data) { m_retn_seen = data; } + + void divmmc_button_w(bool data) { m_divmmc_button = data; } + void divmmc_reg_w(u8 data) { m_divmmc_reg = data; } + + void automap_instant_on_w(bool data) { m_automap_instant_on = data; } + void automap_delayed_on_w(bool data) { m_automap_delayed_on = data; } + void automap_delayed_off_w(bool data) { m_automap_delayed_off = data; } + void automap_rom3_instant_on_w(bool data) { m_automap_rom3_instant_on = data; } + void automap_rom3_delayed_on_w(bool data) { m_automap_rom3_delayed_on = data; } + void automap_nmi_instant_on_w(bool data) { m_automap_nmi_instant_on = data; } + void automap_nmi_delayed_on_w(bool data) { m_automap_nmi_delayed_on = data; } + + bool divmmc_rom_en_r() const { return rom_en() && m_en; } + bool divmmc_ram_en_r() const { return ram_en() && m_en; } + bool divmmc_rdonly_r() const { return page0() || (mapram() && ram_bank() == 3); } + u8 divmmc_ram_bank_r() const { return ram_bank() & 0x0f; } + + void clock_w() noexcept; // called on active clock edge + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +private: + // in + u8 m_cpu_a_15_13; + bool m_cpu_mreq_n; + bool m_cpu_m1_n; + + bool m_en; + bool m_automap_reset; + bool m_automap_active; + bool m_automap_rom3_active; + bool m_retn_seen; + + bool m_divmmc_button; + u8 m_divmmc_reg; + + bool m_automap_instant_on; + bool m_automap_delayed_on; + bool m_automap_delayed_off; + bool m_automap_rom3_instant_on; + bool m_automap_rom3_delayed_on; + bool m_automap_nmi_instant_on; + bool m_automap_nmi_delayed_on; + + // internal + bool m_button_nmi; + bool m_automap_hold; + bool m_automap_held; + + // signal + bool conmem() const noexcept; + bool mapram() const noexcept; + bool page0() const noexcept; + bool page1() const noexcept; + bool rom_en() const noexcept; + bool ram_en() const noexcept; + u8 ram_bank() const noexcept; + bool automap_nmi_instant_on() const noexcept; + bool automap_nmi_delayed_on() const noexcept; + bool automap() const noexcept; + +}; + +DECLARE_DEVICE_TYPE(SPECNEXT_DIVMMC, specnext_divmmc_device) + +#endif // MAME_SINCLAIR_SPECNEXT_DIVMMC_H