diff options
Diffstat (limited to 'src/devices/cpu/h8/h8_timer16.cpp')
-rw-r--r-- | src/devices/cpu/h8/h8_timer16.cpp | 768 |
1 files changed, 427 insertions, 341 deletions
diff --git a/src/devices/cpu/h8/h8_timer16.cpp b/src/devices/cpu/h8/h8_timer16.cpp index 5c4294e542c..263168909d6 100644 --- a/src/devices/cpu/h8/h8_timer16.cpp +++ b/src/devices/cpu/h8/h8_timer16.cpp @@ -1,298 +1,352 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_timer16.cpp + + H8 16 bits timer + + TODO: + - IRQs are level triggered? eg. when an interrupt enable flag gets set + while an overflow or compare match flag is 1, will it trigger an IRQ? + Or if it's edge triggered, will it trigger an IRQ on rising edge of + (irq_enable & flag)? Note that mu100 will lock up at boot if it's + triggered at rising edge of (flag) or (irq_enable & flag). + - When writing 0 to the status register(s), the overflow/compare match + flags will only be cleared after a read access was done while they + were set? It's how the databook explains it, similar to HD6301. + - H8/325 16-bit timer is shoehorned in and may have a bug lurking? + It doesn't have TGR registers, but functionally equivalent OCR/ICR. + - Make the base class more generic, and derive the devices from that, + so they don't have to jumble so much with the IRQ/flag bits. The + overflow IRQ/flag being hardcoded on bit 4 is also problematic. + - Proper support for input capture registers. + - Add support for chained timers. + +***************************************************************************/ + #include "emu.h" #include "h8_timer16.h" // Verbosity level // 0 = no messages // 1 = everything -const int V = 0; +static constexpr int V = 0; -DEFINE_DEVICE_TYPE(H8_TIMER16, h8_timer16_device, "h8_timer16", "H8 16-bit timer") -DEFINE_DEVICE_TYPE(H8_TIMER16_CHANNEL, h8_timer16_channel_device, "h8_timer16_channel", "H8 16-bit timer channel") -DEFINE_DEVICE_TYPE(H8H_TIMER16_CHANNEL, h8h_timer16_channel_device, "h8h_timer16_channel", "H8H 16-bit timer channel") -DEFINE_DEVICE_TYPE(H8S_TIMER16_CHANNEL, h8s_timer16_channel_device, "h8s_timer16_channel", "H8S 16-bit timer channel") +DEFINE_DEVICE_TYPE(H8_TIMER16, h8_timer16_device, "h8_timer16", "H8 16-bit timer") +DEFINE_DEVICE_TYPE(H8_TIMER16_CHANNEL, h8_timer16_channel_device, "h8_timer16_channel", "H8 16-bit timer channel") +DEFINE_DEVICE_TYPE(H8325_TIMER16_CHANNEL, h8325_timer16_channel_device, "h8325_timer16_channel", "H8/325 16-bit timer channel") +DEFINE_DEVICE_TYPE(H8H_TIMER16_CHANNEL, h8h_timer16_channel_device, "h8h_timer16_channel", "H8H 16-bit timer channel") +DEFINE_DEVICE_TYPE(H8S_TIMER16_CHANNEL, h8s_timer16_channel_device, "h8s_timer16_channel", "H8S 16-bit timer channel") -h8_timer16_channel_device::h8_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : +h8_timer16_channel_device::h8_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : h8_timer16_channel_device(mconfig, H8_TIMER16_CHANNEL, tag, owner, clock) { - chain_tag = nullptr; } -h8_timer16_channel_device::h8_timer16_channel_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : +h8_timer16_channel_device::h8_timer16_channel_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, type, tag, owner, clock), - cpu(*this, "^^"), chained_timer(nullptr), intc(nullptr), intc_tag(nullptr), tier_mask(0), tgr_count(0), tbr_count(0), tgr_clearing(0), tcr(0), tier(0), ier(0), isr(0), clock_type(0), - clock_divider(0), tcnt(0), last_clock_update(0), event_time(0), phase(0), counter_cycle(0), counter_incrementing(false), channel_active(false) + m_cpu(*this, finder_base::DUMMY_TAG), + m_intc(*this, finder_base::DUMMY_TAG), + m_chained_timer(*this, finder_base::DUMMY_TAG), + m_tier_mask(0), m_tgr_count(0), m_tbr_count(0), m_tgr_clearing(0), m_tcr(0), m_tier(0), m_ier(0), m_isr(0), m_clock_type(0), + m_clock_divider(0), m_tcnt(0), m_last_clock_update(0), m_event_time(0), m_phase(0), m_counter_cycle(0), m_counter_incrementing(false), m_channel_active(false) { - chain_tag = nullptr; -} - -void h8_timer16_channel_device::set_info(int _tgr_count, int _tbr_count, const char *intc, int irq_base) -{ - tgr_count = _tgr_count; - tbr_count = _tbr_count; - intc_tag = intc; - - interrupt[0] = irq_base++; - interrupt[1] = irq_base++; - interrupt[2] = -1; - interrupt[3] = -1; - interrupt[4] = irq_base; - interrupt[5] = irq_base; } -READ8_MEMBER(h8_timer16_channel_device::tcr_r) +u8 h8_timer16_channel_device::tcr_r() { - return tcr; + return m_tcr; } -WRITE8_MEMBER(h8_timer16_channel_device::tcr_w) +void h8_timer16_channel_device::tcr_w(u8 data) { update_counter(); - tcr = data; + m_tcr = data; if(V>=1) logerror("tcr_w %02x\n", data); tcr_update(); recalc_event(); } -READ8_MEMBER(h8_timer16_channel_device::tmdr_r) +u8 h8_timer16_channel_device::tmdr_r() { return 0x00; } -WRITE8_MEMBER(h8_timer16_channel_device::tmdr_w) +void h8_timer16_channel_device::tmdr_w(u8 data) { if(V>=1) logerror("tmdr_w %02x\n", data); } -READ8_MEMBER(h8_timer16_channel_device::tior_r) +u8 h8_timer16_channel_device::tior_r() { return 0x00; } -WRITE8_MEMBER(h8_timer16_channel_device::tior_w) +void h8_timer16_channel_device::tior_w(offs_t offset, u8 data) { if(V>=1) logerror("tior_w %d, %02x\n", offset, data); } -void h8_timer16_channel_device::set_ier(uint8_t value) +void h8_timer16_channel_device::set_ier(u8 value) { update_counter(); - ier = value; + m_ier = value; recalc_event(); } void h8_timer16_channel_device::set_enable(bool enable) { update_counter(); - channel_active = enable; + m_channel_active = enable; recalc_event(); } -READ8_MEMBER(h8_timer16_channel_device::tier_r) +u8 h8_timer16_channel_device::tier_r() { - return tier; + return m_tier; } -WRITE8_MEMBER(h8_timer16_channel_device::tier_w) +void h8_timer16_channel_device::tier_w(u8 data) { update_counter(); if(V>=1) logerror("tier_w %02x\n", data); - tier = data; + m_tier = data; tier_update(); if(V>=1) logerror("irq %c%c%c%c%c%c trigger=%d\n", - ier & IRQ_A ? 'a' : '.', - ier & IRQ_B ? 'b' : '.', - ier & IRQ_C ? 'c' : '.', - ier & IRQ_D ? 'd' : '.', - ier & IRQ_V ? 'v' : '.', - ier & IRQ_U ? 'u' : '.', - ier & IRQ_TRIG ? 1 : 0); + m_ier & IRQ_A ? 'a' : '.', + m_ier & IRQ_B ? 'b' : '.', + m_ier & IRQ_C ? 'c' : '.', + m_ier & IRQ_D ? 'd' : '.', + m_ier & IRQ_V ? 'v' : '.', + m_ier & IRQ_U ? 'u' : '.', + m_ier & IRQ_TRIG ? 1 : 0); recalc_event(); } -READ8_MEMBER(h8_timer16_channel_device::tsr_r) +u8 h8_timer16_channel_device::tsr_r() { + if(!machine().side_effects_disabled()) + update_counter(); return isr_to_sr(); } -WRITE8_MEMBER(h8_timer16_channel_device::tsr_w) +void h8_timer16_channel_device::tsr_w(u8 data) { + update_counter(); if(V>=1) logerror("tsr_w %02x\n", data); isr_update(data); + recalc_event(); } -READ16_MEMBER(h8_timer16_channel_device::tcnt_r) +u16 h8_timer16_channel_device::tcnt_r() { - update_counter(); - return tcnt; + if(!machine().side_effects_disabled()) + update_counter(); + return m_tcnt; } -WRITE16_MEMBER(h8_timer16_channel_device::tcnt_w) +void h8_timer16_channel_device::tcnt_w(offs_t offset, u16 data, u16 mem_mask) { update_counter(); - COMBINE_DATA(&tcnt); - if(V>=1) logerror("tcnt_w %04x\n", tcnt); + COMBINE_DATA(&m_tcnt); + if(V>=1) logerror("tcnt_w %04x\n", m_tcnt); recalc_event(); } -READ16_MEMBER(h8_timer16_channel_device::tgr_r) +u16 h8_timer16_channel_device::tgr_r(offs_t offset) { - return tgr[offset]; + return m_tgr[offset]; } -WRITE16_MEMBER(h8_timer16_channel_device::tgr_w) +void h8_timer16_channel_device::tgr_w(offs_t offset, u16 data, u16 mem_mask) { update_counter(); - COMBINE_DATA(tgr + offset); - if(V>=1) logerror("tgr%c_w %04x\n", 'a'+offset, tgr[offset]); + COMBINE_DATA(m_tgr + offset); + if(V>=1) logerror("tgr%c_w %04x\n", 'a'+offset, m_tgr[offset]); recalc_event(); } -READ16_MEMBER(h8_timer16_channel_device::tbr_r) +u16 h8_timer16_channel_device::tbr_r(offs_t offset) { - return tgr[offset+tgr_count]; + return m_tgr[offset + m_tgr_count]; } -WRITE16_MEMBER(h8_timer16_channel_device::tbr_w) +void h8_timer16_channel_device::tbr_w(offs_t offset, u16 data, u16 mem_mask) { - COMBINE_DATA(tgr + offset + tgr_count); - if(V>=1) logerror("tbr%c_w %04x\n", 'a'+offset, tgr[offset]); + COMBINE_DATA(m_tgr + offset + m_tgr_count); + if(V>=1) logerror("tbr%c_w %04x\n", 'a'+offset, m_tgr[offset + m_tgr_count]); } void h8_timer16_channel_device::device_start() { - intc = owner()->siblingdevice<h8_intc_device>(intc_tag); - channel_active = false; + m_channel_active = false; device_reset(); - save_item(NAME(tgr_clearing)); - save_item(NAME(tcr)); - save_item(NAME(tier)); - save_item(NAME(ier)); - save_item(NAME(isr)); - save_item(NAME(clock_type)); - save_item(NAME(clock_divider)); - save_item(NAME(tcnt)); - save_item(NAME(tgr)); - save_item(NAME(last_clock_update)); - save_item(NAME(event_time)); - save_item(NAME(phase)); - save_item(NAME(counter_cycle)); - save_item(NAME(counter_incrementing)); - save_item(NAME(channel_active)); + save_item(NAME(m_tgr_clearing)); + save_item(NAME(m_tcr)); + save_item(NAME(m_tier)); + save_item(NAME(m_ier)); + save_item(NAME(m_isr)); + save_item(NAME(m_clock_type)); + save_item(NAME(m_clock_divider)); + save_item(NAME(m_tcnt)); + save_item(NAME(m_tgr)); + save_item(NAME(m_last_clock_update)); + save_item(NAME(m_event_time)); + save_item(NAME(m_phase)); + save_item(NAME(m_counter_cycle)); + save_item(NAME(m_counter_incrementing)); + save_item(NAME(m_channel_active)); } void h8_timer16_channel_device::device_reset() { - // Don't touch channel_active here, top level device handles it - tcr = 0; - tcnt = 0; - memset(tgr, 0xff, sizeof(tgr)); - tgr_clearing = TGR_CLEAR_NONE; - clock_type = DIV_1; - clock_divider = 0; - counter_cycle = 0x10000; - phase = 0; - tier = 0x40 & tier_mask; - ier = 0; - isr = 0; - last_clock_update = 0; - event_time = 0; - counter_incrementing = true; -} - -uint64_t h8_timer16_channel_device::internal_update(uint64_t current_time) -{ - if(event_time && current_time >= event_time) { - update_counter(current_time); - recalc_event(current_time); + // Don't touch channel_active here, top level device handles it. + m_tcr = 0; + m_tcnt = 0; + memset(m_tgr, 0xff, sizeof(m_tgr)); + m_tgr_clearing = TGR_CLEAR_NONE; + m_clock_type = DIV_1; + m_clock_divider = 0; + m_counter_cycle = 0x10000; + m_phase = 0; + m_tier = 0x40 & m_tier_mask; + m_ier = 0; + m_isr = 0; + m_last_clock_update = 0; + m_event_time = 0; + m_counter_incrementing = true; +} + +u64 h8_timer16_channel_device::internal_update(u64 current_time) +{ + while(m_event_time && current_time >= m_event_time) { + update_counter(m_event_time); + recalc_event(m_event_time); } - return event_time; + return m_event_time; +} + +void h8_timer16_channel_device::notify_standby(int state) +{ + if(!state && m_event_time) { + u64 delta = m_cpu->total_cycles() - m_cpu->standby_time(); + m_event_time += delta; + m_last_clock_update += delta; + } } -void h8_timer16_channel_device::update_counter(uint64_t cur_time) +void h8_timer16_channel_device::update_counter(u64 cur_time) { - if(clock_type != DIV_1) + if(m_clock_type != DIV_1) return; if(!cur_time) - cur_time = cpu->total_cycles(); + cur_time = m_cpu->total_cycles(); - if(!channel_active) { - last_clock_update = cur_time; + if(!m_channel_active) { + m_last_clock_update = cur_time; return; } - uint64_t base_time = last_clock_update; - uint64_t new_time = cur_time; - if(clock_divider) { - base_time = (base_time + phase) >> clock_divider; - new_time = (new_time + phase) >> clock_divider; + u64 base_time = m_last_clock_update; + m_last_clock_update = cur_time; + u64 new_time = cur_time; + if(m_clock_divider) { + base_time = (base_time + m_phase) >> m_clock_divider; + new_time = (new_time + m_phase) >> m_clock_divider; } - if(counter_incrementing) { - int tt = tcnt + new_time - base_time; - tcnt = tt % counter_cycle; - - for(int i=0; i<tgr_count; i++) - if((ier & (1 << i)) && (tt == tgr[i] || tcnt == tgr[i]) && interrupt[i] != -1) { - isr |= 1 << i; - intc->internal_interrupt(interrupt[i]); + if(new_time == base_time) + return; + + if(m_counter_incrementing) { + u16 prev = m_tcnt; + u64 delta = new_time - base_time; + u64 tt = m_tcnt + delta; + + if(prev >= m_counter_cycle) { + if(tt >= 0x10000) + m_tcnt = (tt - 0x10000) % m_counter_cycle; + else + m_tcnt = tt; + } else + m_tcnt = tt % m_counter_cycle; + + for(int i = 0; i < m_tgr_count; i++) { + u16 cmp = m_tgr[i] + 1; + bool match = m_tcnt == cmp || (tt == cmp && tt == m_counter_cycle); + if(!match) { + // Need to do additional checks here for software that polls the flags with interrupts disabled, since recalc_event only schedules IRQ events. + if(prev >= m_counter_cycle) + match = (cmp > prev && tt >= cmp) || (cmp <= m_counter_cycle && m_tcnt < m_counter_cycle && (delta - (0x10000 - prev)) >= cmp); + else if(cmp <= m_counter_cycle) + match = delta >= m_counter_cycle || (prev < cmp && tt >= cmp) || (m_tcnt <= prev && m_tcnt >= cmp); + + if(match && BIT(m_ier, i) && m_interrupt[i] != -1) + logerror("update_counter unexpected TGR %d IRQ\n, i"); + } + + if(match) { + m_isr |= 1 << i; + if(BIT(m_ier, i) && m_interrupt[i] != -1) + m_intc->internal_interrupt(m_interrupt[i]); } - if(tt >= 0x10000 && (ier & IRQ_V) && interrupt[4] != -1) { - isr |= IRQ_V; - intc->internal_interrupt(interrupt[4]); } - } else - tcnt = (((tcnt ^ 0xffff) + new_time - base_time) % counter_cycle) ^ 0xffff; - last_clock_update = cur_time; + if(tt >= 0x10000 && (m_counter_cycle == 0x10000 || prev >= m_counter_cycle)) { + m_isr |= IRQ_V; + if(m_ier & IRQ_V && m_interrupt[4] != -1) + m_intc->internal_interrupt(m_interrupt[4]); + } + } else { + logerror("decrementing counter\n"); + exit(1); + } } -void h8_timer16_channel_device::recalc_event(uint64_t cur_time) +void h8_timer16_channel_device::recalc_event(u64 cur_time) { - if(!channel_active) { - event_time = 0; + if(!m_channel_active) { + m_event_time = 0; return; } bool update_cpu = cur_time == 0; - uint64_t old_event_time = event_time; + u64 old_event_time = m_event_time; - if(clock_type != DIV_1) { - event_time = 0; + if(m_clock_type != DIV_1) { + m_event_time = 0; if(old_event_time && update_cpu) - cpu->internal_update(); + m_cpu->internal_update(); return; } if(!cur_time) - cur_time = cpu->total_cycles(); + cur_time = m_cpu->total_cycles(); - if(counter_incrementing) { - uint32_t event_delay = 0xffffffff; - if(tgr_clearing >= 0 && tgr[tgr_clearing]) - counter_cycle = tgr[tgr_clearing]; - else { - counter_cycle = 0x10000; - if(ier & IRQ_V) { - event_delay = counter_cycle - tcnt; - if(!event_delay) - event_delay = counter_cycle; - } - } - for(int i=0; i<tgr_count; i++) - if(ier & (1 << i)) { - uint32_t new_delay = 0xffffffff; - if(tgr[i] > tcnt) { - if(tcnt >= counter_cycle || tgr[i] <= counter_cycle) - new_delay = tgr[i] - tcnt; - } else if(tgr[i] <= counter_cycle) { - if(tcnt < counter_cycle) - new_delay = (counter_cycle - tcnt) + tgr[i]; + if(m_counter_incrementing) { + u32 event_delay = 0xffffffff; + if(m_tgr_clearing >= 0) + m_counter_cycle = m_tgr[m_tgr_clearing] + 1; + else + m_counter_cycle = 0x10000; + if((m_ier & IRQ_V && m_interrupt[4] != -1) && (m_counter_cycle == 0x10000 || m_tcnt >= m_counter_cycle)) + event_delay = 0x10000 - m_tcnt; + + for(int i = 0; i < m_tgr_count; i++) + if(BIT(m_ier, i) && m_interrupt[i] != -1) { + u32 new_delay = 0xffffffff; + u16 cmp = m_tgr[i] + 1; + if(cmp > m_tcnt) { + if(m_tcnt >= m_counter_cycle || cmp <= m_counter_cycle) + new_delay = cmp - m_tcnt; + } else if(cmp <= m_counter_cycle) { + if(m_tcnt < m_counter_cycle) + new_delay = (m_counter_cycle - m_tcnt) + cmp; else - new_delay = (0x10000 - tcnt) + tgr[i]; + new_delay = (0x10000 - m_tcnt) + cmp; } if(event_delay > new_delay) @@ -300,120 +354,108 @@ void h8_timer16_channel_device::recalc_event(uint64_t cur_time) } if(event_delay != 0xffffffff) - event_time = ((((cur_time + (1ULL << clock_divider) - phase) >> clock_divider) + event_delay - 1) << clock_divider) + phase; + m_event_time = ((((cur_time + (1ULL << m_clock_divider) - m_phase) >> m_clock_divider) + event_delay - 1) << m_clock_divider) + m_phase; else - event_time = 0; - + m_event_time = 0; } else { logerror("decrementing counter\n"); exit(1); } - if(old_event_time != event_time && update_cpu) - cpu->internal_update(); + if(old_event_time != m_event_time && update_cpu) + m_cpu->internal_update(); } -h8_timer16_device::h8_timer16_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, H8_TIMER16, tag, owner, clock), - cpu(*this, DEVICE_SELF_OWNER) -{ -} -void h8_timer16_device::set_info(int count, uint8_t tstr) +h8_timer16_device::h8_timer16_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + device_t(mconfig, H8_TIMER16, tag, owner, clock), + m_cpu(*this, finder_base::DUMMY_TAG), + m_timer_channel(*this, "%u", 0) { - timer_count = count; - default_tstr = tstr; } void h8_timer16_device::device_start() { - memset(timer_channel, 0, sizeof(timer_channel)); - for(int i=0; i<timer_count; i++) { - char tm[2]; - sprintf(tm, "%d", i); - timer_channel[i] = subdevice<h8_timer16_channel_device>(tm); - } - - save_item(NAME(tstr)); + save_item(NAME(m_tstr)); } -void h8_timer16_device::device_reset() +void h8_timer16_device::device_reset_after_children() { - tstr = default_tstr; - for(int i=0; i<timer_count; i++) - timer_channel[i]->set_enable((tstr >> i) & 1); + m_tstr = m_default_tstr; + for(int i = 0; i < m_timer_count; i++) + m_timer_channel[i]->set_enable((m_tstr >> i) & 1); } -READ8_MEMBER(h8_timer16_device::tstr_r) +u8 h8_timer16_device::tstr_r() { - return tstr; + return m_tstr; } -WRITE8_MEMBER(h8_timer16_device::tstr_w) +void h8_timer16_device::tstr_w(u8 data) { if(V>=1) logerror("tstr_w %02x\n", data); - tstr = data; - for(int i=0; i<timer_count; i++) - timer_channel[i]->set_enable((tstr >> i) & 1); + m_tstr = data; + for(int i = 0; i < m_timer_count; i++) + m_timer_channel[i]->set_enable((m_tstr >> i) & 1); } -READ8_MEMBER(h8_timer16_device::tsyr_r) +u8 h8_timer16_device::tsyr_r() { return 0x00; } -WRITE8_MEMBER(h8_timer16_device::tsyr_w) +void h8_timer16_device::tsyr_w(u8 data) { if(V>=1) logerror("tsyr_w %02x\n", data); } -READ8_MEMBER(h8_timer16_device::tmdr_r) +u8 h8_timer16_device::tmdr_r() { return 0x00; } -WRITE8_MEMBER(h8_timer16_device::tmdr_w) +void h8_timer16_device::tmdr_w(u8 data) { if(V>=1) logerror("tmdr_w %02x\n", data); } -READ8_MEMBER(h8_timer16_device::tfcr_r) +u8 h8_timer16_device::tfcr_r() { return 0x00; } -WRITE8_MEMBER(h8_timer16_device::tfcr_w) +void h8_timer16_device::tfcr_w(u8 data) { if(V>=1) logerror("tfcr_w %02x\n", data); } -READ8_MEMBER(h8_timer16_device::toer_r) +u8 h8_timer16_device::toer_r() { return 0x00; } -WRITE8_MEMBER(h8_timer16_device::toer_w) +void h8_timer16_device::toer_w(u8 data) { if(V>=1) logerror("toer_w %02x\n", data); } -READ8_MEMBER(h8_timer16_device::tocr_r) +u8 h8_timer16_device::tocr_r() { return 0x00; } -WRITE8_MEMBER(h8_timer16_device::tocr_w) +void h8_timer16_device::tocr_w(u8 data) { if(V>=1) logerror("tocr_w %02x\n", data); } -READ8_MEMBER(h8_timer16_device::tisr_r) +u8 h8_timer16_device::tisr_r(offs_t offset) { - uint8_t r = 0; - for(int i=0; i<timer_count; i++) - r |= timer_channel[i]->tisr_r(offset) << i; - for(int i=timer_count; i<4; i++) + u8 r = 0; + for(int i = 0; i < m_timer_count; i++) + r |= m_timer_channel[i]->tisr_r(offset) << i; + for(int i = m_timer_count; i < 4; i++) r |= 0x11 <<i; if(V>=1) logerror("tisr%c_r %02x\n", 'a'+offset, r); @@ -421,39 +463,38 @@ READ8_MEMBER(h8_timer16_device::tisr_r) return r; } -WRITE8_MEMBER(h8_timer16_device::tisr_w) +void h8_timer16_device::tisr_w(offs_t offset, u8 data) { if(V>=1) logerror("tisr%c_w %02x\n", 'a'+offset, data); - for(int i=0; i<timer_count; i++) - timer_channel[i]->tisr_w(offset, data >> i); + for(int i = 0; i < m_timer_count; i++) + m_timer_channel[i]->tisr_w(offset, data >> i); } -READ8_MEMBER(h8_timer16_device::tisrc_r) +u8 h8_timer16_device::tisrc_r() { - return tisr_r(space, 2, mem_mask); + return tisr_r(2); } -WRITE8_MEMBER(h8_timer16_device::tisrc_w) +void h8_timer16_device::tisrc_w(u8 data) { - tisr_w(space, 2, data, mem_mask); + tisr_w(2, data); } -WRITE8_MEMBER(h8_timer16_device::tolr_w) +void h8_timer16_device::tolr_w(u8 data) { if(V>=1) logerror("tocr_w %02x\n", data); } - void h8_timer16_channel_device::tier_update() { } -void h8_timer16_channel_device::isr_update(uint8_t val) +void h8_timer16_channel_device::isr_update(u8 val) { } -uint8_t h8_timer16_channel_device::isr_to_sr() const +u8 h8_timer16_channel_device::isr_to_sr() const { return 0x00; } @@ -462,278 +503,323 @@ void h8_timer16_channel_device::tcr_update() { } -void h8_timer16_channel_device::tisr_w(int offset, uint8_t value) +void h8_timer16_channel_device::tisr_w(int offset, u8 value) { update_counter(); if(!(value & 0x01)) { switch(offset) { case 0: - isr &= ~IRQ_A; + m_isr &= ~IRQ_A; break; case 1: - isr &= ~IRQ_B; + m_isr &= ~IRQ_B; break; case 2: - isr &= ~IRQ_V; + m_isr &= ~IRQ_V; break; } } if(value & 0x10) { switch(offset) { case 0: - ier |= IRQ_A; + m_ier |= IRQ_A; break; case 1: - ier |= IRQ_B; + m_ier |= IRQ_B; break; case 2: - ier |= IRQ_V; + m_ier |= IRQ_V; break; } } else { switch(offset) { case 0: - ier &= ~IRQ_A; + m_ier &= ~IRQ_A; break; case 1: - ier &= ~IRQ_B; + m_ier &= ~IRQ_B; break; case 2: - ier &= ~IRQ_V; + m_ier &= ~IRQ_V; break; } } recalc_event(); } -uint8_t h8_timer16_channel_device::tisr_r(int offset) const +u8 h8_timer16_channel_device::tisr_r(int offset) const { switch(offset) { case 0: - return ((ier & IRQ_A) ? 0x10 : 0x00) | ((isr & IRQ_A) ? 0x01 : 0x00); + return ((m_ier & IRQ_A) ? 0x10 : 0x00) | ((m_isr & IRQ_A) ? 0x01 : 0x00); case 1: - return ((ier & IRQ_B) ? 0x10 : 0x00) | ((isr & IRQ_B) ? 0x01 : 0x00); + return ((m_ier & IRQ_B) ? 0x10 : 0x00) | ((m_isr & IRQ_B) ? 0x01 : 0x00); case 2: - return ((ier & IRQ_V) ? 0x10 : 0x00) | ((isr & IRQ_V) ? 0x01 : 0x00); + return ((m_ier & IRQ_V) ? 0x10 : 0x00) | ((m_isr & IRQ_V) ? 0x01 : 0x00); } return 0x00; } -h8h_timer16_channel_device::h8h_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - h8_timer16_channel_device(mconfig, H8H_TIMER16_CHANNEL, tag, owner, clock) + +// H8/325 + +h8325_timer16_channel_device::h8325_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + h8_timer16_channel_device(mconfig, H8325_TIMER16_CHANNEL, tag, owner, clock), + m_tcsr(0) { } -h8h_timer16_channel_device::~h8h_timer16_channel_device() +h8325_timer16_channel_device::~h8325_timer16_channel_device() { } -void h8h_timer16_channel_device::set_info(int _tgr_count, int _tbr_count, const char *intc, int irq_base) +void h8325_timer16_channel_device::device_start() { - tgr_count = _tgr_count; - tbr_count = _tbr_count; - intc_tag = intc; + h8_timer16_channel_device::device_start(); - interrupt[0] = irq_base++; - interrupt[1] = irq_base++; - interrupt[2] = -1; - interrupt[3] = -1; - interrupt[4] = irq_base; - interrupt[5] = irq_base; + save_item(NAME(m_tcsr)); +} + +void h8325_timer16_channel_device::device_reset() +{ + h8_timer16_channel_device::device_reset(); + + m_tcsr = 0; + m_clock_divider = 1; +} + +void h8325_timer16_channel_device::tcr_update() +{ + m_ier = + (m_tcr & 0x10 ? IRQ_V : 0) | + (m_tcr & 0x20 ? IRQ_A : 0) | + (m_tcr & 0x40 ? IRQ_B : 0) | + (m_tcr & 0x80 ? IRQ_C : 0); + + m_clock_type = DIV_1; + m_clock_divider = 0; + + switch (m_tcr & 3) { + case 0: // /2 + m_clock_divider = 1; + break; + case 1: // /8 + m_clock_divider = 3; + break; + case 2: // /32 + m_clock_divider = 5; + break; + case 3: // TODO: external + m_clock_type = -1; + break; + } +} + +void h8325_timer16_channel_device::isr_update(u8 val) +{ + m_tcsr = val; + + if(val & 1) + m_tgr_clearing = 0; + else + m_tgr_clearing = TGR_CLEAR_NONE; + + if(!(val & 0x10)) + m_isr &= ~IRQ_V; + if(!(val & 0x20)) + m_isr &= ~IRQ_A; + if(!(val & 0x40)) + m_isr &= ~IRQ_B; + if(!(val & 0x80)) + m_isr &= ~IRQ_C; +} + +u8 h8325_timer16_channel_device::isr_to_sr() const +{ + return (m_tcsr & 0x0f) | + (m_isr & IRQ_V ? 0x10 : 0) | + (m_isr & IRQ_A ? 0x20 : 0) | + (m_isr & IRQ_B ? 0x40 : 0) | + (m_isr & IRQ_C ? 0x80 : 0); +} + + +// H8H + +h8h_timer16_channel_device::h8h_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + h8_timer16_channel_device(mconfig, H8H_TIMER16_CHANNEL, tag, owner, clock) +{ +} + +h8h_timer16_channel_device::~h8h_timer16_channel_device() +{ } void h8h_timer16_channel_device::tier_update() { - tier = tier | 0xf8; - ier = - (tier & 0x01 ? IRQ_A : 0) | - (tier & 0x02 ? IRQ_B : 0) | - (tier & 0x04 ? IRQ_V : 0); + m_tier = m_tier | 0xf8; + m_ier = + (m_tier & 0x01 ? IRQ_A : 0) | + (m_tier & 0x02 ? IRQ_B : 0) | + (m_tier & 0x04 ? IRQ_V : 0); } -void h8h_timer16_channel_device::isr_update(uint8_t val) +void h8h_timer16_channel_device::isr_update(u8 val) { if(!(val & 1)) - isr &= ~IRQ_A; + m_isr &= ~IRQ_A; if(!(val & 2)) - isr &= ~IRQ_B; + m_isr &= ~IRQ_B; if(!(val & 4)) - isr &= ~IRQ_V; + m_isr &= ~IRQ_V; } -uint8_t h8h_timer16_channel_device::isr_to_sr() const +u8 h8h_timer16_channel_device::isr_to_sr() const { - return 0xf8 | (isr & IRQ_V ? 4 : 0) | (isr & IRQ_B ? 2 : 0) | (isr & IRQ_A ? 1 : 0); + return 0xf8 | (m_isr & IRQ_V ? 4 : 0) | (m_isr & IRQ_B ? 2 : 0) | (m_isr & IRQ_A ? 1 : 0); } void h8h_timer16_channel_device::tcr_update() { - switch(tcr & 0x60) { + switch(m_tcr & 0x60) { case 0x00: - tgr_clearing = TGR_CLEAR_NONE; + m_tgr_clearing = TGR_CLEAR_NONE; if(V>=1) logerror("No automatic tcnt clearing\n"); break; case 0x20: case 0x40: { - tgr_clearing = tcr & 0x20 ? 0 : 1; - if(V>=1) logerror("Auto-clear on tgr%c (%04x)\n", 'a'+tgr_clearing, tgr[tgr_clearing]); + m_tgr_clearing = m_tcr & 0x20 ? 0 : 1; + if(V>=1) logerror("Auto-clear on tgr%c (%04x)\n", 'a'+m_tgr_clearing, m_tgr[m_tgr_clearing]); break; } case 0x60: - tgr_clearing = TGR_CLEAR_EXT; + m_tgr_clearing = TGR_CLEAR_EXT; if(V>=1) logerror("External sync clear\n"); break; } - int count_type = tcr & 7; + int count_type = m_tcr & 7; if(count_type < 4) { - clock_type = DIV_1; - clock_divider = count_type; - if(V>=1) logerror("clock divider %d (%d)\n", clock_divider, 1 << clock_divider); + m_clock_type = DIV_1; + m_clock_divider = count_type; + if(V>=1) logerror("clock divider %d (%d)\n", m_clock_divider, 1 << m_clock_divider); if(count_type <= DIV_2) - phase = 0; + m_phase = 0; else { - switch(tcr & 0x18) { + switch(m_tcr & 0x18) { case 0x00: - phase = 0; + m_phase = 0; if(V>=1) logerror("Phase 0\n"); break; case 0x08: - phase = 1 << (clock_divider-1); + m_phase = 1 << (m_clock_divider-1); if(V>=1) logerror("Phase 180\n"); break; case 0x10: case 0x18: - phase = 0; - clock_divider--; + m_phase = 0; + m_clock_divider--; if(V>=1) logerror("Phase 0+180\n"); break; } } } else { - clock_type = INPUT_A + (count_type-4); - clock_divider = 0; - phase = 0; + m_clock_type = INPUT_A + (count_type-4); + m_clock_divider = 0; + m_phase = 0; if(V>=1) logerror("counting input %c\n", 'a'+count_type-INPUT_A); } } -h8s_timer16_channel_device::h8s_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - h8_timer16_channel_device(mconfig, H8S_TIMER16_CHANNEL, tag, owner, clock) -{ -} -h8s_timer16_channel_device::~h8s_timer16_channel_device() -{ -} +// H8S -void h8s_timer16_channel_device::set_chain(const char *_chain_tag) +h8s_timer16_channel_device::h8s_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + h8_timer16_channel_device(mconfig, H8S_TIMER16_CHANNEL, tag, owner, clock) { - chain_tag = _chain_tag; } -void h8s_timer16_channel_device::set_info(int _tgr_count, uint8_t _tier_mask, const char *intc, int irq_base, - int t0, int t1, int t2, int t3, int t4, int t5, int t6, int t7) +h8s_timer16_channel_device::~h8s_timer16_channel_device() { - tgr_count = _tgr_count; - tbr_count = 0; - tier_mask = _tier_mask; - intc_tag = intc; - - interrupt[0] = irq_base++; - interrupt[1] = irq_base++; - interrupt[2] = tier_mask & 0x04 ? -1 : irq_base++; - interrupt[3] = tier_mask & 0x08 ? -1 : irq_base++; - interrupt[4] = irq_base; - interrupt[5] = tier_mask & 0x20 ? -1 : irq_base++; - - count_types[0] = t0; - count_types[1] = t1; - count_types[2] = t2; - count_types[3] = t3; - count_types[4] = t4; - count_types[5] = t5; - count_types[6] = t6; - count_types[7] = t7; } void h8s_timer16_channel_device::tier_update() { - tier = (tier & ~tier_mask) | 0x40; - ier = - (tier & 0x01 ? IRQ_A : 0) | - (tier & 0x02 ? IRQ_B : 0) | - (tier & 0x04 ? IRQ_C : 0) | - (tier & 0x08 ? IRQ_D : 0) | - (tier & 0x10 ? IRQ_V : 0) | - (tier & 0x20 ? IRQ_U : 0) | - (tier & 0x80 ? IRQ_TRIG : 0); + m_tier = (m_tier & ~m_tier_mask) | 0x40; + m_ier = + (m_tier & 0x01 ? IRQ_A : 0) | + (m_tier & 0x02 ? IRQ_B : 0) | + (m_tier & 0x04 ? IRQ_C : 0) | + (m_tier & 0x08 ? IRQ_D : 0) | + (m_tier & 0x10 ? IRQ_V : 0) | + (m_tier & 0x20 ? IRQ_U : 0) | + (m_tier & 0x80 ? IRQ_TRIG : 0); } -void h8s_timer16_channel_device::isr_update(uint8_t val) +void h8s_timer16_channel_device::isr_update(u8 val) { - isr &= (val | tier_mask | 0xc0); + m_isr &= (val | m_tier_mask | 0xc0); } -uint8_t h8s_timer16_channel_device::isr_to_sr() const +u8 h8s_timer16_channel_device::isr_to_sr() const { - return 0xc0 | isr; + return 0xc0 | m_isr; } void h8s_timer16_channel_device::tcr_update() { - switch(tcr & 0x60) { + switch(m_tcr & 0x60) { case 0x00: - tgr_clearing = TGR_CLEAR_NONE; + m_tgr_clearing = TGR_CLEAR_NONE; if(V>=1) logerror("No automatic tcnt clearing\n"); break; case 0x20: case 0x40: { - tgr_clearing = tcr & 0x20 ? 0 : 1; - if(tgr_count > 2 && (tcr & 0x80)) - tgr_clearing += 2; - if(V>=1) logerror("Auto-clear on tgr%c\n", 'a'+tgr_clearing); + m_tgr_clearing = m_tcr & 0x20 ? 0 : 1; + if(m_tgr_count > 2 && (m_tcr & 0x80)) + m_tgr_clearing += 2; + if(V>=1) logerror("Auto-clear on tgr%c\n", 'a'+m_tgr_clearing); break; } case 0x60: - tgr_clearing = TGR_CLEAR_EXT; + m_tgr_clearing = TGR_CLEAR_EXT; if(V>=1) logerror("External sync clear\n"); break; } - int count_type = count_types[tcr & 7]; - if(count_type >= DIV_1 && clock_type <= DIV_4) { - clock_type = DIV_1; - clock_divider = count_type - DIV_1; - if(V>=1) logerror("clock divider %d (%d)\n", clock_divider, 1 << clock_divider); - if(!clock_divider) - phase = 0; + int count_type = m_count_types[m_tcr & 7]; + if(count_type >= DIV_1 && m_clock_type <= DIV_4) { + m_clock_type = DIV_1; + m_clock_divider = count_type - DIV_1; + if(V>=1) logerror("clock divider %d (%d)\n", m_clock_divider, 1 << m_clock_divider); + if(!m_clock_divider) + m_phase = 0; else { - switch(tcr & 0x18) { + switch(m_tcr & 0x18) { case 0x00: - phase = 0; + m_phase = 0; if(V>=1) logerror("Phase 0\n"); break; case 0x08: - phase = 1 << (clock_divider-1); + m_phase = 1 << (m_clock_divider-1); if(V>=1) logerror("Phase 180\n"); break; case 0x10: case 0x18: - phase = 0; - clock_divider--; + m_phase = 0; + m_clock_divider--; if(V>=1) logerror("Phase 0+180\n"); break; } } } else if(count_type == CHAIN) { - clock_type = CHAIN; - clock_divider = 0; - phase = 0; + m_clock_type = CHAIN; + m_clock_divider = 0; + m_phase = 0; if(V>=1) logerror("chained timer\n"); } else if(count_type >= INPUT_A && count_type <= INPUT_D) { - clock_type = count_type; - clock_divider = 0; - phase = 0; + m_clock_type = count_type; + m_clock_divider = 0; + m_phase = 0; if(V>=1) logerror("counting input %c\n", 'a'+count_type-INPUT_A); } } |