diff options
author | 2020-09-14 23:32:58 -0400 | |
---|---|---|
committer | 2020-09-14 23:32:58 -0400 | |
commit | 7e121d68bb443f579da3271e43255d69925d71a3 (patch) | |
tree | 941183a697631a786b87c36900904f030badc1ad | |
parent | 949da6a0b08610f062b1c62255ffc907b2298e8b (diff) |
kl5c80a12, kl5c80a16: Added emulation of KP63(A) Timer/Counter unit. This improves timings in animalc, haekaka, pyenaget and tdoboon.
* animalc: Pile kludge upon kludge for poorly understood video timing register
* gocowboy, itazuram: Increase frequency of one timer interrupt (and hopper timing in gocowboy)
* kc82, kp69: Modernize state_add syntax
-rw-r--r-- | scripts/src/cpu.lua | 10 | ||||
-rw-r--r-- | src/devices/cpu/z80/kc82.cpp | 6 | ||||
-rw-r--r-- | src/devices/cpu/z80/kp63.cpp | 477 | ||||
-rw-r--r-- | src/devices/cpu/z80/kp63.h | 98 | ||||
-rw-r--r-- | src/devices/cpu/z80/kp69.cpp | 10 | ||||
-rw-r--r-- | src/mame/drivers/sigmab98.cpp | 84 |
6 files changed, 633 insertions, 52 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index f8c16807c87..a55cf443fdb 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -49,6 +49,14 @@ if (CPU_INCLUDE_DRC) then MAME_DIR .. "src/devices/cpu/drcbex86.h", } end + + if _OPTIONS["targetos"]=="macosx" and _OPTIONS["gcc"]~=nil then + if string.find(_OPTIONS["gcc"], "clang") and (str_to_version(_OPTIONS["gcc_version"]) < 80000) then + defines { + "TARGET_OS_OSX=1", + } + end + end end -------------------------------------------------- @@ -2624,6 +2632,8 @@ if (CPUS["Z80"]~=null) then MAME_DIR .. "src/devices/cpu/z80/kl5c80a12.h", MAME_DIR .. "src/devices/cpu/z80/kl5c80a16.cpp", MAME_DIR .. "src/devices/cpu/z80/kl5c80a16.h", + MAME_DIR .. "src/devices/cpu/z80/kp63.cpp", + MAME_DIR .. "src/devices/cpu/z80/kp63.h", MAME_DIR .. "src/devices/cpu/z80/kp69.cpp", MAME_DIR .. "src/devices/cpu/z80/kp69.h", MAME_DIR .. "src/devices/cpu/z80/ky80.cpp", diff --git a/src/devices/cpu/z80/kc82.cpp b/src/devices/cpu/z80/kc82.cpp index dbea8fc70f5..bf0a26290c4 100644 --- a/src/devices/cpu/z80/kc82.cpp +++ b/src/devices/cpu/z80/kc82.cpp @@ -64,13 +64,11 @@ void kc82_device::device_start() for (int n = 1; n <= 4; n++) { - state_add<u8>(KC82_B1 + n - 1, string_format("B%d", n).c_str(), - [this, n]() { return m_mmu_b[n]; }, + state_add(KC82_B1 + n - 1, string_format("B%d", n).c_str(), m_mmu_b[n], [this, n](u8 data) { m_mmu_b[n] = data; mmu_remap_pages(); } ).mask(0x3f); if (n != 4) - state_add<u16>(KC82_A1 + n - 1, string_format("A%d", n).c_str(), - [this, n]() { return m_mmu_a[n]; }, + state_add(KC82_A1 + n - 1, string_format("A%d", n).c_str(), m_mmu_a[n], [this, n](u16 data) { m_mmu_a[n] = data; mmu_remap_pages(); } ).mask(0x3ff); } diff --git a/src/devices/cpu/z80/kp63.cpp b/src/devices/cpu/z80/kp63.cpp new file mode 100644 index 00000000000..26968be46fe --- /dev/null +++ b/src/devices/cpu/z80/kp63.cpp @@ -0,0 +1,477 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Kawasaki Steel (Kawatetsu) KP63(A) Timer/Counter + + These macro cells provide 4 independent 16-bit down counters (reduced + to 3 in some versions) driven by an 8-bit prescaler attached to the + system clock. This prescaler is not fully emulated here, since its + operations are mostly transparent, though a divide-by-4 clock output + (SYNC) may be selected to appear on a port pin. + + Each counter has a single and optional external input (GATEn), which + on the KP63 can only be used to gate a divide-by-4 count but can also + be configured as an input clock on the KP63A. + + Two outputs are generated for each counter. The pulse or toggle output + (OUTPn) has configurable polarity and can be used for 8-bit PWM. The + strobe output (OUTSn) goes active high for 4 clock cycles when the + counter underflows and is connected to the interrupt controller. + + Writing the initial count register (CR) and reading the current count + are two-step processes, effective at the second write or first read. + These must not be overlapped with each other since they share a + temporary register. + +***************************************************************************/ + +#include "emu.h" +#include "kp63.h" + +#define VERBOSE 1 +#include "logmacro.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definitions +DEFINE_DEVICE_TYPE(KP63_3CHANNEL, kp63_3channel_device, "kp63_3channel", "Kawasaki Steel KP63 Timer/Counter (3 channels)") +DEFINE_DEVICE_TYPE(KP63A, kp63a_device, "kp63a", "Kawasaki Steel KP63A Timer/Counter") + +const char *const kp63_device::s_count_modes[4] = +{ + "one-shot", + "continuous count", + "WDT", + "PWM" +}; + + +//************************************************************************** +// KP63 DEVICE +//************************************************************************** + +//------------------------------------------------- +// kp63_device - constructor +//------------------------------------------------- + +kp63_device::kp63_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 num_counters, u8 mode_mask) + : device_t(mconfig, type, tag, owner, clock) + , m_out_pulse_callback(*this) + , m_out_strobe_callback(*this) + , c_num_counters(num_counters) + , c_mode_mask(mode_mask) + , m_timer{0} + , m_strobe_timer{0} + , m_pwm_timer{0} + , m_cr{0} + , m_last_count{0} + , m_count_tmp{0} + , m_status{0} + , m_rw_seq(0) + , m_timer_started(0) + , m_gate_input(0xf) +{ +} + + +//------------------------------------------------- +// kp63_3channel_device - constructor +//------------------------------------------------- + +kp63_3channel_device::kp63_3channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : kp63_device(mconfig, KP63_3CHANNEL, tag, owner, clock, 3, 0x1f) +{ +} + + +//------------------------------------------------- +// kp63a_device - constructor +//------------------------------------------------- + +kp63a_device::kp63a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : kp63_device(mconfig, KP63A, tag, owner, clock, 4, 0x3f) +{ +} + + +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void kp63_device::device_resolve_objects() +{ + // Resolve output callbacks + m_out_pulse_callback.resolve_all_safe(); + m_out_strobe_callback.resolve_all_safe(); +} + + +//------------------------------------------------- +// timer_expired - handle timed count underflow +//------------------------------------------------- + +template <int N> +TIMER_CALLBACK_MEMBER(kp63_device::timer_expired) +{ + timer_pulse(N); +} + + +//------------------------------------------------- +// strobe_off - handle end of strobe output +//------------------------------------------------- + +template <int N> +TIMER_CALLBACK_MEMBER(kp63_device::strobe_off) +{ + m_out_strobe_callback[N](0); +} + + +//------------------------------------------------- +// pwm_off - handle PWM phase change +//------------------------------------------------- + +template <int N> +TIMER_CALLBACK_MEMBER(kp63_device::pwm_off) +{ + m_status[N] &= 0x7f; + m_out_pulse_callback[N](BIT(m_status[N], 4) ? 1 : 0); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kp63_device::device_start() +{ + // Setup timers + m_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::timer_expired<0>), this)); + m_strobe_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::strobe_off<0>), this)); + m_pwm_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::pwm_off<0>), this)); + m_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::timer_expired<1>), this)); + m_strobe_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::strobe_off<1>), this)); + m_pwm_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::pwm_off<1>), this)); + m_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::timer_expired<2>), this)); + m_strobe_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::strobe_off<2>), this)); + m_pwm_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::pwm_off<2>), this)); + if (c_num_counters > 3) + { + m_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::timer_expired<3>), this)); + m_strobe_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::strobe_off<3>), this)); + m_pwm_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::pwm_off<3>), this)); + } + + // Save state + save_item(NAME(m_cr)); + save_item(NAME(m_last_count)); + save_item(NAME(m_count_tmp)); + save_item(NAME(m_status)); + save_item(NAME(m_rw_seq)); + save_item(NAME(m_timer_started)); + save_item(NAME(m_gate_input)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kp63_device::device_reset() +{ + for (unsigned n = 0; n < c_num_counters; n++) + { + // Turn off timers + m_timer[n]->adjust(attotime::never); + m_strobe_timer[n]->adjust(attotime::never); + m_pwm_timer[n]->adjust(attotime::never); + + // Reset status and count + m_status[n] = 0; + m_cr[n] = 0xffff; + m_last_count[n] = 0xffff; + + // Clear outputs + m_out_pulse_callback[n](0); + m_out_strobe_callback[n](0); + } + + // Clear read/write sequence for all counters + m_rw_seq = 0; + m_timer_started = 0; +} + + +//------------------------------------------------- +// timer_pulse - change outputs and stop or +// reload timer as count underflows +//------------------------------------------------- + +void kp63_device::timer_pulse(unsigned n) +{ + // Toggle pulse output + m_status[n] ^= 0x80; + m_out_pulse_callback[n](BIT(m_status[n], 7) != BIT(m_status[n], 4) ? 1 : 0); + + // Begin strobe output + m_out_strobe_callback[n](1); + m_strobe_timer[n]->adjust(clocks_to_attotime(4)); + + // Reload timer in continuous count and PWM modes + if (BIT(m_status[n], 2)) + timer_reload(n); + else + { + // Stop count at FFFF in one-shot and WDT modes + m_last_count[n] = 0xffff; + m_timer_started &= ~(1 << n); + } +} + + +//------------------------------------------------- +// timer_reload - reload timer from CR +//------------------------------------------------- + +void kp63_device::timer_reload(unsigned n) +{ + m_timer_started |= 1 << n; + + if (BIT(m_status[n], 5) || ((m_status[n] & 0x03) == 0x03 && !BIT(m_gate_input, n))) + m_last_count[n] = m_cr[n]; + else + { + unsigned prescale = BIT(m_status[n], 1) ? 4 : BIT(m_status[n], 0) ? 16 : 256; + if ((m_status[n] & 0x0c) == 0x0c) + { + // PWM + m_timer[n]->adjust(clocks_to_attotime(prescale * ((m_cr[n] & 0x00ff) + 1))); + m_pwm_timer[n]->adjust(clocks_to_attotime(prescale * ((m_cr[n] >> 8) + 1))); + } + else + m_timer[n]->adjust(clocks_to_attotime(prescale * (u32(m_cr[n]) + 1))); + } +} + + +//------------------------------------------------- +// timer_resume_count - start counting again +//------------------------------------------------- + +void kp63_device::timer_resume_count(unsigned n) +{ + if (!BIT(m_status[n], 5) || ((m_status[n] & 0x03) != 0x03 || BIT(m_gate_input, n))) + { + unsigned prescale = BIT(m_status[n], 1) ? 4 : BIT(m_status[n], 0) ? 16 : 256; + if ((m_status[n] & 0x0c) == 0x0c) + { + // PWM + m_timer[n]->adjust(clocks_to_attotime(prescale * ((m_last_count[n] & 0x00ff) + 1))); + m_pwm_timer[n]->adjust(clocks_to_attotime(prescale * ((m_last_count[n] >> 8) + 1))); + } + else + m_timer[n]->adjust(clocks_to_attotime(prescale * (u32(m_last_count[n]) + 1))); + } +} + + +//------------------------------------------------- +// timer_get_count - obtain the instant count in +// case of a readout or pause +//------------------------------------------------- + +u16 kp63_device::timer_get_count(unsigned n) const +{ + if (!BIT(m_timer_started, n) || BIT(m_status[n], 5) || ((m_status[n] & 0x03) == 0x03 && !BIT(m_gate_input, n))) + return m_last_count[n]; + else + { + unsigned prescale = BIT(m_status[n], 1) ? 4 : BIT(m_status[n], 0) ? 16 : 256; + if ((m_status[n] & 0x0c) == 0x0c) + { + // PWM + u8 ticks = attotime_to_clocks(m_timer[n]->remaining()) / prescale; + return ticks | ((m_cr[n] - (u16(ticks) << 8)) & 0xff00); + } + else + return attotime_to_clocks(m_timer[n]->remaining()) / prescale; + } +} + + +//------------------------------------------------- +// read - read count or status register +//------------------------------------------------- + +u8 kp63_device::read(offs_t offset) +{ + const unsigned n = offset >> 1; + assert(n < c_num_counters); + + if (BIT(offset, 0)) + { + // Status read clears read/write sequence + if (!machine().side_effects_disabled()) + m_rw_seq &= ~(1 << n); + return m_status[n]; + } + else if (BIT(m_rw_seq, n)) + { + // Second step of counter readout + if (!machine().side_effects_disabled()) + m_rw_seq &= ~(1 << n); + return m_count_tmp[n]; + } + else + { + // First step of counter readout + u16 count = timer_get_count(n); + if (!machine().side_effects_disabled()) + { + // Latch high byte into TMP register + m_rw_seq |= 1 << n; + m_count_tmp[n] = count >> 8; + } + return count & 0x00ff; + } +} + +//------------------------------------------------- +// write - set CR or mode register +//------------------------------------------------- + +void kp63_device::write(offs_t offset, u8 data) +{ + const unsigned n = offset >> 1; + assert(n < c_num_counters); + + if (BIT(offset, 0)) + { + bool old_outp = BIT(m_status[n], 7) != BIT(m_status[n], 4); + + // Stop count before setting mode + if (BIT(m_timer_started, n)) + { + if (!BIT(m_status[n], 5) || ((m_status[n] & 0x03) != 0x03 || BIT(m_gate_input, n))) + { + m_last_count[n] = timer_get_count(n); + m_timer[n]->adjust(attotime::never); + m_pwm_timer[n]->adjust(attotime::never); + } + m_timer_started &= ~(1 << n); + } + + if (BIT(data & c_mode_mask, 5)) + LOG("%s: Timer #%d configured for %s mode, %s edges of GATE, initial output %c\n", + machine().describe_context(), + n, + s_count_modes[BIT(data, 2, 2)], + BIT(data, 1) ? "???" : BIT(data, 0) ? "falling" : "rising", + BIT(data, 4) ? 'H' : 'L'); + else + LOG("%s: Timer #%d configured for %s mode, 1/%d system clock (GATE %s), initial output %c\n", + machine().describe_context(), + n, + s_count_modes[BIT(data, 2, 2)], + BIT(data, 1) ? 4 : BIT(data, 0) ? 16 : 256, + (data == 0x03) == 0x03 ? "effective" : "ignored", + BIT(data, 4) ? 'H' : 'L'); + m_status[n] = data & c_mode_mask; + + // Update OUTP + if (old_outp != BIT(data, 4)) + m_out_pulse_callback[n](BIT(data, 4) ? 1 : 0); + } + else if ((m_status[n] & 0x0c) == 0x08) + { + // WDT retrigger (data ignored; initial count must be written using a different mode) + timer_reload(n); + } + else if (BIT(m_rw_seq, n)) + { + // Second step of initial count write + m_rw_seq &= ~(1 << n); + m_cr[n] = u16(data) << 8 | m_count_tmp[n]; + + LOG("%s: Timer #%d initial count = %d\n", machine().describe_context(), n, (m_status[n] == 0x0c) ? m_cr[n] & 0x00ff : m_cr[n]); + + // Automatic retrigger in one-shot and continuous modes + if (!BIT(m_status[n], 3) || !BIT(m_timer_started, n)) + { + if (!BIT(m_status[n], 7)) + { + // Toggle OUTP + m_status[n] |= 0x80; + m_out_pulse_callback[n](BIT(m_status[n], 4) ? 0 : 1); + } + timer_reload(n); + } + } + else + { + // First step of initial count write (held in TMP register) + m_rw_seq |= 1 << n; + m_count_tmp[n] = data; + } +} + +//------------------------------------------------- +// write_gate - handle gate inputs +//------------------------------------------------- + +void kp63_device::write_gate(unsigned n, bool state) +{ + assert(n < c_num_counters); + + if (BIT(m_gate_input, n) != state) + return; + + if (state) + m_gate_input |= 1 << n; + else + m_gate_input &= ~(1 << n); + + if (BIT(m_timer_started, n)) + { + if ((m_status[n] & 0x23) == 0x03) + { + // Timer gated on or off + if (state) + timer_resume_count(n); + else + { + m_last_count[n] = timer_get_count(n); + m_timer[n]->adjust(attotime::never); + } + } + else if ((m_status[n] & 0x23) == (state ? 0x21 : 0x20)) + { + // Count edges of gate input + if ((m_status[n] & 0x0c) == 0x0c) + { + // PWM: count is in lower 8 bits + if ((m_last_count[n] & 0x00ff) == 0) + timer_pulse(n); + else + { + // Decrement both halves and check for underflow in upper half + m_last_count[n] -= 0x0101; + if (m_last_count[n] >= 0xff00) + { + m_status[n] &= 0x7f; + m_out_pulse_callback[n](BIT(m_status[n], 4) ? 1 : 0); + } + } + } + else if (m_last_count[n]-- == 0) + timer_pulse(n); + } + } +} diff --git a/src/devices/cpu/z80/kp63.h b/src/devices/cpu/z80/kp63.h new file mode 100644 index 00000000000..73e269fb72b --- /dev/null +++ b/src/devices/cpu/z80/kp63.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Kawasaki Steel (Kawatetsu) KP63(A) Timer/Counter + +***************************************************************************/ + +#ifndef MAME_CPU_Z80_KP63_H +#define MAME_CPU_Z80_KP63_H + +#pragma once + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class kp63_device : public device_t +{ +public: + // callback configuration + template <int N> auto outp_callback() { return m_out_pulse_callback[N].bind(); } + template <int N> auto outs_callback() { return m_out_strobe_callback[N].bind(); } + + // register interface + u8 read(offs_t offset); + void write(offs_t offset, u8 data); + + // input line interface + template <int N> DECLARE_WRITE_LINE_MEMBER(gate_w) { write_gate(N, state); } + +protected: + // construction/destruction + kp63_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 num_counters, u8 mode_mask); + + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + +private: + static const char *const s_count_modes[4]; + + // timer callbacks + template <int N> TIMER_CALLBACK_MEMBER(timer_expired); + template <int N> TIMER_CALLBACK_MEMBER(strobe_off); + template <int N> TIMER_CALLBACK_MEMBER(pwm_off); + + // internal helpers + void timer_pulse(unsigned n); + void timer_reload(unsigned n); + void timer_resume_count(unsigned n); + u16 timer_get_count(unsigned n) const; + void write_gate(unsigned n, bool state); + + // callback objects + devcb_write_line::array<4> m_out_pulse_callback; + devcb_write_line::array<4> m_out_strobe_callback; + + // constant parameters + const u8 c_num_counters; + const u8 c_mode_mask; + + // internal timers + emu_timer *m_timer[4]; + emu_timer *m_strobe_timer[4]; + emu_timer *m_pwm_timer[4]; + + // internal state + u16 m_cr[4]; + u16 m_last_count[4]; + u8 m_count_tmp[4]; + u8 m_status[4]; + u8 m_rw_seq; + u8 m_timer_started; + u8 m_gate_input; +}; + +class kp63_3channel_device : public kp63_device +{ +public: + // device type constructor + kp63_3channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +class kp63a_device : public kp63_device +{ +public: + // device type constructor + kp63a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +// device type declarations +DECLARE_DEVICE_TYPE(KP63_3CHANNEL, kp63_3channel_device) +DECLARE_DEVICE_TYPE(KP63A, kp63a_device) + +#endif // MAME_CPU_Z80_KP63_H diff --git a/src/devices/cpu/z80/kp69.cpp b/src/devices/cpu/z80/kp69.cpp index dca74ff3b25..84be060c4c7 100644 --- a/src/devices/cpu/z80/kp69.cpp +++ b/src/devices/cpu/z80/kp69.cpp @@ -107,12 +107,12 @@ void kp69_device::device_start() void kp69_base_device::add_to_state(device_state_interface &state, int index) { - state.state_add<u16>(index, "IRR", [this]() { return m_irr; }, [this](u16 data) { set_irr(data); }); - state.state_add<u16>(index + 1, "ISR", [this]() { return m_isr; }, [this](u16 data) { set_isr(data); }); + state.state_add(index, "IRR", m_irr, [this](u16 data) { set_irr(data); }); + state.state_add(index + 1, "ISR", m_isr, [this](u16 data) { set_isr(data); }); state.state_add(index + 2, "IVR", m_ivr).mask(0xe0); - state.state_add<u16>(index + 3, "LER", [this]() { return m_ler; }, [this](u16 data) { set_ler(data); }); - state.state_add<u16>(index + 4, "PGR", [this]() { return m_pgr; }, [this](u16 data) { set_pgr(data); }); - state.state_add<u16>(index + 5, "IMR", [this]() { return m_imr; }, [this](u16 data) { set_imr(data); }); + state.state_add(index + 3, "LER", m_ler, [this](u16 data) { set_ler(data); }); + state.state_add(index + 4, "PGR", m_pgr, [this](u16 data) { set_pgr(data); }); + state.state_add(index + 5, "IMR", m_imr, [this](u16 data) { set_imr(data); }); } diff --git a/src/mame/drivers/sigmab98.cpp b/src/mame/drivers/sigmab98.cpp index 39bc6c29f93..99fdfb37bbd 100644 --- a/src/mame/drivers/sigmab98.cpp +++ b/src/mame/drivers/sigmab98.cpp @@ -102,7 +102,7 @@ To Do: to "coin" (it probably changes the number of reads from port $C0). I guess the reset_delay mechanism should be implemented with a timer in eeprom.c. - pyenaget intro: when the theater scrolls out to the left, the train should scroll in from the right, - with no visible gaps. It currently leaves the screen empty instead, for several seconds. + with no visible gaps. It currently leaves a small gap. - tdoboon: no smoke from hit planes as shown in the video? Tiles are present (f60-125f) and used in demo mode. - dashhero does not acknowledge the button bashing correctly, it's very hard to win (a slower pace works better!) - dodghero and sushimar often write zeroes to 81XX1 and 00XX1 for some reason (maybe just sloppy coding?) @@ -283,6 +283,7 @@ public: sammymdl_state(const machine_config &mconfig, device_type type, const char *tag) : sigmab98_base_state(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_kp69(*this, "maincpu:kp69") , m_eeprom(*this, "eeprom") , m_hopper(*this, "hopper") , m_hopper_small(*this, "hopper_small") @@ -301,13 +302,13 @@ public: void init_itazuram(); void init_animalc(); void init_haekaka(); - void init_gocowboy(); protected: virtual void machine_start() override { m_leds.resolve(); } private: - TIMER_DEVICE_CALLBACK_MEMBER(sammymdl_irq); + TIMER_DEVICE_CALLBACK_MEMBER(gocowboy_int); + TIMER_DEVICE_CALLBACK_MEMBER(timer_1khz); uint8_t coin_counter_r(); void coin_counter_w(uint8_t data); @@ -339,6 +340,7 @@ private: // Required devices required_device<kl5c80a12_device> m_maincpu; + required_device<kp69_device> m_kp69; required_device<eeprom_serial_93cxx_device> m_eeprom; // Optional devices @@ -348,10 +350,6 @@ private: output_finder<8> m_leds; - uint8_t m_vblank_vector; - uint8_t m_timer0_vector; - uint8_t m_timer1_vector; - uint8_t m_out[3]; }; @@ -946,7 +944,7 @@ uint8_t sigmab98_base_state::vblank_r() { // mask 0x04 must be set before writing sprite list // mask 0x10 must be set or irq/00 hangs? - return m_vblank | 0x14; + return (m_vblank & ~0x01) | 0x14; } void sigmab98_base_state::vblank_w(uint8_t data) @@ -1632,23 +1630,29 @@ void lufykzku_state::lufykzku(machine_config &config) Sammy Medal Games ***************************************************************************/ -TIMER_DEVICE_CALLBACK_MEMBER(sammymdl_state::sammymdl_irq) +TIMER_DEVICE_CALLBACK_MEMBER(sammymdl_state::gocowboy_int) { int scanline = param; - uint16_t irqs = 0; + // TODO: what really triggers these? if (scanline == 240) - irqs |= 1 << ((m_vblank_vector & 0x1e) >> 1); + { + m_kp69->ir_w<0>(1); + m_kp69->ir_w<0>(0); + } if (scanline == 128) - irqs |= 1 << ((m_timer0_vector & 0x1e) >> 1); - - if (scanline == 32) - irqs |= 1 << ((m_timer1_vector & 0x1e) >> 1); + { + m_kp69->ir_w<1>(1); + m_kp69->ir_w<1>(0); + } +} - // FIXME: this is not much less of a hack than HOLD_LINE - if (irqs != 0) - m_maincpu->set_state_int(kl5c80a12_device::KP69_IRR, m_maincpu->state_int(kl5c80a12_device::KP69_IRR) | irqs); +TIMER_DEVICE_CALLBACK_MEMBER(sammymdl_state::timer_1khz) +{ + // FIXME: this is an internally generated timer interrupt + m_kp69->ir_w<11>(1); + m_kp69->ir_w<11>(0); } void sammymdl_state::sammymdl(machine_config &config) @@ -1657,8 +1661,6 @@ void sammymdl_state::sammymdl(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &sammymdl_state::animalc_map); m_maincpu->set_addrmap(AS_IO, &sammymdl_state::animalc_io); - TIMER(config, "scantimer").configure_scanline(FUNC(sammymdl_state::sammymdl_irq), "screen", 0, 1); - NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // battery backed RAM EEPROM_93C46_8BIT(config, "eeprom"); @@ -1673,7 +1675,7 @@ void sammymdl_state::sammymdl(machine_config &config) m_screen->set_size(0x140, 0x100); m_screen->set_visarea(0, 0x140-1, 0, 0xf0-1); m_screen->set_screen_update(FUNC(sammymdl_state::screen_update)); - m_screen->screen_vblank().set(FUNC(sammymdl_state::screen_vblank_sammymdl)); + m_screen->screen_vblank().set(m_kp69, FUNC(kp69_device::ir_w<0>)); m_screen->set_palette(m_palette); GFXDECODE(config, m_gfxdecode, m_palette, gfx_sigmab98); @@ -1706,9 +1708,14 @@ void sammymdl_state::gocowboy(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &sammymdl_state::gocowboy_map); m_maincpu->set_addrmap(AS_IO, &sammymdl_state::gocowboy_io); + TIMER(config, "scantimer").configure_scanline(FUNC(sammymdl_state::gocowboy_int), "screen", 0, 1); + TIMER(config, "1khztimer").configure_periodic(FUNC(sammymdl_state::timer_1khz), attotime::from_msec(1)); + config.device_remove("hopper"); - TICKET_DISPENSER(config, m_hopper_small, attotime::from_msec(1000), TICKET_MOTOR_ACTIVE_LOW, TICKET_STATUS_ACTIVE_LOW ); - TICKET_DISPENSER(config, m_hopper_large, attotime::from_msec(1000), TICKET_MOTOR_ACTIVE_LOW, TICKET_STATUS_ACTIVE_LOW ); + TICKET_DISPENSER(config, m_hopper_small, attotime::from_msec(200), TICKET_MOTOR_ACTIVE_LOW, TICKET_STATUS_ACTIVE_LOW ); + TICKET_DISPENSER(config, m_hopper_large, attotime::from_msec(200), TICKET_MOTOR_ACTIVE_LOW, TICKET_STATUS_ACTIVE_LOW ); + + m_screen->screen_vblank().set_nop(); } void sammymdl_state::haekaka(machine_config &config) @@ -1717,14 +1724,21 @@ void sammymdl_state::haekaka(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &sammymdl_state::haekaka_map); m_maincpu->set_addrmap(AS_IO, &sammymdl_state::haekaka_io); + + m_screen->screen_vblank().set(m_kp69, FUNC(kp69_device::ir_w<2>)); } void sammymdl_state::itazuram(machine_config &config) { sammymdl(config); + TIMER(config, "scantimer").configure_scanline(FUNC(sammymdl_state::gocowboy_int), "screen", 0, 1); + TIMER(config, "1khztimer").configure_periodic(FUNC(sammymdl_state::timer_1khz), attotime::from_msec(1)); + m_maincpu->set_addrmap(AS_PROGRAM, &sammymdl_state::itazuram_map); m_maincpu->set_addrmap(AS_IO, &sammymdl_state::itazuram_io); + + m_screen->screen_vblank().set_nop(); } void sammymdl_state::pyenaget(machine_config &config) @@ -1733,6 +1747,8 @@ void sammymdl_state::pyenaget(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &sammymdl_state::haekaka_map); m_maincpu->set_addrmap(AS_IO, &sammymdl_state::pyenaget_io); + + m_screen->screen_vblank().set(m_kp69, FUNC(kp69_device::ir_w<2>)); } void sammymdl_state::tdoboon(machine_config &config) @@ -1742,6 +1758,7 @@ void sammymdl_state::tdoboon(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &sammymdl_state::tdoboon_map); m_maincpu->set_addrmap(AS_IO, &sammymdl_state::tdoboon_io); + m_screen->screen_vblank().set(m_kp69, FUNC(kp69_device::ir_w<2>)); m_screen->set_visarea(0,0x140-1, 0+4,0xf0+4-1); } @@ -2184,10 +2201,6 @@ void sammymdl_state::init_animalc() // force jump out of BIOS loop rom[0x005ac] = 0xc3; - - m_vblank_vector = 0x00; // increment counter - m_timer0_vector = 0x1c; // read hopper state - m_timer1_vector = 0x1e; // drive hopper motor } /*************************************************************************** @@ -2225,13 +2238,6 @@ ROM_START( gocowboy ) ROM_LOAD( "vm1212f01.u5.jed", 0x0000, 0x5cde, CRC(b86a1825) SHA1(cc2e633fb8a24cfc93291a778b0964089f6b8ac7) ) ROM_END -void sammymdl_state::init_gocowboy() -{ - m_vblank_vector = 0x00; - m_timer0_vector = 0x02; - m_timer1_vector = 0x16; -} - /*************************************************************************** Itazura Monkey ( VX1902L02 ITZRMONKY 200011211639 SAMMY CORP. AM ) @@ -2260,10 +2266,6 @@ void sammymdl_state::init_itazuram() // force jump out of BIOS loop rom[0x005ac] = 0xc3; - - m_vblank_vector = 0x00; - m_timer0_vector = 0x02; - m_timer1_vector = 0x16; } /*************************************************************************** @@ -2366,10 +2368,6 @@ void sammymdl_state::init_haekaka() // force jump out of BIOS loop rom[0x005ac] = 0xc3; - - m_vblank_vector = 0x04; - m_timer0_vector = 0x1a; - m_timer1_vector = 0x1c; } /*************************************************************************** @@ -2396,4 +2394,4 @@ GAME( 2000, itazuram, sammymdl, itazuram, sammymdl, sammymdl_state, init_itazura GAME( 2000, pyenaget, sammymdl, pyenaget, sammymdl, sammymdl_state, init_haekaka, ROT0, "Sammy", "Pye-nage Taikai", 0 ) GAME( 2000, tdoboon, sammymdl, tdoboon, haekaka, sammymdl_state, init_haekaka, ROT0, "Sammy", "Taihou de Doboon", 0 ) GAME( 2001, haekaka, sammymdl, haekaka, haekaka, sammymdl_state, init_haekaka, ROT0, "Sammy", "Hae Hae Ka Ka Ka", 0 ) -GAME( 2003, gocowboy, 0, gocowboy, gocowboy, sammymdl_state, init_gocowboy, ROT0, "Sammy", "Go Go Cowboy (English, prize)", 0 ) +GAME( 2003, gocowboy, 0, gocowboy, gocowboy, sammymdl_state, empty_init, ROT0, "Sammy", "Go Go Cowboy (English, prize)", 0 ) |