diff options
author | 2019-11-07 10:25:21 +0200 | |
---|---|---|
committer | 2019-11-07 10:25:21 +0200 | |
commit | 80aa59a46e4da52fce22bc4bf9c07f6baa497d36 (patch) | |
tree | a8ef0bbf1fb2688de8787a0076cd49378a3a5180 /src/devices/cpu/sh | |
parent | 9404607605f82e64af0933123b800ce46b604aa5 (diff) |
sh2: implement watchdog timer
Diffstat (limited to 'src/devices/cpu/sh')
-rw-r--r-- | src/devices/cpu/sh/sh2.cpp | 2 | ||||
-rw-r--r-- | src/devices/cpu/sh/sh2.h | 4 | ||||
-rw-r--r-- | src/devices/cpu/sh/sh2comn.cpp | 53 |
3 files changed, 58 insertions, 1 deletions
diff --git a/src/devices/cpu/sh/sh2.cpp b/src/devices/cpu/sh/sh2.cpp index b9be01f3c7e..eddf593b2db 100644 --- a/src/devices/cpu/sh/sh2.cpp +++ b/src/devices/cpu/sh/sh2.cpp @@ -515,6 +515,8 @@ void sh2_device::device_start() m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_timer_callback), this)); m_timer->adjust(attotime::never); + m_wdtimer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_wdtimer_callback), this)); + m_wdtimer->adjust(attotime::never); m_dma_current_active_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_dma_current_active_callback), this)); m_dma_current_active_timer[0]->adjust(attotime::never); diff --git a/src/devices/cpu/sh/sh2.h b/src/devices/cpu/sh/sh2.h index fd4e9c01bcd..a83bea94646 100644 --- a/src/devices/cpu/sh/sh2.h +++ b/src/devices/cpu/sh/sh2.h @@ -302,6 +302,7 @@ private: int m_internal_irq_vector; emu_timer *m_timer; + emu_timer *m_wdtimer; emu_timer *m_dma_current_active_timer[2]; int m_dma_timer_active[2]; uint8_t m_dma_irq[2]; @@ -339,9 +340,12 @@ private: virtual void execute_one_f000(uint16_t opcode) override; TIMER_CALLBACK_MEMBER( sh2_timer_callback ); + TIMER_CALLBACK_MEMBER( sh2_wdtimer_callback ); TIMER_CALLBACK_MEMBER( sh2_dma_current_active_callback ); void sh2_timer_resync(); void sh2_timer_activate(); + void sh2_wtcnt_recalc(); + void sh2_wdt_activate(); void sh2_do_dma(int dmach); virtual void sh2_exception(const char *message, int irqline) override; void sh2_dmac_check(int dma); diff --git a/src/devices/cpu/sh/sh2comn.cpp b/src/devices/cpu/sh/sh2comn.cpp index bb17a818c17..fc39aacd1f0 100644 --- a/src/devices/cpu/sh/sh2comn.cpp +++ b/src/devices/cpu/sh/sh2comn.cpp @@ -18,6 +18,7 @@ #include "logmacro.h" static const int div_tab[4] = { 3, 5, 7, 0 }; +static const int wdtclk_tab[8] = { 1, 6, 7, 8, 9, 10, 12, 13 }; void sh2_device::sh2_timer_resync() @@ -100,6 +101,32 @@ TIMER_CALLBACK_MEMBER( sh2_device::sh2_timer_callback ) sh2_timer_activate(); } +void sh2_device::sh2_wtcnt_recalc() +{ + if (m_wdtimer->expire() != attotime::never) + m_wtcnt = 0x100 - (attotime_to_cycles(m_wdtimer->remaining()) >> wdtclk_tab[m_wtcsr & 7]); +} + +void sh2_device::sh2_wdt_activate() +{ + m_wdtimer->adjust(cycles_to_attotime((0x100 - m_wtcnt) << wdtclk_tab[m_wtcsr & 7])); +} + +TIMER_CALLBACK_MEMBER(sh2_device::sh2_wdtimer_callback) +{ + m_wtcnt = 0; + if (!(m_wtcsr & 0x40)) // timer mode + { + m_wtcsr |= 0x80; + sh2_recalc_irq(); + sh2_wdt_activate(); + } + else // watchdog mode + { + m_rstcsr |= 0x80; + // TODO reset and /WDTOVF out + } +} /* We have to do DMA on a timer (or at least, in chunks) due to the way some systems use it. @@ -841,6 +868,7 @@ WRITE32_MEMBER( sh2_device::dvdntl_w ) READ16_MEMBER( sh2_device::wtcnt_r ) { + sh2_wtcnt_recalc(); return ((m_wtcsr | 0x18) << 8) | (m_wtcnt & 0xff); } @@ -856,6 +884,8 @@ WRITE16_MEMBER( sh2_device::wtcnt_w ) { case 0x5a00: m_wtcnt = m_wtcw[0] & 0xff; + if (m_wtcsr & 0x20) + sh2_wdt_activate(); break; case 0xa500: /* @@ -866,7 +896,17 @@ WRITE16_MEMBER( sh2_device::wtcnt_w ) ---1 1--- ---- -xxx Clock select */ - m_wtcsr = m_wtcw[0] & 0xff; + sh2_wtcnt_recalc(); + m_wtcsr &= m_wtcw[0] & 0x80; + m_wtcsr |= m_wtcw[0] & 0x7f; + if (m_wtcsr & 0x20) + sh2_wdt_activate(); + else + { + m_wtcnt = 0; + m_wdtimer->adjust(attotime::never); + } + sh2_recalc_irq(); break; } } @@ -1049,6 +1089,17 @@ void sh2_device::sh2_recalc_irq() } } + // WDT irqs + if (m_wtcsr & 0x80) + { + level = m_irq_level.wdt & 15; + if (level > irq) + { + irq = level; + vector = (m_vcrwdt >> 8) & 0x7f; + } + } + // DMA irqs if((m_dmac[0].chcr & 6) == 6 && m_dma_irq[0]) { level = m_irq_level.dmac & 15; |