// license:BSD-3-Clause // copyright-holders:Aaron Giles /*************************************************************************** watchdog.c Watchdog timer device. ***************************************************************************/ #include "emu.h" #include "watchdog.h" #include "emuopts.h" #include "screen.h" //************************************************************************** // WATCHDOG TIMER DEVICE //************************************************************************** DEFINE_DEVICE_TYPE(WATCHDOG_TIMER, watchdog_timer_device, "watchdog", "Watchdog Timer") //------------------------------------------------- // watchdog_timer_device - constructor //------------------------------------------------- watchdog_timer_device::watchdog_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, WATCHDOG_TIMER, tag, owner, clock) , m_vblank_count(0) , m_time(attotime::zero) , m_screen_tag(nullptr) { } //------------------------------------------------- // device_validity_check - validate the device // configuration //------------------------------------------------- void watchdog_timer_device::device_validity_check(validity_checker &valid) const { if (m_vblank_count != 0) { screen_device *screen = dynamic_cast(siblingdevice(m_screen_tag)); if (screen == nullptr) osd_printf_error("Invalid screen tag specified\n"); } } //------------------------------------------------- // device_start - perform device-specific // startup //------------------------------------------------- void watchdog_timer_device::device_start() { // initialize the watchdog m_counter = 0; m_timer = timer_alloc(); if (m_vblank_count != 0) { // fetch the screen screen_device *screen = siblingdevice(m_screen_tag); if (screen != nullptr) screen->register_vblank_callback(vblank_state_delegate(&watchdog_timer_device::watchdog_vblank, this)); } save_item(NAME(m_enabled)); save_item(NAME(m_counter)); } //------------------------------------------------- // device_reset - reset the device //------------------------------------------------- void watchdog_timer_device::device_reset() { // set up the watchdog timer; only start off enabled if explicitly configured m_enabled = (m_vblank_count != 0 || m_time != attotime::zero); watchdog_reset(); m_enabled = true; } //------------------------------------------------- // device_timer - handle timer expiration events //------------------------------------------------- void watchdog_timer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { watchdog_fired(); } //------------------------------------------------- // watchdog_reset - reset the watchdog timer //------------------------------------------------- void watchdog_timer_device::watchdog_reset() { // if we're not enabled, skip it if (!m_enabled) m_timer->adjust(attotime::never); // VBLANK-based watchdog? else if (m_vblank_count != 0) m_counter = m_vblank_count; // timer-based watchdog? else if (m_time != attotime::zero) m_timer->adjust(m_time); // default to an obscene amount of time (3 seconds) else m_timer->adjust(attotime::from_seconds(3)); } //------------------------------------------------- // watchdog_enable - reset the watchdog timer //------------------------------------------------- void watchdog_timer_device::watchdog_enable(bool enable) { // when re-enabled, we reset our state if (m_enabled != enable) { m_enabled = enable; watchdog_reset(); } } //------------------------------------------------- // watchdog_fired - trigger machine reset //------------------------------------------------- void watchdog_timer_device::watchdog_fired() { logerror("Reset caused by the watchdog!!!\n"); bool verbose = machine().options().verbose(); #ifdef MAME_DEBUG verbose = true; #endif if (verbose) popmessage("Reset caused by the watchdog!!!\n"); machine().schedule_soft_reset(); } //------------------------------------------------- // watchdog_vblank - VBLANK state callback for // watchdog timers //------------------------------------------------- void watchdog_timer_device::watchdog_vblank(screen_device &screen, bool vblank_state) { // VBLANK starting if (vblank_state && m_enabled) { // check the watchdog if (m_vblank_count != 0) if (--m_counter == 0) watchdog_fired(); } } //************************************************************************** // WATCHDOG READ/WRITE HELPERS //************************************************************************** //------------------------------------------------- // 8-bit reset read/write handlers //------------------------------------------------- WRITE8_MEMBER( watchdog_timer_device::reset_w ) { watchdog_reset(); } READ8_MEMBER( watchdog_timer_device::reset_r ) { watchdog_reset(); return space.unmap(); } //------------------------------------------------- // 16-bit reset read/write handlers //------------------------------------------------- WRITE16_MEMBER( watchdog_timer_device::reset16_w ) { watchdog_reset(); } READ16_MEMBER( watchdog_timer_device::reset16_r ) { watchdog_reset(); return space.unmap(); } //------------------------------------------------- // 32-bit reset read/write handlers //------------------------------------------------- WRITE32_MEMBER( watchdog_timer_device::reset32_w ) { watchdog_reset(); } READ32_MEMBER( watchdog_timer_device::reset32_r ) { watchdog_reset(); return space.unmap(); }