diff options
Diffstat (limited to 'src/devices/bus/ss50/mpt.cpp')
-rw-r--r-- | src/devices/bus/ss50/mpt.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/devices/bus/ss50/mpt.cpp b/src/devices/bus/ss50/mpt.cpp new file mode 100644 index 00000000000..70ce9d0e3fa --- /dev/null +++ b/src/devices/bus/ss50/mpt.cpp @@ -0,0 +1,199 @@ +// license:BSD-3-Clause +// copyright-holders:68bit +/********************************************************************** + + SWTPC MP-T Timer / counter + + MC6821 PIA + MK5009 timer/counter + +**********************************************************************/ + +#include "emu.h" +#include "mpt.h" +#include "machine/6821pia.h" +#include "machine/mc14411.h" + + +class ss50_mpt_device : public device_t, public ss50_card_interface +{ +public: + ss50_mpt_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, SS50_MPT, tag, owner, clock) + , ss50_card_interface(mconfig, *this) + , m_pia(*this, "pia") + , m_irqa_jumper(*this, "irqa") + , m_irqb_jumper(*this, "irqb") + { + } + +protected: + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + + virtual u8 register_read(offs_t offset) override; + virtual void register_write(offs_t offset, u8 data) override; + +private: + DECLARE_WRITE8_MEMBER(pia_b_w); + DECLARE_READ8_MEMBER(pia_cb1_r); + DECLARE_WRITE_LINE_MEMBER(pia_irq_b); + TIMER_CALLBACK_MEMBER(mpt_timer_callback); + DECLARE_WRITE_LINE_MEMBER(pia_irqa_w); + DECLARE_WRITE_LINE_MEMBER(pia_irqb_w); + + required_device<pia6821_device> m_pia; + required_ioport m_irqa_jumper; + required_ioport m_irqb_jumper; + + emu_timer *m_mpt_timer; + attotime m_mpt_duration; + uint8_t m_mpt_timer_state; +}; + + +static INPUT_PORTS_START( mpt ) + PORT_START("irqa") + PORT_DIPNAME(1, 0, "IRQ-A") + PORT_DIPSETTING(0, DEF_STR(Off)) + PORT_DIPSETTING(1, DEF_STR(On)) + + PORT_START("irqb") + PORT_DIPNAME(1, 1, "IRQ-B") + PORT_DIPSETTING(0, DEF_STR(Off)) + PORT_DIPSETTING(1, DEF_STR(On)) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor ss50_mpt_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(mpt); +} + + +//------------------------------------------------- +// device_add_mconfig - add device-specific +// machine configuration +//------------------------------------------------- + +void ss50_mpt_device::device_add_mconfig(machine_config &config) +{ + PIA6821(config, m_pia, 0); + m_pia->writepb_handler().set(FUNC(ss50_mpt_device::pia_b_w)); + m_pia->readcb1_handler().set(FUNC(ss50_mpt_device::pia_cb1_r)); + m_pia->irqa_handler().set(FUNC(ss50_mpt_device::pia_irqa_w)); + m_pia->irqb_handler().set(FUNC(ss50_mpt_device::pia_irqb_w)); +} + +void ss50_mpt_device::device_start() +{ + m_mpt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ss50_mpt_device::mpt_timer_callback),this)); + m_mpt_timer_state = 0; +} + +//------------------------------------------------- +// register_read - read from a port register +//------------------------------------------------- + +u8 ss50_mpt_device::register_read(offs_t offset) +{ + return m_pia->read(offset & 3); +} + +//------------------------------------------------- +// register_write - write to a port register +//------------------------------------------------- + +void ss50_mpt_device::register_write(offs_t offset, u8 data) +{ + m_pia->write(offset & 3, data); +} + + +WRITE8_MEMBER(ss50_mpt_device::pia_b_w) +{ + if (data & 0x80) + { + // Reset state. + m_mpt_timer->enable(false); + return; + } + + data &= 0x0f; + + if (data == 0x0c || data == 0x0d || data == 0x0f) + { + // No output for these input settings. + m_mpt_timer->enable(false); + return; + } + + if (data == 0x00) + { + // Hack: could not keep up with this 1us period + // anyway, and this is the initial state and it blocks + // progress, so just give up on this setting. + m_mpt_timer->enable(false); + return; + } + + attotime duration; + // Set the duration for half the period, the time that the next + // transition of state will occur. + switch (data & 0x0f) + { + case 0: duration = attotime::from_nsec(500); break; + case 1: duration = attotime::from_usec(5); break; + case 2: duration = attotime::from_usec(50); break; + case 3: duration = attotime::from_usec(500); break; + case 4: duration = attotime::from_msec(5); break; + case 5: duration = attotime::from_msec(50); break; + case 6: duration = attotime::from_msec(500); break; + case 7: duration = attotime::from_seconds(5); break; + case 8: duration = attotime::from_seconds(50); break; + case 9: duration = attotime::from_seconds(30); break; + case 10: duration = attotime::from_seconds(30 * 60); break; + case 11: duration = attotime::from_seconds(5 * 60); break; + case 14: duration = attotime::from_msec(10); break; + } + + if (duration != m_mpt_duration) + { + // TODO when would a change be latched? + m_mpt_timer->adjust(duration); + m_mpt_duration = duration; + } + m_mpt_timer->enable(true); +} + +READ8_MEMBER(ss50_mpt_device::pia_cb1_r) +{ + return m_mpt_timer_state; +} + +TIMER_CALLBACK_MEMBER(ss50_mpt_device::mpt_timer_callback) +{ + m_mpt_timer_state = !m_mpt_timer_state; + m_pia->cb1_w(m_mpt_timer_state); + m_mpt_timer->adjust(m_mpt_duration); + m_mpt_timer->enable(true); +} + +WRITE_LINE_MEMBER(ss50_mpt_device::pia_irqa_w) +{ + if (m_irqa_jumper->read()) + write_irq(state); +} + +WRITE_LINE_MEMBER(ss50_mpt_device::pia_irqb_w) +{ + if (m_irqb_jumper->read()) + write_irq(state); +} + + +// device type definition +DEFINE_DEVICE_TYPE_PRIVATE(SS50_MPT, ss50_card_interface, ss50_mpt_device, "ss50_mpt", "MP-T Timer / Counter") |