Skip to content

Commit

Permalink
sinclair/specnext_divmmc.cpp: Added Spectrum Next DivMMC device emula…
Browse files Browse the repository at this point in the history
…tion. [holub]
  • Loading branch information
cuavas committed Apr 13, 2024
1 parent 8789ca6 commit 71b4db1
Show file tree
Hide file tree
Showing 2 changed files with 229 additions and 0 deletions.
140 changes: 140 additions & 0 deletions src/mame/sinclair/specnext_divmmc.cpp
Original file line number Diff line number Diff line change
@@ -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")
89 changes: 89 additions & 0 deletions src/mame/sinclair/specnext_divmmc.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 71b4db1

Please sign in to comment.