diff options
author | 2018-07-20 02:27:17 +0200 | |
---|---|---|
committer | 2018-07-21 10:07:00 +0200 | |
commit | eed782f1e3123685a1f368e51577629122542308 (patch) | |
tree | 816a9e97527d05e0b433a12b293628ffd41a7e10 /src/devices/machine/ioptimer.cpp | |
parent | bbfb764647e46dedb81283f89836deaba4f96f68 (diff) |
ps2sony: Some basic VU1 support, major file reshuffling, nw
Diffstat (limited to 'src/devices/machine/ioptimer.cpp')
-rw-r--r-- | src/devices/machine/ioptimer.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/devices/machine/ioptimer.cpp b/src/devices/machine/ioptimer.cpp new file mode 100644 index 00000000000..31c6c4fd6f2 --- /dev/null +++ b/src/devices/machine/ioptimer.cpp @@ -0,0 +1,263 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/****************************************************************************** +* +* Sony PlayStation 2 IOP timer device skeleton +* +* To Do: +* Everything +* +*/ + +#include "emu.h" +#include "ioptimer.h" + +DEFINE_DEVICE_TYPE(SONYIOP_TIMER, iop_timer_device, "ioptimer", "PlayStation 2 IOP timer") + +iop_timer_device::iop_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SONYIOP_TIMER, tag, owner, clock) + , m_compare_timer(nullptr) + , m_overflow_timer(nullptr) + , m_last_update_time(attotime::zero) + , m_elapsed_time(attotime::zero) + , m_zero_return(false) + , m_count(0) + , m_compare(0) + , m_gate_enable(false) + , m_gate_mode(GATM_LOW) + , m_cmp_int_enabled(false) + , m_cmp_int(false) + , m_ovf_int_enabled(false) + , m_ovf_int(false) + , m_ienable(false) + , m_int_cb(*this) +{ +} + +void iop_timer_device::device_start() +{ + m_int_cb.resolve_safe(); + + if (!m_compare_timer) + m_compare_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_timer_device::compare), this)); + + if (!m_overflow_timer) + m_overflow_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_timer_device::overflow), this)); +} + +void iop_timer_device::device_reset() +{ + m_ctrl = 0; + + m_last_update_time = attotime::zero; + m_elapsed_time = attotime::zero; + + m_zero_return = false; + + m_count = 0; + m_compare = 0; + + m_gate_enable = false; + m_gate_mode = GATM_LOW; + + m_cmp_int_enabled = false; + m_cmp_int = false; + + m_ovf_int_enabled = false; + m_ovf_int = false; + + m_ienable = false; + + m_compare_timer->adjust(attotime::never); + m_overflow_timer->adjust(attotime::never); +} + +void iop_timer_device::update_gate() +{ + // TODO +} + +void iop_timer_device::update_interrupts() +{ + if (!m_int_cb.isnull()) + { + bool interrupt = m_ienable && ((m_ovf_int && m_ovf_int_enabled) || (m_cmp_int && m_cmp_int_enabled)); + m_int_cb(interrupt); + } +} + +void iop_timer_device::update_compare_timer() +{ + // TODO: Compare timer functionality is a total guess + if (!m_ienable || !m_cmp_int_enabled) + m_compare_timer->adjust(attotime::never); + m_compare_timer->adjust(attotime::from_ticks(m_compare - m_count, clock())); +} + +void iop_timer_device::update_overflow_timer() +{ + // TODO: Overflow timer functionality is not used yet, total guess + /* + uint32_t ticks = 0; + if (m_zero_return) + { + if (m_compare > m_count) + ticks = m_compare - m_count; + else + ticks = (uint32_t)(0x100000000ULL - (m_count - m_compare)); + } + else + { + ticks = (uint32_t)(0x100000000ULL - m_count); + } + */ + m_overflow_timer->adjust(attotime::never); +} + +void iop_timer_device::update_count() +{ + attotime curr_time = machine().scheduler().time(); + attotime time_delta = curr_time - m_last_update_time; + m_last_update_time = curr_time; + m_elapsed_time += time_delta; + uint32_t ticks = (uint32_t)m_elapsed_time.as_ticks(clock()); + if (ticks > 0) + { + m_elapsed_time -= attotime::from_ticks(ticks, clock()); + m_count += ticks; + } +} + +void iop_timer_device::set_ctrl(uint32_t data) +{ + static const char *gatm_names[4] = { "low?", "reset+rising?", "reset+falling?", "reset+both?" }; + logerror("%s: set_ctrl: GATE=%d, GATM=%s, ZRET=%d\n", machine().describe_context(), data & CTRL_GATE, gatm_names[(data & CTRL_GATM) >> 1], (data & CTRL_ZRET) >> 3); + logerror("%s: CMPE=%d, OVFE=%d, REP_INT=%d, TOG_INT=%d\n", machine().describe_context(), (data & CTRL_CMPE) >> 4, (data & CTRL_OVFE) >> 5, (data & CTRL_REPI) >> 6, (data & CTRL_TOGI) >> 7); + + const uint32_t old = m_ctrl; + m_ctrl = data | CTRL_INTE; + const uint32_t changed = old ^ data; + + if (!changed) return; + + m_gate_enable = data & CTRL_GATE; + m_gate_mode = (timer_gate_mode)((data & CTRL_GATM) >> 1); + m_zero_return = (data & CTRL_ZRET) >> 3; + m_cmp_int_enabled = (data & CTRL_CMPE) >> 4; + m_ovf_int_enabled = (data & CTRL_OVFE) >> 5; + m_repeat_int = (data & CTRL_REPI) >> 6; + m_toggle_int = (data & CTRL_TOGI) >> 7; + m_ienable = 1; + + m_count = 0; + if (changed & CTRL_CMPE) + { + if (data & CTRL_CMPE) + update_compare_timer(); + else + m_compare_timer->adjust(attotime::never); + } + + if (changed & CTRL_OVFE) + { + if (data & CTRL_OVFE) + update_overflow_timer(); + else + m_overflow_timer->adjust(attotime::never); + } + + if (changed & CTRL_INTE) + { + update_interrupts(); + } +} + +TIMER_CALLBACK_MEMBER(iop_timer_device::compare) +{ + if (m_zero_return) + { + m_count = 0; // Guess + update_compare_timer(); + } + else + { + m_compare_timer->adjust(attotime::never); + } + + if (m_cmp_int_enabled) + m_cmp_int = 1; + + update_interrupts(); +} + +TIMER_CALLBACK_MEMBER(iop_timer_device::overflow) +{ + if (m_ovf_int_enabled) + m_ovf_int = 1; + + update_interrupts(); +} + +READ32_MEMBER(iop_timer_device::read) +{ + uint32_t ret = 0; + switch (offset) + { + case 0x00: + { + //const uint32_t old = m_count; + update_count(); + ret = m_count; + //if (old != m_count) + //logerror("%s: IOP timer read: COUNT (%08x & %08x)\n", machine().describe_context(), ret, mem_mask); + break; + } + + case 0x01: + ret = m_ctrl | (m_ovf_int ? CTRL_OVFF : 0) | (m_cmp_int ? CTRL_CMPF : 0); + logerror("%s: IOP timer read: MODE (%08x & %08x)\n", machine().describe_context(), ret, mem_mask); + break; + + case 0x02: + ret = m_compare; + logerror("%s: IOP timer read: COMPARE (%08x & %08x)\n", machine().describe_context(), ret, mem_mask); + break; + + default: + break; + } + return ret; +} + +WRITE32_MEMBER(iop_timer_device::write) +{ + switch (offset) + { + case 0x00: + m_count = data; + logerror("%s: IOP timer write: COUNT = %08x & %08x\n", machine().describe_context(), data, mem_mask); + update_compare_timer(); + update_overflow_timer(); + break; + + case 0x01: + set_ctrl(data); + break; + + case 0x02: + { + logerror("%s: IOP timer write: COMPARE = %08x & %08x\n", machine().describe_context(), data, mem_mask); + if (m_compare == data) + break; + + m_compare = data; + if (!m_toggle_int) + m_ienable = true; + update_compare_timer(); + break; + } + + default: + break; + } +} |