From 83d5618b34b2b0c07a93ff88784081635af55595 Mon Sep 17 00:00:00 2001 From: AJR Date: Fri, 22 Sep 2017 00:22:12 -0400 Subject: am9513: New device --- scripts/src/machine.lua | 12 + scripts/target/mame/arcade.lua | 1 + scripts/target/mame/mess.lua | 1 + src/devices/machine/am9513.cpp | 1318 ++++++++++++++++++++++++++++++++++++++++ src/devices/machine/am9513.h | 209 +++++++ src/mame/drivers/pm68k.cpp | 9 +- 6 files changed, 1546 insertions(+), 4 deletions(-) create mode 100644 src/devices/machine/am9513.cpp create mode 100644 src/devices/machine/am9513.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 0609734ae24..994a78739f2 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -583,6 +583,18 @@ if (MACHINES["AM53CF96"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/am9513.h,MACHINES["AM9513"] = true +--------------------------------------------------- + +if (MACHINES["AM9513"]~=null) then + files { + MAME_DIR .. "src/devices/machine/am9513.cpp", + MAME_DIR .. "src/devices/machine/am9513.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/am9517a.h,MACHINES["AM9517A"] = true diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 3971eca9b3f..4d503893a2c 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -390,6 +390,7 @@ MACHINES["ADC1213X"] = true MACHINES["AICARTC"] = true --MACHINES["AM2847"] = true MACHINES["AM53CF96"] = true +--MACHINES["AM9513"] = true MACHINES["AM9517A"] = true MACHINES["AMIGAFDC"] = true MACHINES["AT_KEYBC"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 8bdf4c09b37..34736df7456 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -379,6 +379,7 @@ MACHINES["ADC1213X"] = true MACHINES["AICARTC"] = true MACHINES["AM2847"] = true MACHINES["AM53CF96"] = true +MACHINES["AM9513"] = true MACHINES["AM9517A"] = true MACHINES["AMIGAFDC"] = true MACHINES["AT_KEYBC"] = true diff --git a/src/devices/machine/am9513.cpp b/src/devices/machine/am9513.cpp new file mode 100644 index 00000000000..1432c879ca9 --- /dev/null +++ b/src/devices/machine/am9513.cpp @@ -0,0 +1,1318 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + Am9513A/Am9513 System Timing Controller (STC) + + The Am9513 is a five-channel counter/timer circuit introduced by + AMD around 1980. (It was also sold as the AmZ8073, apparently due + to a licensing deal with Zilog.) Clock source, edge selection, + gating and retriggering are programmable for each channel. + + All internal counters are 16 bits wide (except the internal 4-bit + counter for the FOUT divider, which is not externally accessible). + The device defaults to an 8-bit external interface after being + powered on or a programmed master reset, but can be configured to + work more efficiently with an 16-bit data bus. + + There is no reset line, though the device does reset itself when + it powers on, and there is a "master reset" software command. + + For a full description of each counter mode, see the datasheet. + +**********************************************************************/ + +#include "emu.h" +#include "machine/am9513.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_MODE (1U << 1) +#define LOG_INPUT (1U << 2) +#define LOG_TC (1U << 3) +//#define VERBOSE (LOG_GENERAL | LOG_MODE | LOG_INPUT) + +#include "logmacro.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(AM9513, am9513_device, "am9513", "Am9513 STC") +DEFINE_DEVICE_TYPE(AM9513A, am9513a_device, "am9513a", "Am9513A STC") + + +//************************************************************************** +// DEVICE CONSTRUCTION AND INITIALIZATION +//************************************************************************** + +//------------------------------------------------- +// am9513_device - constructor +//------------------------------------------------- + +am9513_device::am9513_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, bool is_am9513a) + : device_t(mconfig, type, tag, owner, clock), + m_out_cb{{*this}, {*this}, {*this}, {*this}, {*this}}, + m_fout_cb(*this), + m_is_am9513a(is_am9513a) +{ +} + +am9513_device::am9513_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : am9513_device(mconfig, AM9513, tag, owner, clock, false) +{ +} + +am9513a_device::am9513a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : am9513_device(mconfig, AM9513A, tag, owner, clock, true) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void am9513_device::device_start() +{ + // Resolve callbacks + for (auto &cb : m_out_cb) + cb.resolve_safe(); + m_fout_cb.resolve(); + + // Power-on reset + m_dpr = 0x1f; + m_mmr = 0; + m_write_prefetch = true; + m_status = 0; + m_f = 0; + m_fout = true; + m_fout_counter = 16; + std::fill(std::begin(m_count), std::end(m_count), 0); + std::fill(std::begin(m_counter_load), std::end(m_counter_load), 0); + std::fill(std::begin(m_counter_hold), std::end(m_counter_hold), 0); + std::fill(std::begin(m_counter_mode), std::end(m_counter_mode), 0x0b00); + std::fill(std::begin(m_alarm), std::end(m_alarm), 0); + std::fill(std::begin(m_counter_armed), std::end(m_counter_armed), false); + std::fill(std::begin(m_counter_running), std::end(m_counter_running), false); + std::fill(std::begin(m_alternate_count), std::end(m_alternate_count), false); + std::fill(std::begin(m_src), std::end(m_src), true); + std::fill(std::begin(m_gate), std::end(m_gate), true); + std::fill(std::begin(m_gate_alt), std::end(m_gate_alt), true); + std::fill(std::begin(m_gate_active), std::end(m_gate_active), true); + std::fill(std::begin(m_tc), std::end(m_tc), false); + std::fill(std::begin(m_toggle), std::end(m_toggle), false); + + // Set up frequency timers + for (int f = 0; f < 5; f++) + { + m_freq_timer[f] = timer_alloc(TIMER_F1 + f); + m_freq_timer_selected[f] = (f == 0) ? (m_fout_cb.isnull() ? 0x1e : 0x1f) : 0; + m_freq_timer_cycle[f] = 0; + } + + // Save device state + save_item(NAME(m_dpr)); + save_item(NAME(m_mmr)); + save_item(NAME(m_status)); + save_item(NAME(m_write_prefetch)); + save_item(NAME(m_count)); + save_item(NAME(m_counter_load)); + save_item(NAME(m_counter_hold)); + save_item(NAME(m_counter_mode)); + save_item(NAME(m_alarm)); + save_item(NAME(m_counter_armed)); + save_item(NAME(m_counter_running)); + save_item(NAME(m_alternate_count)); + save_item(NAME(m_src)); + save_item(NAME(m_gate)); + save_item(NAME(m_gate_alt)); + save_item(NAME(m_gate_active)); + save_item(NAME(m_tc)); + save_item(NAME(m_toggle)); + save_item(NAME(m_f)); + save_item(NAME(m_freq_timer_selected)); + save_item(NAME(m_freq_timer_cycle)); + save_item(NAME(m_fout)); + save_item(NAME(m_fout_counter)); + + // Synchronize clearing of OUT n + machine().scheduler().synchronize(timer_expired_delegate(FUNC(am9513_device::clear_outputs), this)); +} + + +//------------------------------------------------- +// clear_outputs - output initial clear state +// (delayed until all devices have started) +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(am9513_device::clear_outputs) +{ + for (int c = 0; c < 5; c++) + m_out_cb[c](0); +} + + +//------------------------------------------------- +// master_reset - software-controlled reset +//------------------------------------------------- + +void am9513_device::master_reset() +{ + LOGMASKED(LOG_MODE, "Master reset\n"); + + // Clear master mode register to all zeroes + m_mmr = 0; + + // Enable prefetch for write + m_write_prefetch = true; + + // Clear TC state + std::fill(std::begin(m_tc), std::end(m_tc), false); + std::fill(std::begin(m_toggle), std::end(m_toggle), false); + + // Initialize counter mode registers + for (int c = 0; c < 5; c++) + set_counter_mode(c, 0x0b00); +} + + +//************************************************************************** +// FREQUENCY SCALER +//************************************************************************** + +//------------------------------------------------- +// init_freq_timer - set up one of the F1-F5 +// frequency timers +//------------------------------------------------- + +void am9513_device::init_freq_timer(int f) +{ + u32 scale = 1; + for (int n = 0; n < f; n++) + scale *= BIT(m_mmr, 15) ? 10 : 16; + + attotime freq = clocks_to_attotime(scale); + if (m_freq_timer_cycle[f] == 0) + m_freq_timer[f]->adjust(freq, 0, freq); + else + m_freq_timer[f]->adjust(freq / 2, 0, freq / 2); + m_freq_timer[f]->enable(m_freq_timer_selected[f] != 0); + + LOGMASKED(LOG_GENERAL, "F%d = %f Hz (%s cycle emulation)\n", f + 1, double(clock()) / scale, + m_freq_timer_selected[f] == 0 ? "no" : m_freq_timer_cycle[f] == 0 ? "partial" : "full"); +} + + +//------------------------------------------------- +// device_clock_changed - called when the +// device clock is altered in any way +//------------------------------------------------- + +void am9513_device::device_clock_changed() +{ + for (int f = 0; f < 5; f++) + init_freq_timer(f); +} + + +//------------------------------------------------- +// device_timer - called whenever a device timer +// fires +//------------------------------------------------- + +void am9513_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + assert(id >= TIMER_F1 && id <= TIMER_F5); + + int cycle = m_freq_timer_cycle[id - TIMER_F1] == 0 ? 2 : 1; + while (cycle-- > 0) + { + m_f ^= 1 << (id - TIMER_F1); + bool level = BIT(m_f, id - TIMER_F1); + + int source = id - TIMER_F1 + 11; + for (int c = 0; c < 5; c++) + { + if ((m_counter_mode[c] & 0x0f00) >> 8 == source && BIT(m_counter_mode[c], 12) == !level) + count_edge(c); + } + + // FOUT Source = Fn + if ((m_mmr & 0x00f0) >> 4 == source || ((m_mmr & 0x00f0) == 0 && id == TIMER_F1)) + fout_tick(); + } +} + + +//------------------------------------------------- +// select_freq_timer - keep track of which of the +// F1-F5 timers are actually in use +//------------------------------------------------- + +void am9513_device::select_freq_timer(int f, int c, bool selected, bool cycle) +{ + assert(f >= 0 && f < 5); + + if (selected) + m_freq_timer_selected[f] |= 1 << c; + else + m_freq_timer_selected[f] &= ~(1 << c); + + if (selected && cycle) + m_freq_timer_cycle[f] |= 1 << c; + else + m_freq_timer_cycle[f] &= ~(1 << c); + + init_freq_timer(f); +} + + +//************************************************************************** +// MASTER MODE SELECTION +//************************************************************************** + +//------------------------------------------------- +// set_master_mode - master mode control +//------------------------------------------------- + +void am9513_device::set_master_mode(u16 data) +{ + u16 old_mmr = m_mmr; + m_mmr = data; + + // Time-of-Day options (TODO: not implemented yet) + if ((m_mmr & 0x0003) != (old_mmr & 0x0003)) + { + switch (m_mmr & 0x0003) + { + case 0: LOGMASKED(LOG_MODE, "TOD Disabled\n"); break; + case 1: LOGMASKED(LOG_MODE, "TOD Enabled (/5 Input)\n"); break; + case 2: LOGMASKED(LOG_MODE, "TOD Enabled (/6 Input)\n"); break; + case 3: LOGMASKED(LOG_MODE, "TOD Enabled (/10 Input)\n"); break; + } + } + + // Comparator enable + if (BIT(m_mmr, 2) != BIT(old_mmr, 2)) + LOGMASKED(LOG_MODE, "Compare 1 %s\n", BIT(m_mmr, 2) ? "Enabled" : "Disabled"); + if (BIT(m_mmr, 3) != BIT(old_mmr, 3)) + LOGMASKED(LOG_MODE, "Compare 2 %s\n", BIT(m_mmr, 3) ? "Enabled" : "Disabled"); + + // FOUT Source/Divider selection + if ((m_mmr & 0x0ff0) != (old_mmr & 0x0ff0)) + { + int source = (m_mmr >> 4) & 15; + int divider = (m_mmr >> 8) & 15; + if (source == 0) + source = 11; + if (divider == 0) + divider = 16; + + int old_source = (old_mmr >> 4) & 15; + if (old_source == 0) + old_source = 11; + if (old_source >= 11 && old_source <= 15 && source != old_source) + select_freq_timer(old_source - 11, 0, false, false); + + if (source >= 11 && source <= 15) + { + LOGMASKED(LOG_MODE, "FOUT = F%d / %d\n", source - 10, divider); + select_freq_timer(source - 11, 0, !m_fout_cb.isnull(), BIT(divider, 0)); + } + else if (source >= 6 && source <= 10) + LOGMASKED(LOG_MODE, "FOUT = GATE %d / %d\n", source - 5, divider); + else + LOGMASKED(LOG_MODE, "FOUT = SRC %d / %d\n", source, divider); + } + + // MM12: FOUT gate control + if (BIT(m_mmr, 12) != BIT(old_mmr, 12)) + LOGMASKED(LOG_MODE, "FOUT: Gate %s\n", BIT(m_mmr, 12) ? "Off" : "On"); + + // MM13: Data bus width + if (BIT(m_mmr, 13) != BIT(old_mmr, 13)) + LOGMASKED(LOG_MODE, "Data Bus Width = %d-Bit\n", BIT(m_mmr, 13) ? 16 : 8); + + // MM14: Data pointer sequencing + if (BIT(m_mmr, 14) != BIT(old_mmr, 14)) + LOGMASKED(LOG_MODE, "%s Data Pointer Increment\n", BIT(m_mmr, 14) ? "Disable" : "Enable"); + + // MM15: Scaler ratio control + if (BIT(m_mmr, 15) != BIT(old_mmr, 15)) + { + LOGMASKED(LOG_MODE, "%s Frequency Division\n", BIT(m_mmr, 15) ? "BCD" : "Binary"); + for (int f = 1; f < 5; f++) + init_freq_timer(f); + } +} + + +//************************************************************************** +// COUNTER CONTROL +//************************************************************************** + +//------------------------------------------------- +// counter_is_mode_x - return true if the counter +// is configured for the special Mode X +//------------------------------------------------- + +bool am9513_device::counter_is_mode_x(int c) const +{ + // Am9513A only: CM7-CM5 = 1, CM15-CM13 = EDGE + return m_is_am9513a && (m_counter_mode[c] & 0xc0e0) == 0xc0e0; +} + + +//------------------------------------------------- +// set_counter_mode - handle counter mode changes +//------------------------------------------------- + +void am9513_device::set_counter_mode(int c, u16 data) +{ + if ((data & 0xe0e0) != (m_counter_mode[c] & 0xe0e0)) + { + // Mode selection and gating control + int mode = ((data >> 5) & 7) * 3; + if ((data & 0xc000) == 0xc000) + mode += 2; // Edge gating + else if ((data & 0xe000) != 0) + mode += 1; // Level gating + LOGMASKED(LOG_MODE, "Counter %d: Mode %c selected\n", c + 1, mode + 'A'); + } + + if ((data & 0x1f00) != (m_counter_mode[c] & 0x1f00)) + { + // Source selection and edge control + int source = (data >> 8) & 15; + int old_source = (m_counter_mode[c] >> 8) & 15; + if (old_source >= 11 && old_source <= 15 && source != old_source) + select_freq_timer(old_source - 11, c + 1, false, false); + if (source >= 11 && source <= 15) + { + select_freq_timer(source - 11, c + 1, true, BIT(data, 12)); + LOGMASKED(LOG_MODE, "Counter %d: Count on %s edge of F%d\n", c + 1, BIT(data, 12) ? "falling" : "rising", source - 10); + } + else if (source >= 6 && source <= 10) + LOGMASKED(LOG_MODE, "Counter %d: Count on %s edge of GATE %d\n", c + 1, BIT(data, 12) ? "falling" : "rising", source - 5); + else if (source == 0) + LOGMASKED(LOG_MODE, "Counter %d: Count on %s edge of TC%d\n", c + 1, BIT(data, 12) ? "falling" : "rising", c - 1); + else + LOGMASKED(LOG_MODE, "Counter %d: Count on %s edge of SRC %d\n", c + 1, BIT(data, 12) ? "falling" : "rising", source); + } + + if ((data & 0x0018) != (m_counter_mode[c] & 0x0018)) + LOGMASKED(LOG_MODE, "Counter %d: %s %s count\n", c + 1, BIT(data, 4) ? "BCD" : "Binary", BIT(data, 3) ? "up" : "down"); + + // Output forms + if ((data & 0x0007) != (m_counter_mode[c] & 0x0007)) + { + switch (data & 0x0007) + { + case 0x0000: + LOGMASKED(LOG_MODE, "Counter %d: Output low (inactive)\n", c + 1); + set_output(c, false); + break; + + case 0x0004: + LOGMASKED(LOG_MODE, "Counter %d: Output high impedance (inactive)\n", c + 1); + break; + + case 0x0001: + if (c < 2 && BIT(m_mmr, c + 2)) + set_output(c, m_count[c] == m_alarm[c]); + else + { + LOGMASKED(LOG_MODE, "Counter %d: Output active high TC pulse\n", c + 1); + set_output(c, m_tc[c]); + } + break; + + case 0x0005: + if (c < 2 && BIT(m_mmr, c + 2)) + set_output(c, m_count[c] != m_alarm[c]); + else + { + LOGMASKED(LOG_MODE, "Counter %d: Output active low TC pulse\n", c + 1); + set_output(c, !m_tc[c]); + } + break; + + case 0x0002: + if (c < 2 && BIT(m_mmr, c + 2)) + set_output(c, m_count[c] == m_alarm[c]); + else + { + LOGMASKED(LOG_MODE, "Counter %d: Output toggle on TC\n", c + 1); + set_output(c, m_toggle[c]); + } + break; + + default: + LOGMASKED(LOG_MODE, "Counter %d: Output mode %d (illegal)\n", c + 1, data & 0x0007); + break; + } + } + + m_counter_mode[c] = data; +} + + +//------------------------------------------------- +// arm_counter - arm a particular counter +//------------------------------------------------- + +void am9513_device::arm_counter(int c) +{ + if (!m_counter_armed[c]) + { + LOGMASKED(LOG_GENERAL, "Counter %d: Arming counter\n", c + 1); + m_counter_armed[c] = true; + + // Count starts upon first active gate edge after arming in Modes C, F, I, L, O, R, X + m_counter_running[c] = (m_counter_mode[c] & 0xc000) != 0xc000; + } + m_alternate_count[c] = false; +} + + +//------------------------------------------------- +// disarm_counter - disarm a particular counter +//------------------------------------------------- + +void am9513_device::disarm_counter(int c) +{ + if (m_counter_armed[c]) + { + LOGMASKED(LOG_GENERAL, "Counter %d: Disarming counter\n", c + 1); + m_counter_armed[c] = false; + m_counter_running[c] = false; + } +} + + +//------------------------------------------------- +// save_counter - capture the current count +//------------------------------------------------- + +void am9513_device::save_counter(int c) +{ + m_counter_hold[c] = m_count[c]; + LOGMASKED(LOG_GENERAL, "Counter %d: Count %u saved\n", c + 1, m_count[c]); +} + + +//************************************************************************** +// OUTPUT CONTROL +//************************************************************************** + + +//------------------------------------------------- +// set_output - set one of the 5 main outputs +//------------------------------------------------- + +void am9513_device::set_output(int c, bool state) +{ + // SR1-SR5 track the output state + if (BIT(m_status, c + 1) == state) + return; + + if (state) + m_status |= 1 << (c + 1); + else + m_status &= ~(1 << (c + 1)); + m_out_cb[c](state); +} + + +//------------------------------------------------- +// set_toggle - output level control for TC +// toggle mode +//------------------------------------------------- + +void am9513_device::set_toggle(int c, bool state) +{ + m_toggle[c] = state; + if ((m_counter_mode[c] & 0x0007) == 0x0002) + set_output(c, state); +} + + +//------------------------------------------------- +// set_tc - register terminal count status +//------------------------------------------------- + +void am9513_device::set_tc(int c, bool state) +{ + m_tc[c] = state; + + // TC output is disabled when comparator is enabled + if (c >= 2 || !BIT(m_mmr, 2 + c)) + { + switch (m_counter_mode[c] & 0x0007) + { + case 0x0001: + // Active high TC pulse + set_output(c, state); + break; + case 0x0002: + // TC toggled output + if (!state) + set_toggle(c, !m_toggle[c]); + break; + case 0x0005: + // Active low TC pulse + set_output(c, !state); + break; + } + } + + if (c < 4) + { + // TC cascading + if ((m_counter_mode[c + 1] & 0x1f00) == (state ? 0x0000 : 0x1000)) + count_edge(c + 1); + + // TC gating + if ((m_counter_mode[c + 1] & 0xe000) == 0x2000) + gate_count(c + 1, state && (bus_is_16_bit() || m_gate_alt[c + 1])); + } +} + + +//************************************************************************** +// SOURCE INPUTS +//************************************************************************** + +//------------------------------------------------- +// write_source - register state changes on SRC +// input lines +//------------------------------------------------- + +void am9513_device::write_source(int s, bool level) +{ + if (level == m_src[s]) + return; + + m_src[s] = level; + LOGMASKED(LOG_INPUT, "Source %d: %s edge\n", s, level ? "Rising" : "Falling"); + + for (int c = 0; c < 5; c++) + { + if ((m_counter_mode[c] & 0x0f00) >> 8 == (s + 1) && BIT(m_counter_mode[c], 12) == !level) + count_edge(c); + } + + // FOUT Source = SRC n + if ((m_mmr & 0x00f0) >> 4 == (s + 1)) + fout_tick(); +} + + +//************************************************************************** +// COUNTER OPERATION +//************************************************************************** + +//------------------------------------------------- +// count_edge - gate and count active edges +//------------------------------------------------- + +void am9513_device::count_edge(int c) +{ + // Counting cannot be disabled or gated during TC + if (!m_tc[c]) + { + if (!m_counter_running[c]) + return; + + if (!m_gate_active[c]) + { + // Modes B, E, H, K, N & Q: Count only during active gate level + int gating = (m_counter_mode[c] >> 13) & 7; + if (gating >= 1 && gating <= 5) + return; + } + } + + step_counter(c, false); +} + + +//------------------------------------------------- +// reload_from_hold - return true if the current +// reload source of the counter is the hold +// register rather than the load register +//------------------------------------------------- + +bool am9513_device::reload_from_hold(int c) const +{ + if (counter_is_mode_x(c)) + return false; + + // Modes S & V: Reload from hold register when gate is high + else if ((m_counter_mode[c] & 0x00c0) == 0x00c0) + return m_gate_active[c]; + + // Modes G, H, I, J, K & L: Alternating reload + else if ((m_counter_mode[c] & 0x00c0) == 0x0040) + return m_alternate_count[c]; + + else + return false; +} + + +//------------------------------------------------- +// step_counter - advance the counter by one step +// and/or reload it from the specified register +// N.B. The "load counter" command works by +// causing an internal step and so can affect TC +//------------------------------------------------- + +void am9513_device::step_counter(int c, bool force_load) +{ + if (BIT(m_counter_mode[c], 3)) + { + // CM3 = 1: Count up + ++m_count[c]; + + // CM4 = 1: BCD adjustment + if (BIT(m_counter_mode[c], 4)) + { + if ((m_count[c] & 0x000f) >= 0x000a) + m_count[c] += 0x0006; + if ((m_count[c] & 0x00f0) >= 0x00a0) + m_count[c] += 0x0060; + if ((m_count[c] & 0x0f00) >= 0x0a00) + m_count[c] += 0x0600; + if ((m_count[c] & 0xf000) >= 0xa000) + m_count[c] += 0x6000; + } + } + else + { + // CM3 = 0: Count down + --m_count[c]; + + // CM4 = 1: BCD adjustment + if (BIT(m_counter_mode[c], 4)) + { + if ((m_count[c] & 0x000f) >= 0x000a) + m_count[c] -= 0x0006; + if ((m_count[c] & 0x00f0) >= 0x00a0) + m_count[c] -= 0x0060; + if ((m_count[c] & 0x0f00) >= 0x0a00) + m_count[c] -= 0x0600; + if ((m_count[c] & 0xf000) >= 0xa000) + m_count[c] -= 0x6000; + } + } + + if (m_count[c] == 0) + { + LOGMASKED(LOG_TC, "Counter %d: Terminal count\n", c + 1); + set_tc(c, true); + m_count[c] = reload_from_hold(c) ? m_counter_hold[c] : m_counter_load[c]; + m_alternate_count[c] = !m_alternate_count[c]; + + // Modes A, B, C, N & O: disarm counter after counting to TC once + if ((m_counter_mode[c] & 0x0060) == 0x0000) + disarm_counter(c); + + // Modes G, H, I & S: disarm counter after counting to TC twice + if ((m_counter_mode[c] & 0x0060) == 0x0040 && !m_alternate_count[c]) + disarm_counter(c); + + // Modes C, F, O, R & X: retriggering required after first TC + // Modes I & L: retriggering required after second TC + if ((m_counter_mode[c] & 0xc000) == 0xc000 && ((m_counter_mode[c] & 0x00c0) != 0x0040 || !m_alternate_count[c])) + m_counter_running[c] = false; + } + else if (m_tc[c]) + { + set_tc(c, false); + if (force_load) + m_count[c] = reload_from_hold(c) ? m_counter_hold[c] : m_counter_load[c]; + } + + if (force_load) + LOGMASKED(LOG_GENERAL, "Counter %d: %u loaded\n", c + 1, m_count[c]); + + // Active comparators + if (c < 2 && BIT(m_mmr, c + 2)) + { + if (BIT(m_counter_mode[c], 2)) + set_output(c, m_count[c] == m_alarm[c]); + else + set_output(c, m_count[c] != m_alarm[c]); + } +} + + +//************************************************************************** +// HARDWARE GATING +//************************************************************************** + +//------------------------------------------------- +// gate_count - track active gate state for each +// counter +//------------------------------------------------- + +void am9513_device::gate_count(int c, bool state) +{ + // Active low gating when CM15 = CM13 = 1 + if ((m_counter_mode[c] & 0xa000) == 0xa000) + state = !state; + + if (m_gate_active[c] == state) + return; + + m_gate_active[c] = state; + LOGMASKED(LOG_INPUT, "Counter %d: Gate %sactive\n", c + 1, state ? "" : "in"); + + // Active gate edge handling for armed counters + if (state && m_counter_armed[c]) + { + // Mode X: transfer counter into Hold register but continue counting + if (counter_is_mode_x(c)) + m_counter_hold[c] = m_count[c]; + + // Modes N, O, Q, R: hardware retriggering + if ((m_counter_mode[c] & 0x00c0) == 0x0080) + { + m_counter_hold[c] = m_count[c]; + m_count[c] = m_counter_load[c]; + } + + // Modes C, F, I, L, O, R, X: start count on active gate edge + if ((m_counter_mode[c] & 0xc000) == 0xc000) + m_counter_running[c] = true; + } +} + + +//------------------------------------------------- +// write_gate - register state changes on the +// GATE n inputs +//------------------------------------------------- + +void am9513_device::write_gate(int g, bool level) +{ + if (level == m_gate[g]) + return; + + m_gate[g] = level; + + for (int c = 0; c < 5; c++) + { + if ((m_counter_mode[c] & 0x0f00) >> 8 == (g + 6) && BIT(m_counter_mode[c], 12) == !level) + count_edge(c); + } + + if (BIT(m_counter_mode[g], 15)) + gate_count(g, level && (bus_is_16_bit() || m_gate_alt[g])); + if (g > 0 && (m_counter_mode[g - 1] & 0xe000) == 0x4000) + gate_count(g - 1, level && (bus_is_16_bit() || m_gate_alt[g - 1])); + if (g < 4 && (m_counter_mode[g + 1] & 0xe000) == 0x6000) + gate_count(g + 1, level && (bus_is_16_bit() || m_gate_alt[g + 1])); + + // FOUT Source = GATE n + if ((m_mmr & 0x00f0) >> 4 == (g + 6)) + fout_tick(); +} + + +//------------------------------------------------- +// write_gate_alt - register state on GATE nA +// inputs (only available in 8-bit mode) +//------------------------------------------------- + +void am9513_device::write_gate_alt(int c, bool level) +{ + if (bus_is_16_bit()) + { + logerror("Gate %dA written when configured as DB%d\n", c + 1, c + 8); + return; + } + + m_gate_alt[c] = level; + + switch (m_counter_mode[c] & 0xe000) + { + case 0x2000: + if (c > 0) + gate_count(c, level && m_tc[c - 1]); + break; + + case 0x4000: + if (c < 4) + gate_count(c + 1, level && m_gate[c + 1]); + break; + + case 0x6000: + if (c > 0) + gate_count(c - 1, level && m_gate[c - 1]); + break; + + case 0x8000: + case 0xa000: + case 0xc000: + case 0xe000: + gate_count(c, level && m_gate[c]); + break; + } +} + + +//************************************************************************** +// DATA PORT MUX +//************************************************************************** + +//------------------------------------------------- +// describe_register - diagnostic helper +//------------------------------------------------- + +std::string am9513_device::describe_register() const +{ + switch (m_dpr) + { + case 0x17: + return std::string("Master Mode"); + case 0x1f: + return std::string("Status"); + case 0x07: + case 0x0f: + return string_format("Counter %d Alarm", BIT(m_dpr, 3) ? 2 : 1); + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + return string_format("Counter %d Mode", m_dpr & 7); + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + return string_format("Counter %d Load", m_dpr & 7); + case 0x11: case 0x19: + case 0x12: case 0x1a: + case 0x13: case 0x1b: + case 0x14: case 0x1c: + case 0x15: case 0x1d: + return string_format("Counter %d Hold", m_dpr & 7); + default: + return string_format("Illegal %02X", m_dpr); + } +} + + +//------------------------------------------------- +// internal_read - read from register selected by +// the data pointer +//------------------------------------------------- + +u16 am9513_device::internal_read() const +{ + switch (m_dpr) + { + case 0x17: // Master mode register + return m_mmr; + case 0x1f: // Status register + return m_status | 0xff00; + case 0x07: // Alarm 1 register + case 0x0f: // Alarm 2 register + return m_alarm[BIT(m_dpr, 3)]; + case 0x01: // Counter 1 mode register + case 0x02: // Counter 2 mode register + case 0x03: // Counter 3 mode register + case 0x04: // Counter 4 mode register + case 0x05: // Counter 5 mode register + return m_counter_mode[(m_dpr & 7) - 1]; + case 0x09: // Counter 1 load register + case 0x0a: // Counter 2 load register + case 0x0b: // Counter 3 load register + case 0x0c: // Counter 4 load register + case 0x0d: // Counter 5 load register + return m_counter_load[(m_dpr & 7) - 1]; + case 0x11: case 0x19: // Counter 1 hold register + case 0x12: case 0x1a: // Counter 2 hold register + case 0x13: case 0x1b: // Counter 3 hold register + case 0x14: case 0x1c: // Counter 4 hold register + case 0x15: case 0x1d: // Counter 5 hold register + return m_counter_hold[(m_dpr & 7) - 1]; + default: // Invalid register + return 0xffff; + } +} + + +//------------------------------------------------- +// internal_read - write to register selected by +// the data pointer +//------------------------------------------------- + +void am9513_device::internal_write(u16 data) +{ + switch (m_dpr) + { + case 0x17: // Master mode register + set_master_mode(data); + break; + case 0x1f: // Status register (read only?) + logerror("Writing %04X to status register\n", data); + break; + case 0x07: // Alarm 1 register + case 0x0f: // Alarm 2 register + LOGMASKED(LOG_GENERAL, "Counter %d: Alarm = %u\n", BIT(m_dpr, 3) ? 2 : 1, data); + m_alarm[BIT(m_dpr, 3)] = data; + break; + case 0x01: // Counter 1 mode register + case 0x02: // Counter 2 mode register + case 0x03: // Counter 3 mode register + case 0x04: // Counter 4 mode register + case 0x05: // Counter 5 mode register + LOGMASKED(LOG_GENERAL, "Counter %d: Mode = %04X\n", m_dpr & 7, data); + set_counter_mode((m_dpr & 7) - 1, data); + break; + case 0x09: // Counter 1 load register + case 0x0a: // Counter 2 load register + case 0x0b: // Counter 3 load register + case 0x0c: // Counter 4 load register + case 0x0d: // Counter 5 load register + LOGMASKED(LOG_GENERAL, "Counter %d: Load = %u\n", m_dpr & 7, data); + m_counter_load[(m_dpr & 7) - 1] = data; + break; + case 0x11: case 0x19: // Counter 1 hold register + case 0x12: case 0x1a: // Counter 2 hold register + case 0x13: case 0x1b: // Counter 3 hold register + case 0x14: case 0x1c: // Counter 4 hold register + case 0x15: case 0x1d: // Counter 5 hold register + LOGMASKED(LOG_GENERAL, "Counter %d: Hold = %u\n", m_dpr & 7, data); + m_counter_hold[(m_dpr & 7) - 1] = data; + break; + default: // Invalid register + logerror("Writing %04X to register %02X\n", data, m_dpr); + break; + } +} + + +//************************************************************************** +// PREFETCH LATCH +//************************************************************************** + +//------------------------------------------------- +// advance_dpr - advance the data pointer through +// one of four cycles after a data read or write +//------------------------------------------------- + +void am9513_device::advance_dpr() +{ + if (BIT(m_mmr, 14) || machine().side_effect_disabled()) + return; + + if (bus_is_16_bit() || !BIT(m_status, 0)) + { + // Least significant byte (or 16-bit word) transferred next + m_status |= 0x01; + } + else + { + // Most significant byte transferred next + m_status &= 0xfe; + return; + } + + // Cycle within group + switch (m_dpr & 0x18) + { + case 0x00: // Mode/Alarm 1 -> Load/Alarm 2 + case 0x08: // Load/Alarm 2 -> Hold/Master Mode + m_dpr += 0x08; + return; + case 0x10: // Hold/Master Mode -> Mode (next counter)/Alarm 1 + m_dpr -= 0x10; + break; + case 0x18: + break; + } + + // Cycle through groups + switch (m_dpr & 0x07) + { + case 0x05: // Counter 5 -> Counter 1 + m_dpr -= 0x04; + break; + case 0x07: // In control group/status cycle + break; + default: + m_dpr += 0x01; + break; + } +} + + +//************************************************************************** +// CONTROL PORT +//************************************************************************** + +//------------------------------------------------- +// command_write - decode writes to control +// register +//------------------------------------------------- + +void am9513_device::command_write(u8 data) +{ + switch (data & 0xe0) + { + case 0x00: + if ((data & 0x07) == 0x00 || (data & 0x07) == 0x06) + { + logerror("Invalid register selected: %02X\n", data); + break; + } + + // Load data pointer + m_dpr = data; + + // Automatic prefetch + m_status |= 0x01; + break; + + case 0x20: // Arm + case 0x40: // Load + case 0x60: // Load and Arm + for (int c = 0; c < 5; c++) + { + if (BIT(data, c)) + { + if (BIT(data, 6)) + step_counter(c, true); + if (BIT(data, 5)) + arm_counter(c); + } + } + break; + + case 0x80: // Disarm and Save + case 0xa0: // Save + case 0xc0: // Disarm + for (int c = 0; c < 5; c++) + { + if (BIT(data, c)) + { + if (!BIT(data, 5)) + disarm_counter(c); + if (!BIT(data, 6)) + save_counter(c); + } + } + break; + + default: + switch (data) + { + case 0xe0: case 0xe8: // Clear/set MM14 (Enable/Disable data pointer sequencing) + LOGMASKED(LOG_MODE, "%s Data Pointer Increment\n", BIT(data, 3) ? "Disable" : "Enable"); + m_mmr = ((m_mmr & ~(1 << 14)) | BIT(data, 3) << 14); + break; + case 0xe1: case 0xe9: // Clear/set toggle out for counter 1 + case 0xe2: case 0xea: // Clear/set toggle out for counter 2 + case 0xe3: case 0xeb: // Clear/set toggle out for counter 3 + case 0xe4: case 0xec: // Clear/set toggle out for counter 4 + case 0xe5: case 0xed: // Clear/set toggle out for counter 5 + set_toggle((data & 7) - 1, BIT(data, 3)); + break; + case 0xe6: case 0xee: // Clear/set MM12 (FOUT gate on/FOUT gate off) + LOGMASKED(LOG_MODE, "FOUT: Gate %s\n", BIT(data, 3) ? "Off" : "On"); + m_mmr = ((m_mmr & ~(1 << 12)) | BIT(data, 3) << 12); + break; + case 0xe7: case 0xef: // Clear/set MM13 (8-bit bus/16-bit bus) + m_mmr = ((m_mmr & ~(1 << 13)) | BIT(data, 3) << 13); + break; + case 0xf1: // Step counter 1 + case 0xf2: // Step counter 2 + case 0xf3: // Step counter 3 + case 0xf4: // Step counter 4 + case 0xf5: // Step counter 5 + step_counter((data & 7) - 1, false); + break; + case 0xff: // Master reset + master_reset(); + break; + case 0xf8: case 0xf9: // Enable/disable prefetch for write (Am9513A only) + if (m_is_am9513a) + { + LOGMASKED(LOG_MODE, "Prefetch %s for write operations\n", BIT(data, 0) ? "disabled" : "enabled"); + m_write_prefetch = !BIT(data, 0); + break; + } + // else fall through + default: + logerror("Invalid command: %02X\n", data); + break; + } + break; + } +} + + +//------------------------------------------------- +// status_read - return the status register +//------------------------------------------------- + +u8 am9513_device::status_read() const +{ + return m_status; +} + + +//************************************************************************** +// DATA BUS MUX +//************************************************************************** + +//------------------------------------------------- +// bus_is_16_bit - determine whether or not the +// device is configured for a 16-bit bus +//------------------------------------------------- + +bool am9513_device::bus_is_16_bit() const +{ + return BIT(m_mmr, 13); +} + + +//------------------------------------------------- +// data_read - generic data read access handler +//------------------------------------------------- + +u16 am9513_device::data_read() +{ + u16 result = internal_read(); + if (!bus_is_16_bit() && !BIT(m_status, 0)) + result = (result >> 8) | 0xff00; + + // update the data pointer + advance_dpr(); + return result; +} + + +//------------------------------------------------- +// data_write - generic data write access handler +//------------------------------------------------- + +void am9513_device::data_write(u16 data) +{ + if (!bus_is_16_bit()) + { + data &= 0x00ff; + if (BIT(m_status, 0)) + data |= internal_read() & 0xff00; + else + data = (data << 8) | (internal_read() & 0x00ff); + } + internal_write(data); + + // update the data pointer + if (m_write_prefetch) + advance_dpr(); +} + + +//------------------------------------------------- +// read8 - 8-bit read access +//------------------------------------------------- + +READ8_MEMBER(am9513_device::read8) +{ + if (BIT(offset, 0)) + return status_read(); + else + return data_read() & 0x00ff; +} + + +//------------------------------------------------- +// write8 - 8-bit write access +//------------------------------------------------- + +WRITE8_MEMBER(am9513_device::write8) +{ + if (BIT(offset, 0)) + { + if (data == 0xef) + logerror("16-bit data bus selected with 8-bit write\n"); + command_write(data); + } + else + data_write(data | 0xff00); +} + + +//------------------------------------------------- +// read16 - 16-bit read access +//------------------------------------------------- + +READ16_MEMBER(am9513_device::read16) +{ + if (BIT(offset, 0)) + return status_read() | 0xff00; + else + { + if (!bus_is_16_bit()) + logerror("16-bit data read in 8-bit bus mode\n"); + return data_read(); + } +} + + +//------------------------------------------------- +// write16 - 16-bit write access +//------------------------------------------------- + +WRITE16_MEMBER(am9513_device::write16) +{ + if ((!bus_is_16_bit() || BIT(offset, 0)) && (data & 0xff00) != 0xff00) + logerror("Errant write of %02X to upper byte of %s register in %d-bit bus mode\n", + (data & 0xff00) >> 8, + BIT(offset, 0) ? "control" : "data", + bus_is_16_bit() ? 16 : 8); + + if (BIT(offset, 0)) + { + if ((data & 0x00ff) == 0x00e7) + logerror("8-bit data bus selected with 16-bit write\n"); + else if ((data & 0x00ff) == 0x00ef && !bus_is_16_bit()) + logerror("16-bit data bus selected\n"); + + command_write(data & 0x00ff); + } + else + data_write(data); +} + + +//************************************************************************** +// DIVIDED FREQUENCY OUTPUT +//************************************************************************** + +void am9513_device::fout_tick() +{ + --m_fout_counter; + if (m_fout_counter > 0) + return; + + // Toggle the output + m_fout = !m_fout; + + // Check whether the FOUT gate is on + if (!BIT(m_mmr, 12) && !m_fout_cb.isnull()) + m_fout_cb(m_fout); + + // Reload the counter + m_fout_counter = (m_mmr >> 8) & 15; + if (m_fout_counter == 0) + m_fout_counter = 16; +} diff --git a/src/devices/machine/am9513.h b/src/devices/machine/am9513.h new file mode 100644 index 00000000000..1c3cc587c53 --- /dev/null +++ b/src/devices/machine/am9513.h @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + Am9513A/Am9513 System Timing Controller + +*********************************************************************** + _____ _____ + VCC 1 |* \_/ | 40 OUT 3 + OUT 2 2 | | 39 GATE 2 + OUT 1 3 | | 38 OUT 4 + GATE 1 4 | | 37 OUT 5 + X1 5 | | 36 GATE 3 + X2 6 | | 35 GATE 4 + FOUT 7 | | 34 GATE 5 + C/_D 8 | | 33 SOURCE 1 + _WR 9 | | 32 SOURCE 2 + _CS 10 | Am9513A | 31 SOURCE 3 + _RD 11 | Am9513 | 30 SOURCE 4 + DB0 12 | | 29 SOURCE 5 + DB1 13 | | 28 DB15 + DB2 14 | | 27 DB14 + DB3 15 | | 26 DB13 + DB4 16 | | 25 DB12/GATE 5A + DB5 17 | | 24 DB11/GATE 4A + DB6 18 | | 23 DB10/GATE 3A + DB7 19 | | 22 DB9/GATE 2A + GATE 1A/DB8 20 |_____________| 21 VSS + +**********************************************************************/ + +#ifndef MAME_MACHINE_AM9513_H +#define MAME_MACHINE_AM9513_H + +#pragma once + +//************************************************************************** +// CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AM9513_OUT1_CALLBACK(_devcb) \ + devcb = &am9513_device::set_out_cb(*device, 0, DEVCB_##_devcb); +#define MCFG_AM9513_OUT2_CALLBACK(_devcb) \ + devcb = &am9513_device::set_out_cb(*device, 1, DEVCB_##_devcb); +#define MCFG_AM9513_OUT3_CALLBACK(_devcb) \ + devcb = &am9513_device::set_out_cb(*device, 2, DEVCB_##_devcb); +#define MCFG_AM9513_OUT4_CALLBACK(_devcb) \ + devcb = &am9513_device::set_out_cb(*device, 3, DEVCB_##_devcb); +#define MCFG_AM9513_OUT5_CALLBACK(_devcb) \ + devcb = &am9513_device::set_out_cb(*device, 4, DEVCB_##_devcb); +#define MCFG_AM9513_FOUT_CALLBACK(_devcb) \ + devcb = &am9513_device::set_fout_cb(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> am9513_device + +class am9513_device : public device_t +{ +public: + // device type constructor + am9513_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + // static configuration + template static devcb_base &set_out_cb(device_t &device, int c, Object &&cb) + { assert(c >= 0 && c < 5); return downcast(device).m_out_cb[c].set_callback(std::forward(cb)); } + template static devcb_base &set_fout_cb(device_t &device, Object &&cb) + { return downcast(device).m_fout_cb.set_callback(std::forward(cb)); } + + // 8-bit data bus interface + DECLARE_READ8_MEMBER(read8); + DECLARE_WRITE8_MEMBER(write8); + + // 16-bit data bus interface + DECLARE_READ16_MEMBER(read16); + DECLARE_WRITE16_MEMBER(write16); + + // Source N inputs + DECLARE_WRITE_LINE_MEMBER(source1_w) { write_source(0, state); } + DECLARE_WRITE_LINE_MEMBER(source2_w) { write_source(1, state); } + DECLARE_WRITE_LINE_MEMBER(source3_w) { write_source(2, state); } + DECLARE_WRITE_LINE_MEMBER(source4_w) { write_source(3, state); } + DECLARE_WRITE_LINE_MEMBER(source5_w) { write_source(4, state); } + + // Gate N inputs + DECLARE_WRITE_LINE_MEMBER(gate1_w) { write_gate(0, state); } + DECLARE_WRITE_LINE_MEMBER(gate2_w) { write_gate(1, state); } + DECLARE_WRITE_LINE_MEMBER(gate3_w) { write_gate(2, state); } + DECLARE_WRITE_LINE_MEMBER(gate4_w) { write_gate(3, state); } + DECLARE_WRITE_LINE_MEMBER(gate5_w) { write_gate(4, state); } + + // Gate N alternate inputs (8-bit mode only; multiplexed with DB8-DB12) + DECLARE_WRITE_LINE_MEMBER(gate1a_w) { write_gate_alt(0, state); } + DECLARE_WRITE_LINE_MEMBER(gate2a_w) { write_gate_alt(1, state); } + DECLARE_WRITE_LINE_MEMBER(gate3a_w) { write_gate_alt(2, state); } + DECLARE_WRITE_LINE_MEMBER(gate4a_w) { write_gate_alt(3, state); } + DECLARE_WRITE_LINE_MEMBER(gate5a_w) { write_gate_alt(4, state); } + + // diagnostic helper + std::string describe_register() const; + +protected: + // base constructor + am9513_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, bool is_am9513a); + + // device-level overrides + virtual void device_start() override; + virtual void device_clock_changed() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + +private: + // internal helpers + TIMER_CALLBACK_MEMBER(clear_outputs); + void master_reset(); + void init_freq_timer(int f); + void select_freq_timer(int f, int c, bool selected, bool cycle); + void set_master_mode(u16 data); + bool counter_is_mode_x(int c) const; + void set_counter_mode(int c, u16 data); + void arm_counter(int c); + void disarm_counter(int c); + void save_counter(int c); + void set_output(int c, bool state); + void set_toggle(int c, bool state); + void set_tc(int c, bool state); + void write_source(int s, bool level); + void count_edge(int c); + bool reload_from_hold(int c) const; + void step_counter(int c, bool force_load); + void gate_count(int c, bool state); + void write_gate(int g, bool level); + void write_gate_alt(int c, bool level); + u16 internal_read() const; + void internal_write(u16 data); + void advance_dpr(); + void command_write(u8 data); + u8 status_read() const; + bool bus_is_16_bit() const; + u16 data_read(); + void data_write(u16 data); + void fout_tick(); + + // output callbacks + devcb_write_line m_out_cb[5]; + devcb_write_line m_fout_cb; + + const bool m_is_am9513a; + + u8 m_dpr; + u16 m_mmr; + u8 m_status; + bool m_write_prefetch; + + // counter-specific registers + u16 m_count[5]; + u16 m_counter_load[5]; + u16 m_counter_hold[5]; + u16 m_counter_mode[5]; + u16 m_alarm[2]; + bool m_counter_armed[5]; + bool m_counter_running[5]; + bool m_alternate_count[5]; + + // input state + bool m_src[5]; + bool m_gate[5]; + bool m_gate_alt[5]; + bool m_gate_active[5]; + + // internal outputs + bool m_tc[5]; + bool m_toggle[5]; + + // frequency timer + u8 m_f; + enum + { + TIMER_F1, + TIMER_F2, + TIMER_F3, + TIMER_F4, + TIMER_F5 + }; + emu_timer *m_freq_timer[5]; + u8 m_freq_timer_selected[5]; + u8 m_freq_timer_cycle[5]; + + bool m_fout; + int m_fout_counter; +}; + +// ======================> am9513a_device + +class am9513a_device : public am9513_device +{ +public: + // device type constructor + am9513a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +// device type declarations +DECLARE_DEVICE_TYPE(AM9513, am9513_device) +DECLARE_DEVICE_TYPE(AM9513A, am9513a_device) + +#endif // MAME_MACHINE_AM9513_H diff --git a/src/mame/drivers/pm68k.cpp b/src/mame/drivers/pm68k.cpp index 5a707d94204..be471162a26 100644 --- a/src/mame/drivers/pm68k.cpp +++ b/src/mame/drivers/pm68k.cpp @@ -13,7 +13,7 @@ Status: Boots into monitor, some commands work, some freeze. #include "emu.h" #include "cpu/m68000/m68000.h" #include "bus/rs232/rs232.h" -#include "machine/clock.h" +#include "machine/am9513.h" #include "machine/z80sio.h" @@ -39,6 +39,7 @@ static ADDRESS_MAP_START(pm68k_mem, AS_PROGRAM, 16, pm68k_state) AM_RANGE(0x000000, 0x1fffff) AM_RAM AM_SHARE("rambase") AM_RANGE(0x200000, 0x205fff) AM_ROM AM_REGION("roms", 0) AM_RANGE(0x600000, 0x600007) AM_DEVREADWRITE8("mpsc", i8274_new_device, ba_cd_r, ba_cd_w, 0xff00) + AM_RANGE(0x800000, 0x800003) AM_DEVREADWRITE("stc", am9513_device, read16, write16) ADDRESS_MAP_END @@ -67,10 +68,10 @@ static MACHINE_CONFIG_START( pm68k ) MCFG_Z80SIO_OUT_DTRB_CB(DEVWRITELINE("rs232b", rs232_port_device, write_dtr)) MCFG_Z80SIO_OUT_RTSB_CB(DEVWRITELINE("rs232b", rs232_port_device, write_rts)) - MCFG_DEVICE_ADD("baudclock", CLOCK, 153600) - MCFG_CLOCK_SIGNAL_HANDLER(DEVWRITELINE("mpsc", i8274_new_device, rxca_w)) - MCFG_DEVCB_CHAIN_OUTPUT(DEVWRITELINE("mpsc", i8274_new_device, rxcb_w)) + MCFG_DEVICE_ADD("stc", AM9513, 3993600) + MCFG_AM9513_OUT4_CALLBACK(DEVWRITELINE("mpsc", i8274_new_device, rxca_w)) MCFG_DEVCB_CHAIN_OUTPUT(DEVWRITELINE("mpsc", i8274_new_device, txca_w)) + MCFG_AM9513_OUT5_CALLBACK(DEVWRITELINE("mpsc", i8274_new_device, rxcb_w)) MCFG_DEVCB_CHAIN_OUTPUT(DEVWRITELINE("mpsc", i8274_new_device, txcb_w)) MCFG_RS232_PORT_ADD("rs232a", default_rs232_devices, "terminal") -- cgit v1.2.3