diff options
author | hap <happppp@users.noreply.github.com> | 2021-09-10 12:55:25 +0200 |
---|---|---|
committer | hap <happppp@users.noreply.github.com> | 2021-09-10 12:55:54 +0200 |
commit | c5ceada693d06346505467da3af16fc7707271ef (patch) | |
tree | d06c31dd6859a0e75ca798b1d879f3ac6c1e1317 /src/devices/machine | |
parent | 2811cda9c67963f7877cf6fe784ee548bf22a0c1 (diff) |
clock: add setters for period, duty cycle, pulse width
Diffstat (limited to 'src/devices/machine')
-rw-r--r-- | src/devices/machine/clock.cpp | 140 | ||||
-rw-r--r-- | src/devices/machine/clock.h | 36 |
2 files changed, 150 insertions, 26 deletions
diff --git a/src/devices/machine/clock.cpp b/src/devices/machine/clock.cpp index 374dc8a16a8..803e3d3a55f 100644 --- a/src/devices/machine/clock.cpp +++ b/src/devices/machine/clock.cpp @@ -1,46 +1,146 @@ // license:BSD-3-Clause -// copyright-holders:smf +// copyright-holders:smf, hap +/* + +Generic clock signal device + +Set the period either with device_t m_clock, or with set_period if it needs +to be more fine-tuned (m_clock has higher priority). + +The duty cycle can be changed with set_duty_cycle (default is 50%), or the +pulse width (active time) can be set directly with set_pulse_width. + +Output signal at machine start is right after falling edge. + +TODO: +- add one-shot trigger? eg. monostable 555 + +*/ + #include "emu.h" #include "clock.h" DEFINE_DEVICE_TYPE(CLOCK, clock_device, "clock", "Clock") -clock_device::clock_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, CLOCK, tag, owner, clock), +clock_device::clock_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + device_t(mconfig, CLOCK, tag, owner, clock), m_signal(0), - m_timer(nullptr), + m_output(-1), + m_duty(0.5), + m_period(attotime::never), + m_pw(attotime::never), + m_timer_init(nullptr), + m_timer_tick(nullptr), m_signal_handler(*this) { } void clock_device::device_start() { - m_signal_handler.resolve(); + m_signal_handler.resolve_safe(); save_item(NAME(m_signal)); + save_item(NAME(m_output)); + save_item(NAME(m_duty)); + save_item(NAME(m_period)); + save_item(NAME(m_pw)); + save_item(NAME(m_thigh)); + save_item(NAME(m_tlow)); + + m_timer_init = timer_alloc(TID_CLOCK_INIT); + m_timer_tick = timer_alloc(TID_CLOCK_TICK); + reinit(); } -void clock_device::device_clock_changed() +void clock_device::reinit() { - if (!m_signal_handler.isnull() && m_clock > 0) - { - if (m_timer == nullptr) - m_timer = timer_alloc(0); + if (!m_timer_init) + return; - const attotime period(attotime::from_hz(m_clock * 2)); - - attotime next = period - m_timer->elapsed(); - if (next < attotime::zero) - next = attotime::zero; + // not using synchronize(), that may retrigger more than once + m_timer_init->adjust(attotime::zero); +} - m_timer->adjust(next, 0, period); +void clock_device::output() +{ + if (m_signal != m_output) + { + m_output = m_signal; + m_signal_handler(m_output); } - else if (m_timer != nullptr) - m_timer->adjust(attotime::never); } void clock_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { - m_signal = !m_signal; - m_signal_handler(m_signal); + switch (id) + { + case TID_CLOCK_INIT: + { + attotime period = (m_clock > 0) ? attotime::from_hz(m_clock) : m_period; + assert(!period.is_zero()); + + if (period.is_never()) + { + m_timer_tick->adjust(attotime::never); + return; + } + + if (!m_pw.is_never()) + { + // set timing via pulse width + attotime pw = m_pw; + if (pw > period) + pw = period; + + m_thigh = pw; + m_tlow = period - pw; + } + else + { + // set timing via duty cycle + if (m_duty == 0.5) + { + m_thigh = period / 2; + m_tlow = m_thigh; + } + else if (m_duty == 0.0) + { + m_thigh = attotime::zero; + m_tlow = period; + } + else if (m_duty == 1.0) + { + m_thigh = period; + m_tlow = attotime::zero; + } + else + { + double p = period.as_double(); + m_thigh = attotime::from_double(m_duty * p); + m_tlow = attotime::from_double((1.0 - m_duty) * p); + } + } + + attotime next = m_signal ? m_thigh : m_tlow; + if (next < m_timer_tick->remaining()) + m_timer_tick->adjust(next); + + break; + } + + case TID_CLOCK_TICK: + if (m_thigh.is_zero()) + m_signal = 0; + else if (m_tlow.is_zero()) + m_signal = 1; + else + m_signal ^= 1; + + m_timer_tick->adjust(m_signal ? m_thigh : m_tlow); + output(); + break; + + default: + break; + } } diff --git a/src/devices/machine/clock.h b/src/devices/machine/clock.h index 4bf0bed47a0..7e2fe1925a6 100644 --- a/src/devices/machine/clock.h +++ b/src/devices/machine/clock.h @@ -1,27 +1,51 @@ // license:BSD-3-Clause -// copyright-holders:smf +// copyright-holders:smf, hap +/* + + Generic clock signal device + +*/ + #ifndef MAME_MACHINE_CLOCK_H #define MAME_MACHINE_CLOCK_H #pragma once - class clock_device : public device_t { public: + clock_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); + auto signal_handler() { return m_signal_handler.bind(); } - DECLARE_READ_LINE_MEMBER(signal_r) { return m_signal; } + auto &set_period(attotime period) { m_period = period; reinit(); return *this; } + auto &set_pulse_width(attotime pw) { assert(!pw.is_never()); m_pw = pw; reinit(); return *this; } + auto &set_duty_cycle(double duty) { assert(duty > 0.0 && duty < 1.0); m_duty = duty; m_pw = attotime::never; reinit(); return *this; } - clock_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + DECLARE_READ_LINE_MEMBER(signal_r) { return m_signal; } protected: virtual void device_start() override; + virtual void device_reset() override { output(); } virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - virtual void device_clock_changed() override; + virtual void device_clock_changed() override { reinit(); } private: + static constexpr device_timer_id TID_CLOCK_INIT = 0; + static constexpr device_timer_id TID_CLOCK_TICK = 1; + + void reinit(); + void output(); + int m_signal; - emu_timer *m_timer; + int m_output; + double m_duty; + attotime m_period; + attotime m_pw; + attotime m_thigh; + attotime m_tlow; + + emu_timer *m_timer_init; + emu_timer *m_timer_tick; devcb_write_line m_signal_handler; }; |