diff options
Diffstat (limited to 'src/devices/machine/clock.cpp')
-rw-r--r-- | src/devices/machine/clock.cpp | 125 |
1 files changed, 105 insertions, 20 deletions
diff --git a/src/devices/machine/clock.cpp b/src/devices/machine/clock.cpp index 374dc8a16a8..670dfba09aa 100644 --- a/src/devices/machine/clock.cpp +++ b/src/devices/machine/clock.cpp @@ -1,46 +1,131 @@ // 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. + +*/ + #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(); - 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(FUNC(clock_device::clock_init), this); + m_timer_tick = timer_alloc(FUNC(clock_device::clock_tick), this); + reinit(); +} + +void clock_device::reinit() +{ + if (!m_timer_init) + return; + + // not using synchronize(), that may retrigger more than once + m_timer_init->adjust(attotime::zero); } -void clock_device::device_clock_changed() +void clock_device::output() { - if (!m_signal_handler.isnull() && m_clock > 0) + if (m_signal != m_output) { - if (m_timer == nullptr) - m_timer = timer_alloc(0); + m_output = m_signal; + m_signal_handler(m_output); + } +} - const attotime period(attotime::from_hz(m_clock * 2)); +TIMER_CALLBACK_MEMBER(clock_device::clock_init) +{ + attotime period = (m_clock > 0) ? attotime::from_hz(m_clock) : m_period; + assert(!period.is_zero()); - attotime next = period - m_timer->elapsed(); - if (next < attotime::zero) - next = attotime::zero; + if (period.is_never()) + { + m_timer_tick->adjust(attotime::never); + return; + } - m_timer->adjust(next, 0, period); + 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); + } } - else if (m_timer != nullptr) - m_timer->adjust(attotime::never); + + attotime next = m_signal ? m_thigh : m_tlow; + if (next < m_timer_tick->remaining()) + m_timer_tick->adjust(next); } -void clock_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(clock_device::clock_tick) { - m_signal = !m_signal; - m_signal_handler(m_signal); + 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(); } |