summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/fidel_clockdiv.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/fidel_clockdiv.cpp')
-rw-r--r--src/mame/machine/fidel_clockdiv.cpp115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/mame/machine/fidel_clockdiv.cpp b/src/mame/machine/fidel_clockdiv.cpp
new file mode 100644
index 00000000000..efbdbe9af4f
--- /dev/null
+++ b/src/mame/machine/fidel_clockdiv.cpp
@@ -0,0 +1,115 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/******************************************************************************
+
+Fidelity Electronics 6502 dynamic(offset-dependent) CPU clock divider base class.
+Used to compensate slow memory chips in chess computer models: SC12, AS12, PC, EAS, EAG.
+
+TODO:
+- improve clock divider? it seems a little bit slower than the real machine.
+ Currently, a dummy timer workaround is needed, or it's much worse.
+ Is the problem here due to timing of CPU addressbus changes? We can only 'sense'
+ the addressbus at read or write accesses.
+
+******************************************************************************/
+
+#include "emu.h"
+#include "machine/fidel_clockdiv.h"
+
+
+// machine start/reset
+
+void fidel_clockdiv_state::machine_start()
+{
+ // zerofill/register for savestates
+ m_div_config = 0;
+
+ save_item(NAME(m_div_status));
+ save_item(NAME(m_div_config));
+ save_item(NAME(m_div_scale));
+
+ // dummy timer for cpu divider
+ m_div_timer = machine().scheduler().timer_alloc(timer_expired_delegate(), this);
+}
+
+void fidel_clockdiv_state::machine_reset()
+{
+ div_refresh();
+}
+
+
+// input ports
+
+INPUT_PORTS_START( fidel_clockdiv_2 )
+ PORT_START("div_config") // hardwired, default to /2
+ PORT_CONFNAME( 0x03, 0x02, "CPU Divider" ) PORT_CHANGED_MEMBER(DEVICE_SELF, fidel_clockdiv_state, div_changed, nullptr)
+ PORT_CONFSETTING( 0x00, "Disabled" )
+ PORT_CONFSETTING( 0x02, "2" )
+ PORT_CONFSETTING( 0x03, "4" )
+INPUT_PORTS_END
+
+INPUT_PORTS_START( fidel_clockdiv_4 )
+ PORT_START("div_config") // hardwired, default to /4
+ PORT_CONFNAME( 0x03, 0x03, "CPU Divider" ) PORT_CHANGED_MEMBER(DEVICE_SELF, fidel_clockdiv_state, div_changed, nullptr)
+ PORT_CONFSETTING( 0x00, "Disabled" )
+ PORT_CONFSETTING( 0x02, "2" )
+ PORT_CONFSETTING( 0x03, "4" )
+INPUT_PORTS_END
+
+
+// implementation
+
+void fidel_clockdiv_state::div_set_cpu_freq(offs_t offset)
+{
+ if (offset != m_div_status)
+ {
+ // when a13/a14 is high, XTAL goes through divider(s)
+ // (depending on factory-set jumper, either one or two 7474)
+ m_maincpu->set_clock_scale(offset ? m_div_scale : 1.0);
+
+ m_div_status = offset;
+ }
+}
+
+void fidel_clockdiv_state::div_trampoline_w(offs_t offset, u8 data)
+{
+ if (m_div_config)
+ div_set_cpu_freq(offset & 0x6000);
+
+ m_mainmap->write8(offset, data);
+}
+
+u8 fidel_clockdiv_state::div_trampoline_r(offs_t offset)
+{
+ if (m_div_config && !machine().side_effects_disabled())
+ div_set_cpu_freq(offset & 0x6000);
+
+ return m_mainmap->read8(offset);
+}
+
+void fidel_clockdiv_state::div_trampoline(address_map &map)
+{
+ map(0x0000, 0xffff).rw(FUNC(fidel_clockdiv_state::div_trampoline_r), FUNC(fidel_clockdiv_state::div_trampoline_w));
+}
+
+void fidel_clockdiv_state::div_refresh(ioport_value val)
+{
+ if (val == 0xff)
+ {
+ // bail out if there is no cpu divider
+ ioport_port *inp = ioport("div_config");
+ if (inp == nullptr)
+ return;
+
+ val = inp->read();
+ }
+
+ m_maincpu->set_clock_scale(1.0);
+ m_div_status = ~0;
+ m_div_config = val;
+ m_div_scale = (m_div_config & 1) ? 0.25 : 0.5;
+
+ // stop high frequency background timer if cpu divider is disabled
+ attotime period = (val) ? attotime::from_hz(m_maincpu->clock()) : attotime::never;
+ m_div_timer->adjust(period, 0, period);
+}