diff options
Diffstat (limited to 'src/devices/machine/ripple_counter.cpp')
-rw-r--r-- | src/devices/machine/ripple_counter.cpp | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/devices/machine/ripple_counter.cpp b/src/devices/machine/ripple_counter.cpp new file mode 100644 index 00000000000..ae38d342d68 --- /dev/null +++ b/src/devices/machine/ripple_counter.cpp @@ -0,0 +1,202 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + Generic binary ripple counter emulation + + This device emulates basic ripple counter logic ICs with falling- + edge clocks and a synchronous reset inputs such as CD4040 and + 74LS393. + + The optional 8-bit ROM interface is intended to help stream ROM + data to sound chips that lack memory interfaces of their own + (e.g. MSM5205, TMS5110). + +**********************************************************************/ + +#include "emu.h" +#include "machine/ripple_counter.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +DEFINE_DEVICE_TYPE(RIPPLE_COUNTER, ripple_counter_device, "ripple_counter", "Generic ripple counter") + + +//************************************************************************** +// RIPPLE COUNTER DEVICE +//************************************************************************** + +//------------------------------------------------- +// ripple_counter_device - constructor +//------------------------------------------------- + +ripple_counter_device::ripple_counter_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, RIPPLE_COUNTER, tag, owner, clock), + device_rom_interface(mconfig, *this, 0, ENDIANNESS_LITTLE, 8), + m_count_out_cb(*this), + m_rom_out_cb(*this), + m_count_timer(nullptr), + m_count_mask(0), + m_count(1), + m_clk(false), + m_reset(false) +{ +} + + +//------------------------------------------------- +// static_set_stages - configure the number of +// stages used to count +//------------------------------------------------- + +void ripple_counter_device::static_set_stages(device_t &device, u8 stages) +{ + auto &dev = downcast<ripple_counter_device &>(device); + dev.m_count_mask = (1U << stages) - 1; + dev.set_rom_addr_width(stages); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +device_memory_interface::space_config_vector ripple_counter_device::memory_space_config() const +{ + if (m_rom_out_cb.isnull()) + return space_config_vector(); + else + return device_rom_interface::memory_space_config(); +} + + +//------------------------------------------------- +// device_validity_check - validate a device after +// the configuration has been constructed +//------------------------------------------------- + +void ripple_counter_device::device_validity_check(validity_checker &valid) const +{ + if (m_count_mask == 0) + osd_printf_error("No counting stages configured\n"); +} + + +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void ripple_counter_device::device_resolve_objects() +{ + // resolve callbacks + m_count_out_cb.resolve_safe(); + m_rom_out_cb.resolve(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ripple_counter_device::device_start() +{ + // initialize timers + m_count_timer = timer_alloc(TIMER_COUNT); + + // register internal state + save_item(NAME(m_count)); + save_item(NAME(m_clk)); + save_item(NAME(m_reset)); +} + + +//------------------------------------------------- +// device_clock_changed - called when the +// device clock is altered in any way +//------------------------------------------------- + +void ripple_counter_device::device_clock_changed() +{ + attotime freq = m_reset ? attotime::never : clocks_to_attotime(1); + m_count_timer->adjust(freq, 0, freq); +} + + +//------------------------------------------------- +// rom_bank_updated - called when the ROM bank +// is changed +//------------------------------------------------- + +void ripple_counter_device::rom_bank_updated() +{ + m_rom_out_cb(read_byte(m_count)); +} + + +//------------------------------------------------- +// set_count - update the count and associated +// outputs +//------------------------------------------------- + +void ripple_counter_device::set_count(u32 count) +{ + m_count = count; + m_count_out_cb(count); + if (!m_rom_out_cb.isnull()) + m_rom_out_cb(read_byte(count)); +} + + +//------------------------------------------------- +// clock_w - handle falling-edge clock input +//------------------------------------------------- + +WRITE_LINE_MEMBER(ripple_counter_device::clock_w) +{ + if (m_clk != bool(state)) + { + m_clk = bool(state); + if (!state && !m_reset) + set_count((m_count + 1) & m_count_mask); + } +} + + +//------------------------------------------------- +// reset_w - handle active-high reset input +//------------------------------------------------- + +WRITE_LINE_MEMBER(ripple_counter_device::reset_w) +{ + if (m_reset != bool(state)) + { + m_reset = bool(state); + if (state && m_count != 0) + set_count(0); + + // stop or start the count timer as required + notify_clock_changed(); + } +} + + +//------------------------------------------------- +// device_timer - called whenever a device timer +// fires +//------------------------------------------------- + +void ripple_counter_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_COUNT: + set_count((m_count + 1) & m_count_mask); + break; + } +} |