summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/h8/h8_timer16.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/h8/h8_timer16.cpp')
-rw-r--r--src/devices/cpu/h8/h8_timer16.cpp768
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);
}
}