summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/sh/sh2comn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/sh/sh2comn.cpp')
-rw-r--r--src/devices/cpu/sh/sh2comn.cpp53
1 files changed, 52 insertions, 1 deletions
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;