From 009f31fae2e6df9b7eb0c505a09008ea718f1a45 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Thu, 20 Jul 2023 11:31:31 +0700 Subject: dp8573: add dp8572a variant --- scripts/src/machine.lua | 8 +- src/devices/machine/dp8573.cpp | 358 ----------------------------- src/devices/machine/dp8573.h | 154 ------------- src/devices/machine/dp8573a.cpp | 486 ++++++++++++++++++++++++++++++++++++++++ src/devices/machine/dp8573a.h | 73 ++++++ src/mame/sgi/4dpi.cpp | 14 +- src/mame/sgi/hpc1.cpp | 2 +- src/mame/sgi/hpc1.h | 4 +- 8 files changed, 573 insertions(+), 526 deletions(-) delete mode 100644 src/devices/machine/dp8573.cpp delete mode 100644 src/devices/machine/dp8573.h create mode 100644 src/devices/machine/dp8573a.cpp create mode 100644 src/devices/machine/dp8573a.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 3dd4eef38ab..824fce923ff 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -4185,13 +4185,13 @@ end --------------------------------------------------- -- ---@src/devices/machine/dp8573.h,MACHINES["DP8573"] = true +--@src/devices/machine/dp8573a.h,MACHINES["DP8573A"] = true --------------------------------------------------- -if (MACHINES["DP8573"]~=null) then +if (MACHINES["DP8573A"]~=null) then files { - MAME_DIR .. "src/devices/machine/dp8573.cpp", - MAME_DIR .. "src/devices/machine/dp8573.h", + MAME_DIR .. "src/devices/machine/dp8573a.cpp", + MAME_DIR .. "src/devices/machine/dp8573a.h", } end diff --git a/src/devices/machine/dp8573.cpp b/src/devices/machine/dp8573.cpp deleted file mode 100644 index 32e03645b64..00000000000 --- a/src/devices/machine/dp8573.cpp +++ /dev/null @@ -1,358 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -/*************************************************************************** - - DP8573 Real Time Clock (RTC) - -***************************************************************************/ - -#include "emu.h" -#include "machine/dp8573.h" - -#include "machine/timehelp.h" - -#include -#include - -#define LOG_TICKS (1U << 1) -#define LOG_ALL (LOG_GENERAL | LOG_TICKS) - -#define VERBOSE (0) -#include "logmacro.h" - -// device type definition -DEFINE_DEVICE_TYPE(DP8573, dp8573_device, "dp8573", "DP8573 Real-Time Clock") - -dp8573_device::dp8573_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, DP8573, tag, owner, clock) - , device_nvram_interface(mconfig, *this) - , device_rtc_interface(mconfig, *this) - , m_intr_cb(*this) - , m_mfo_cb(*this) -{ -} - -void dp8573_device::device_start() -{ - save_item(NAME(m_ram)); - save_item(NAME(m_tscr)); - save_item(NAME(m_pfr)); - save_item(NAME(m_millis)); - - m_timer = timer_alloc(FUNC(dp8573_device::msec_tick), this); - m_timer->adjust(attotime::never); - - std::fill(std::begin(m_ram), std::end(m_ram), 0); - - m_tscr = 0; - - m_timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1)); -} - -void dp8573_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) -{ - m_millis = 0; - m_ram[REG_HUNDREDTH] = 0; - m_ram[REG_SECOND] = time_helper::make_bcd(second); - m_ram[REG_MINUTE] = time_helper::make_bcd(minute); - m_ram[REG_HOUR] = time_helper::make_bcd(hour); - m_ram[REG_DAY] = time_helper::make_bcd(day); - m_ram[REG_MONTH] = time_helper::make_bcd(month); - m_ram[REG_YEAR] = time_helper::make_bcd(year); - m_ram[REG_DAYOFWEEK] = time_helper::make_bcd(day_of_week); - - m_pfr = 0; - - // FIXME: should probably rely on nvram start/stop state - m_ram[REG_RTMR] = RTMR_CSS; -} - -void dp8573_device::save_registers() -{ - m_ram[REG_SAVE_SECOND] = m_ram[REG_SECOND]; - m_ram[REG_SAVE_MINUTE] = m_ram[REG_MINUTE]; - m_ram[REG_SAVE_HOUR] = m_ram[REG_HOUR]; - m_ram[REG_SAVE_DAY] = m_ram[REG_DAY]; - m_ram[REG_SAVE_MONTH] = m_ram[REG_MONTH]; -} - -TIMER_CALLBACK_MEMBER(dp8573_device::msec_tick) -{ - if ((m_pfr & PFR_OSF) || !(m_ram[REG_RTMR] & RTMR_CSS)) - { - LOGMASKED(LOG_TICKS, "Tick suppressed due to OSF or !CSS\n"); - return; - } - - m_pfr |= PFR_1MS; - - bool carry = false; - bool tens_carry = false; - time_helper::inc_bcd(&m_millis, 0xff, 0x00, 0x09, &tens_carry); - if (tens_carry) - { - m_pfr |= PFR_10MS; - carry = time_helper::inc_bcd(&m_ram[REG_HUNDREDTH], 0xff, 0x00, 0x99, &tens_carry); - if (tens_carry) - m_pfr |= PFR_100MS; - } - if (carry) - { - m_pfr |= PFR_1S; - carry = time_helper::inc_bcd(&m_ram[REG_SECOND], 0xff, 0x00, 0x59, &tens_carry); - if (tens_carry) - m_pfr |= PFR_10S; - } - if (carry) - { - m_pfr |= PFR_1MIN; - carry = time_helper::inc_bcd(&m_ram[REG_MINUTE], 0xff, 0x00, 0x59); - } - if (carry) - { - if (m_ram[REG_RTMR] & RTMR_12H) - { - carry = time_helper::inc_bcd(&m_ram[REG_HOUR], 0xff, 0x01, 0x12); - if (carry) - { - m_ram[REG_HOUR] |= 0x20; - carry = !(m_ram[REG_HOUR] & 0x20); - } - } - else - { - carry = time_helper::inc_bcd(&m_ram[REG_HOUR], 0xff, 0x00, 0x23); - } - } - if (carry) - { - static const uint8_t daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; - - time_helper::inc_bcd(&m_ram[REG_DAYOFWEEK], 0xff, 0x01, 0x07); - - uint8_t month = time_helper::from_bcd(m_ram[REG_MONTH]); - - uint8_t maxdays; - if (month == 2 && (m_ram[REG_RTMR] & RTMR_LY) == 0) - { - maxdays = 0x29; - } - else if (month >= 1 && month <= 12) - { - maxdays = daysinmonth[month - 1]; - } - else - { - maxdays = 0x31; - } - - carry = time_helper::inc_bcd(&m_ram[REG_DAY], 0xff, 0x01, maxdays); - } - if (carry) - { - carry = time_helper::inc_bcd(&m_ram[REG_MONTH], 0xff, 0x01, 0x12); - } - if (carry) - { - carry = time_helper::inc_bcd(&m_ram[REG_YEAR], 0xff, 0x00, 0x99); - } - if (carry) - { - // Advance the leap-year counter - uint8_t leap = m_ram[REG_RTMR] & RTMR_LY; - leap = (leap + 1) & RTMR_LY; - m_ram[REG_RTMR] &= ~RTMR_LY; - m_ram[REG_RTMR] |= leap; - } - - // Check for Time Save mode - if (m_tscr & TSCR_TS) - { - save_registers(); - } - - // Check for periodic interrupts - const uint8_t icr0 = m_ram[REG_PFR_ICR0] & ~ICR0_RAM_MASK; - const uint8_t pfr = m_pfr & ~ICR0_RAM_MASK; - if (icr0 & pfr) - { - set_interrupt(MSR_PER); - } - - const uint8_t icr1 = m_ram[REG_TSCR_ICR1] & ICR1_COMPARE_MASK; - if (icr1) - { - if (m_ram[REG_SECOND] == m_ram[REG_COMP_SECOND] || - m_ram[REG_MINUTE] == m_ram[REG_COMP_MINUTE] || - m_ram[REG_HOUR] == m_ram[REG_COMP_HOUR] || - m_ram[REG_DAY] == m_ram[REG_COMP_DAY] || - m_ram[REG_MONTH] == m_ram[REG_COMP_MONTH] || - m_ram[REG_DAYOFWEEK] == m_ram[REG_COMP_DAYOFWEEK]) - { - set_interrupt(MSR_AL); - } - } -} - -void dp8573_device::set_interrupt(uint8_t mask) -{ - bool was_intr = m_ram[REG_MSR] & MSR_INT; - m_ram[REG_MSR] |= mask; - - if (m_ram[REG_MSR] & MSR_INT_MASK) - m_ram[REG_MSR] |= MSR_INT; - - if (!was_intr && (m_ram[REG_MSR] & MSR_INT)) - m_intr_cb(0); -} - -void dp8573_device::clear_interrupt(uint8_t mask) -{ - bool was_intr = m_ram[REG_MSR] & MSR_INT; - m_ram[REG_MSR] &= ~mask; - - if (was_intr && !(m_ram[REG_MSR] & MSR_INT)) - m_intr_cb(1); -} - -void dp8573_device::write(offs_t offset, u8 data) -{ - LOG("%s: DP8573 - Register Write: %02x = %02x\n", machine().describe_context(), offset, data); - - switch (offset) - { - case REG_MSR: // Main Status Register - m_ram[offset] &= ~MSR_RAM_MASK; - m_ram[offset] |= data & MSR_RAM_MASK; - if (data & MSR_CLEARABLE_MASK) - clear_interrupt(data & MSR_CLEARABLE_MASK); - break; - - case REG_RTMR: // Not Applicable / Real-Time Mode Register - if (m_ram[REG_MSR] & MSR_RS) - { - const uint8_t old = m_ram[offset]; - m_ram[offset] = data; - if ((old ^ data) & RTMR_12H) - { - uint8_t hour; - if (old & RTMR_12H) - hour = time_helper::from_bcd(m_ram[REG_HOUR] & 0x1f) + (BIT(m_ram[REG_HOUR], 5) ? 12 : 0); - else - hour = time_helper::from_bcd(m_ram[REG_HOUR]); - - if (data & RTMR_12H) - { - m_ram[REG_HOUR] = time_helper::make_bcd(hour % 12); - m_ram[REG_HOUR] |= (hour > 11) ? 0x20 : 0; - } - else - { - m_ram[REG_HOUR] = time_helper::make_bcd(hour); - } - } - } - break; - - case REG_OMR: // Not Applicable / Output Mode Register - if (m_ram[REG_MSR] & MSR_RS) - { - // Not yet implemented: Buffered Crystal Oscillator output on MFO pin - m_ram[offset] = data; - } - break; - - case REG_PFR_ICR0: // Periodic Flag Register / Interrupt Control Register 0 - if (m_ram[REG_MSR] & MSR_RS) - { - m_ram[offset] = data; - } - else - { - m_pfr &= ~PFR_TM; - m_pfr |= data & PFR_TM; - } - break; - - case REG_TSCR_ICR1: // Time Save Control Register / Interrupt Control Register 1 - if (m_ram[REG_MSR] & MSR_RS) - { - m_ram[offset] = data; - } - else - { - m_tscr = data & ~TSCR_NA; - if (data & TSCR_TS) - save_registers(); - } - break; - - case REG_RAM_D1D0: // RAM, D1/D0 bits only - m_ram[offset] = data & 3; - break; - - case REG_NA_0FH: - case REG_NA_10H: - case REG_NA_11H: - case REG_NA_12H: - break; - - default: - m_ram[offset] = data; - break; - } -} - -u8 dp8573_device::read(offs_t offset) -{ - uint8_t ret = m_ram[offset]; - - if (offset >= REG_RTMR && offset <= REG_TSCR_ICR1) - { - if (m_ram[REG_MSR] & MSR_RS) - { - } - else - { - switch (offset) - { - case REG_RTMR: - case REG_OMR: - ret = 0; - break; - case REG_PFR_ICR0: - ret = m_pfr; - m_pfr &= ~PFR_READ_CLEAR_MASK; - break; - case REG_TSCR_ICR1: - ret = m_tscr; - break; - default: - break; - } - } - } - - LOG("%s: DP8573 - Register Read: %02x = %02x\n", machine().describe_context(), offset, ret); - return ret; -} - -void dp8573_device::nvram_default() -{ - memset(m_ram, 0, 32); -} - -bool dp8573_device::nvram_read(util::read_stream &file) -{ - size_t actual; - if (file.read(m_ram, 32, actual) || actual != 32) - return false; - - return true; -} - -bool dp8573_device::nvram_write(util::write_stream &file) -{ - size_t actual; - return !file.write(m_ram, 32, actual) && actual == 32; -} diff --git a/src/devices/machine/dp8573.h b/src/devices/machine/dp8573.h deleted file mode 100644 index 7cc873d47d1..00000000000 --- a/src/devices/machine/dp8573.h +++ /dev/null @@ -1,154 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -/*************************************************************************** - - DP8573 Real Time Clock (RTC) - -***************************************************************************/ - -#ifndef DEVICES_MACHINE_DP8573_H -#define DEVICES_MACHINE_DP8573_H - -#pragma once - -#include "dirtc.h" - -class dp8573_device : public device_t, public device_nvram_interface, public device_rtc_interface -{ -public: - dp8573_device(const machine_config &mconfig, const char *tag, device_t *owner) - : dp8573_device(mconfig, tag, owner, 32768) - { - } - - dp8573_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - void write(offs_t offset, u8 data); - u8 read(offs_t offset); - void pfail_w(int state) {} - - auto intr() { return m_intr_cb.bind(); } - auto mfo() { return m_mfo_cb.bind(); } - -protected: - // device-level overrides - virtual void device_start() override; - - // device_nvram_interface overrides - virtual void nvram_default() override; - virtual bool nvram_read(util::read_stream &file) override; - virtual bool nvram_write(util::write_stream &file) override; - - // device_rtc_interface overrides - virtual bool rtc_feature_y2k() const override { return false; } - virtual bool rtc_feature_leap_year() const override { return true; } - virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override; - - void save_registers(); - void set_interrupt(uint8_t mask); - void clear_interrupt(uint8_t mask); - - TIMER_CALLBACK_MEMBER(msec_tick); - - enum - { - REG_MSR = 0x00, // Main Status Register - REG_RTMR = 0x01, // Not Applicable / Real-Time Mode Register - REG_OMR = 0x02, // Not Applicable / Output Mode Register - REG_PFR_ICR0 = 0x03, // Periodic Flag Register / Interrupt Control Register 0 - REG_TSCR_ICR1 = 0x04, // Time Save Control Register / Interrupt Control Register 1 - REG_HUNDREDTH = 0x05, // Hundredths and Tenths of a Second (0-99) - REG_SECOND = 0x06, // Seconds (0-59) - REG_MINUTE = 0x07, // Minutes (0-59) - REG_HOUR = 0x08, // Hours (1-12, 0-23) - REG_DAY = 0x09, // Day of Month (1-28/29/30/31) - REG_MONTH = 0x0a, // Month (1-12) - REG_YEAR = 0x0b, // Year (0-99) - // 0x0c - RAM - REG_RAM_D1D0 = 0x0d, // RAM, D1/D0 bits only - REG_DAYOFWEEK = 0x0e, // Day of Week (1-7) - REG_NA_0FH = 0x0f, - REG_NA_10H = 0x10, - REG_NA_11H = 0x11, - REG_NA_12H = 0x12, - REG_COMP_SECOND = 0x13, // Seconds Compare RAM (0-59) - REG_COMP_MINUTE = 0x14, // Minutes Compare RAM (0-59) - REG_COMP_HOUR = 0x15, // Hours Compare RAM (1-12, 0-23) - REG_COMP_DAY = 0x16, // Day of Month Compare RAM (1-28/29/30/31) - REG_COMP_MONTH = 0x17, // Month Compare RAM (1-12) - REG_COMP_DAYOFWEEK = 0x18, // Day of Week Compare RAM (1-7) - REG_SAVE_SECOND = 0x19, // Seconds Time Save RAM - REG_SAVE_MINUTE = 0x1a, // Minutes Time Save RAM - REG_SAVE_HOUR = 0x1b, // Hours Time Save RAM - REG_SAVE_DAY = 0x1c, // Day of Month Time Save RAM - REG_SAVE_MONTH = 0x1d, // Month Time Save RAM - // 0x1e - RAM - REG_TEST = 0x1f, // RAM / Test Mode Register - - MSR_INT = 0x01, // Interrupt Status - MSR_PF = 0x02, // Power Fail Interrupt - MSR_PER = 0x04, // Period Interrupt - MSR_AL = 0x08, // Alarm Interrupt - MSR_RS = 0x40, // Register Select Bit - MSR_RAM_MASK = 0xf0, - MSR_INT_MASK = 0x0e, - MSR_CLEARABLE_MASK = 0x0c, - - PFR_1MIN = 0x01, // Minutes flag - PFR_10S = 0x02, // 10-second flag - PFR_1S = 0x04, // Seconds flag - PFR_100MS = 0x08, // 100-millisecond flag - PFR_10MS = 0x10, // 10-millisecond flag - PFR_1MS = 0x20, // Millisecond flag - PFR_OSF = 0x40, // Oscillator Failed / Single Supply Bit - PFR_TM = 0x80, // Test Mode Enable - PFR_READ_CLEAR_MASK = 0x3f, - - TSCR_RAM_MASK = 0x3f, - TSCR_NA = 0x40, // N/A - TSCR_TS = 0x80, // Time Save Enable - - RTMR_LY0 = 0x01, // Leap Year LSB - RTMR_LY1 = 0x02, // Leap Year MSB - RTMR_LY = 0x03, - RTMR_12H = 0x04, // 12/!24 hour mode - RTMR_CSS = 0x08, // Clock Start/!Stop - RTMR_IPF = 0x10, // Interrupt PF Operation - RTMR_RAM_MASK = 0xe0, - - OMR_RAM_MASK = 0x7f, - OMR_MO = 0x80, // MFO Pin as Oscillator - - ICR0_MN = 0x01, // Minutes enable - ICR0_TS = 0x02, // 10-second enable - ICR0_S = 0x04, // Seconds enable - ICR0_HM = 0x08, // 100 millisecond enable - ICR0_TM = 0x10, // 10 millisecond enable - ICR0_1M = 0x20, // Milliseconds enable - ICR0_RAM_MASK = 0xc0, - - ICR1_SC = 0x01, // Second compare enable - ICR1_MN = 0x02, // Minute compare enable - ICR1_HR = 0x04, // Hour compare enable - ICR1_DOM = 0x08, // Day of month compare enable - ICR1_MO = 0x10, // Month compare enable - ICR1_DOW = 0x20, // Day of week compare enable - ICR1_ALE = 0x40, // Alarm interrupt enable - ICR1_PFE = 0x80, // Power fail interrupt enable - ICR1_COMPARE_MASK = 0x3f - }; - - uint8_t m_ram[32]; - uint8_t m_tscr; - uint8_t m_pfr; - uint8_t m_millis; - - emu_timer *m_timer; - - devcb_write_line m_intr_cb; - devcb_write_line m_mfo_cb; -}; - -DECLARE_DEVICE_TYPE(DP8573, dp8573_device) - -#endif // DEVICES_MACHINE_DP8573_H diff --git a/src/devices/machine/dp8573a.cpp b/src/devices/machine/dp8573a.cpp new file mode 100644 index 00000000000..a9670de84b7 --- /dev/null +++ b/src/devices/machine/dp8573a.cpp @@ -0,0 +1,486 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz + +/* + * DP8572A/DP8573A Real Time Clock (RTC) + * + * The DP8572A has several enhancements over the DP8573A: + * - additional page of 32 bytes of RAM + * - programmable prescaler (allows choice of 32.768KHz, 4.194304MHz, 4.9152MHz + * and 32.0KHz oscillators) + * - power fail delay + * + * TODO: + * - dp8572a programmable prescaler + */ + +#include "emu.h" +#include "machine/dp8573a.h" + +#include "machine/timehelp.h" + +#include +#include + +#define LOG_TICKS (1U << 1) +#define LOG_ALL (LOG_GENERAL | LOG_TICKS) + +#define VERBOSE (0) +#include "logmacro.h" + +enum : uint8_t +{ + REG_MSR = 0x00, // Main Status Register + REG_RTMR = 0x01, // Not Applicable / Real-Time Mode Register + REG_OMR = 0x02, // Not Applicable / Output Mode Register + REG_PFR_ICR0 = 0x03, // Periodic Flag Register / Interrupt Control Register 0 + REG_TSCR_ICR1 = 0x04, // Time Save Control Register / Interrupt Control Register 1 + REG_HUNDREDTH = 0x05, // Hundredths and Tenths of a Second (0-99) + REG_SECOND = 0x06, // Seconds (0-59) + REG_MINUTE = 0x07, // Minutes (0-59) + REG_HOUR = 0x08, // Hours (1-12, 0-23) + REG_DAY = 0x09, // Day of Month (1-28/29/30/31) + REG_MONTH = 0x0a, // Month (1-12) + REG_YEAR = 0x0b, // Year (0-99) + // 0x0c - RAM + REG_RAM_D1D0 = 0x0d, // RAM, D1/D0 bits only + REG_DAYOFWEEK = 0x0e, // Day of Week (1-7) + REG_NA_0FH = 0x0f, + REG_NA_10H = 0x10, + REG_NA_11H = 0x11, + REG_NA_12H = 0x12, + REG_COMP_SECOND = 0x13, // Seconds Compare RAM (0-59) + REG_COMP_MINUTE = 0x14, // Minutes Compare RAM (0-59) + REG_COMP_HOUR = 0x15, // Hours Compare RAM (1-12, 0-23) + REG_COMP_DAY = 0x16, // Day of Month Compare RAM (1-28/29/30/31) + REG_COMP_MONTH = 0x17, // Month Compare RAM (1-12) + REG_COMP_DAYOFWEEK = 0x18, // Day of Week Compare RAM (1-7) + REG_SAVE_SECOND = 0x19, // Seconds Time Save RAM + REG_SAVE_MINUTE = 0x1a, // Minutes Time Save RAM + REG_SAVE_HOUR = 0x1b, // Hours Time Save RAM + REG_SAVE_DAY = 0x1c, // Day of Month Time Save RAM + REG_SAVE_MONTH = 0x1d, // Month Time Save RAM + // 0x1e - RAM + REG_TEST = 0x1f, // RAM / Test Mode Register + + MSR_INT = 0x01, // Interrupt Status + MSR_PF = 0x02, // Power Fail Interrupt + MSR_PER = 0x04, // Period Interrupt + MSR_AL = 0x08, // Alarm Interrupt + MSR_RS = 0x40, // Register Select Bit + MSR_PS = 0x80, // Page Select (DP8572A) + MSR_RAM_MASK = 0xf0, + MSR_INT_MASK = 0x0e, + MSR_CLEARABLE_MASK = 0x0c, + + PFR_1MIN = 0x01, // Minutes flag + PFR_10S = 0x02, // 10-second flag + PFR_1S = 0x04, // Seconds flag + PFR_100MS = 0x08, // 100-millisecond flag + PFR_10MS = 0x10, // 10-millisecond flag + PFR_1MS = 0x20, // Millisecond flag + PFR_OSF = 0x40, // Oscillator Failed / Single Supply Bit + PFR_TM = 0x80, // Test Mode Enable + PFR_READ_CLEAR_MASK = 0x3f, + + TSCR_RAM_MASK = 0x3f, + TSCR_PFDE = 0x20, // Power Fail Delay Enable (DP8572A) + TSCR_NA = 0x40, // N/A + TSCR_LBF = 0x40, // Low Battery Flag (DP8572A) + TSCR_TS = 0x80, // Time Save Enable + + RTMR_LY0 = 0x01, // Leap Year LSB + RTMR_LY1 = 0x02, // Leap Year MSB + RTMR_LY = 0x03, + RTMR_12H = 0x04, // 12/!24 hour mode + RTMR_CSS = 0x08, // Clock Start/!Stop + RTMR_IPF = 0x10, // Interrupt PF Operation + RTMR_XT0 = 0x40, // Crystal Freq. XT0 (DP8572A) + RTMR_XT1 = 0x80, // Crystal Freq. XT1 (DP8572A) + RTMR_RAM_MASK = 0xe0, + + OMR_RAM_MASK = 0x7f, + OMR_MO = 0x80, // MFO Pin as Oscillator + + ICR0_MN = 0x01, // Minutes enable + ICR0_TS = 0x02, // 10-second enable + ICR0_S = 0x04, // Seconds enable + ICR0_HM = 0x08, // 100 millisecond enable + ICR0_TM = 0x10, // 10 millisecond enable + ICR0_1M = 0x20, // Milliseconds enable + ICR0_RAM_MASK = 0xc0, + + ICR1_SC = 0x01, // Second compare enable + ICR1_MN = 0x02, // Minute compare enable + ICR1_HR = 0x04, // Hour compare enable + ICR1_DOM = 0x08, // Day of month compare enable + ICR1_MO = 0x10, // Month compare enable + ICR1_DOW = 0x20, // Day of week compare enable + ICR1_ALE = 0x40, // Alarm interrupt enable + ICR1_PFE = 0x80, // Power fail interrupt enable + ICR1_COMPARE_MASK = 0x3f +}; + +// device type definition +DEFINE_DEVICE_TYPE(DP8572A, dp8572a_device, "dp8572a", "DP8572A Real Time Clock") +DEFINE_DEVICE_TYPE(DP8573A, dp8573a_device, "dp8573a", "DP8573A Real Time Clock") + +dp8573a_device::dp8573a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_nvram_interface(mconfig, *this) + , device_rtc_interface(mconfig, *this) + , m_intr_cb(*this) + , m_mfo_cb(*this) +{ +} + +dp8573a_device::dp8573a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : dp8573a_device(mconfig, DP8573A, tag, owner, clock) +{ +} + +dp8572a_device::dp8572a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : dp8573a_device(mconfig, DP8572A, tag, owner, clock) +{ +} + +void dp8573a_device::device_start() +{ + m_ram = std::make_unique(ram_size()); + + save_pointer(NAME(m_ram), ram_size()); + save_item(NAME(m_tscr)); + save_item(NAME(m_pfr)); + save_item(NAME(m_millis)); + + m_timer = timer_alloc(FUNC(dp8573a_device::msec_tick), this); + m_timer->adjust(attotime::never); + + m_tscr = 0; + + m_timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1)); +} + +void dp8573a_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + m_millis = 0; + m_ram[REG_HUNDREDTH] = 0; + m_ram[REG_SECOND] = time_helper::make_bcd(second); + m_ram[REG_MINUTE] = time_helper::make_bcd(minute); + m_ram[REG_HOUR] = time_helper::make_bcd(hour); + m_ram[REG_DAY] = time_helper::make_bcd(day); + m_ram[REG_MONTH] = time_helper::make_bcd(month); + m_ram[REG_YEAR] = time_helper::make_bcd(year); + m_ram[REG_DAYOFWEEK] = time_helper::make_bcd(day_of_week); + + m_pfr = 0; + + // FIXME: should probably rely on nvram start/stop state + m_ram[REG_RTMR] = RTMR_CSS; +} + +void dp8573a_device::save_registers() +{ + m_ram[REG_SAVE_SECOND] = m_ram[REG_SECOND]; + m_ram[REG_SAVE_MINUTE] = m_ram[REG_MINUTE]; + m_ram[REG_SAVE_HOUR] = m_ram[REG_HOUR]; + m_ram[REG_SAVE_DAY] = m_ram[REG_DAY]; + m_ram[REG_SAVE_MONTH] = m_ram[REG_MONTH]; +} + +TIMER_CALLBACK_MEMBER(dp8573a_device::msec_tick) +{ + if ((m_pfr & PFR_OSF) || !(m_ram[REG_RTMR] & RTMR_CSS)) + { + LOGMASKED(LOG_TICKS, "Tick suppressed due to OSF or !CSS\n"); + return; + } + + m_pfr |= PFR_1MS; + + bool carry = false; + bool tens_carry = false; + time_helper::inc_bcd(&m_millis, 0xff, 0x00, 0x09, &tens_carry); + if (tens_carry) + { + m_pfr |= PFR_10MS; + carry = time_helper::inc_bcd(&m_ram[REG_HUNDREDTH], 0xff, 0x00, 0x99, &tens_carry); + if (tens_carry) + m_pfr |= PFR_100MS; + } + if (carry) + { + m_pfr |= PFR_1S; + carry = time_helper::inc_bcd(&m_ram[REG_SECOND], 0xff, 0x00, 0x59, &tens_carry); + if (tens_carry) + m_pfr |= PFR_10S; + } + if (carry) + { + m_pfr |= PFR_1MIN; + carry = time_helper::inc_bcd(&m_ram[REG_MINUTE], 0xff, 0x00, 0x59); + } + if (carry) + { + if (m_ram[REG_RTMR] & RTMR_12H) + { + carry = time_helper::inc_bcd(&m_ram[REG_HOUR], 0xff, 0x01, 0x12); + if (carry) + { + m_ram[REG_HOUR] |= 0x20; + carry = !(m_ram[REG_HOUR] & 0x20); + } + } + else + { + carry = time_helper::inc_bcd(&m_ram[REG_HOUR], 0xff, 0x00, 0x23); + } + } + if (carry) + { + static const uint8_t daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + + time_helper::inc_bcd(&m_ram[REG_DAYOFWEEK], 0xff, 0x01, 0x07); + + uint8_t month = time_helper::from_bcd(m_ram[REG_MONTH]); + + uint8_t maxdays; + if (month == 2 && (m_ram[REG_RTMR] & RTMR_LY) == 0) + { + maxdays = 0x29; + } + else if (month >= 1 && month <= 12) + { + maxdays = daysinmonth[month - 1]; + } + else + { + maxdays = 0x31; + } + + carry = time_helper::inc_bcd(&m_ram[REG_DAY], 0xff, 0x01, maxdays); + } + if (carry) + { + carry = time_helper::inc_bcd(&m_ram[REG_MONTH], 0xff, 0x01, 0x12); + } + if (carry) + { + carry = time_helper::inc_bcd(&m_ram[REG_YEAR], 0xff, 0x00, 0x99); + } + if (carry) + { + // Advance the leap-year counter + uint8_t leap = m_ram[REG_RTMR] & RTMR_LY; + leap = (leap + 1) & RTMR_LY; + m_ram[REG_RTMR] &= ~RTMR_LY; + m_ram[REG_RTMR] |= leap; + } + + // Check for Time Save mode + if (m_tscr & TSCR_TS) + { + save_registers(); + } + + // Check for periodic interrupts + const uint8_t icr0 = m_ram[REG_PFR_ICR0] & ~ICR0_RAM_MASK; + const uint8_t pfr = m_pfr & ~ICR0_RAM_MASK; + if (icr0 & pfr) + { + set_interrupt(MSR_PER); + } + + const uint8_t icr1 = m_ram[REG_TSCR_ICR1] & ICR1_COMPARE_MASK; + if (icr1) + { + if (m_ram[REG_SECOND] == m_ram[REG_COMP_SECOND] || + m_ram[REG_MINUTE] == m_ram[REG_COMP_MINUTE] || + m_ram[REG_HOUR] == m_ram[REG_COMP_HOUR] || + m_ram[REG_DAY] == m_ram[REG_COMP_DAY] || + m_ram[REG_MONTH] == m_ram[REG_COMP_MONTH] || + m_ram[REG_DAYOFWEEK] == m_ram[REG_COMP_DAYOFWEEK]) + { + set_interrupt(MSR_AL); + } + } +} + +void dp8573a_device::set_interrupt(uint8_t mask) +{ + bool was_intr = m_ram[REG_MSR] & MSR_INT; + m_ram[REG_MSR] |= mask; + + if (m_ram[REG_MSR] & MSR_INT_MASK) + m_ram[REG_MSR] |= MSR_INT; + + if (!was_intr && (m_ram[REG_MSR] & MSR_INT)) + m_intr_cb(0); +} + +void dp8573a_device::clear_interrupt(uint8_t mask) +{ + bool was_intr = m_ram[REG_MSR] & MSR_INT; + m_ram[REG_MSR] &= ~mask; + + if (was_intr && !(m_ram[REG_MSR] & MSR_INT)) + m_intr_cb(1); +} + +void dp8573a_device::write(offs_t offset, uint8_t data) +{ + LOG("%s: Register Write: %02x = %02x\n", machine().describe_context(), offset, data); + + switch (offset) + { + case REG_MSR: // Main Status Register + m_ram[offset] &= ~MSR_RAM_MASK; + m_ram[offset] |= data & MSR_RAM_MASK; + if (data & MSR_CLEARABLE_MASK) + clear_interrupt(data & MSR_CLEARABLE_MASK); + break; + + case REG_RTMR: // Not Applicable / Real-Time Mode Register + if (m_ram[REG_MSR] & MSR_RS) + { + const uint8_t old = m_ram[offset]; + m_ram[offset] = data; + if ((old ^ data) & RTMR_12H) + { + uint8_t hour; + if (old & RTMR_12H) + hour = time_helper::from_bcd(m_ram[REG_HOUR] & 0x1f) + (BIT(m_ram[REG_HOUR], 5) ? 12 : 0); + else + hour = time_helper::from_bcd(m_ram[REG_HOUR]); + + if (data & RTMR_12H) + { + m_ram[REG_HOUR] = time_helper::make_bcd(hour % 12); + m_ram[REG_HOUR] |= (hour > 11) ? 0x20 : 0; + } + else + { + m_ram[REG_HOUR] = time_helper::make_bcd(hour); + } + } + } + break; + + case REG_OMR: // Not Applicable / Output Mode Register + if (m_ram[REG_MSR] & MSR_RS) + { + // Not yet implemented: Buffered Crystal Oscillator output on MFO pin + m_ram[offset] = data; + } + break; + + case REG_PFR_ICR0: // Periodic Flag Register / Interrupt Control Register 0 + if (m_ram[REG_MSR] & MSR_RS) + { + m_ram[offset] = data; + } + else + { + m_pfr &= ~PFR_TM; + m_pfr |= data & PFR_TM; + } + break; + + case REG_TSCR_ICR1: // Time Save Control Register / Interrupt Control Register 1 + if (m_ram[REG_MSR] & MSR_RS) + { + m_ram[offset] = data; + } + else + { + m_tscr = data & ~TSCR_NA; + if (data & TSCR_TS) + save_registers(); + } + break; + + case REG_RAM_D1D0: // RAM, D1/D0 bits only + m_ram[offset] = data & 3; + break; + + case REG_NA_0FH: + case REG_NA_10H: + case REG_NA_11H: + case REG_NA_12H: + break; + + default: + m_ram[offset] = data; + break; + } +} + +uint8_t dp8573a_device::read(offs_t offset) +{ + uint8_t ret = m_ram[offset]; + + if (offset >= REG_RTMR && offset <= REG_TSCR_ICR1) + { + if (m_ram[REG_MSR] & MSR_RS) + { + } + else + { + switch (offset) + { + case REG_RTMR: + case REG_OMR: + ret = 0; + break; + case REG_PFR_ICR0: + ret = m_pfr; + m_pfr &= ~PFR_READ_CLEAR_MASK; + break; + case REG_TSCR_ICR1: + ret = m_tscr; + break; + default: + break; + } + } + } + + LOG("%s: Register Read: %02x = %02x\n", machine().describe_context(), offset, ret); + return ret; +} + +void dp8573a_device::nvram_default() +{ + std::fill_n(m_ram.get(), ram_size(), 0); +} + +bool dp8573a_device::nvram_read(util::read_stream &file) +{ + size_t actual; + if (file.read(m_ram.get(), ram_size(), actual) || actual != ram_size()) + return false; + + return true; +} + +bool dp8573a_device::nvram_write(util::write_stream &file) +{ + size_t actual; + return !file.write(m_ram.get(), ram_size(), actual) && actual == ram_size(); +} + +void dp8572a_device::write(offs_t offset, uint8_t data) +{ + if (offset && (m_ram[REG_MSR] & MSR_PS)) + m_ram[offset + 32] = data; + else + dp8573a_device::write(offset, data); +} + +uint8_t dp8572a_device::read(offs_t offset) +{ + if (offset && (m_ram[REG_MSR] & MSR_PS)) + return m_ram[offset + 32]; + else + return dp8573a_device::read(offset); +} diff --git a/src/devices/machine/dp8573a.h b/src/devices/machine/dp8573a.h new file mode 100644 index 00000000000..5851c9a65ab --- /dev/null +++ b/src/devices/machine/dp8573a.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz + +#ifndef DEVICES_MACHINE_DP8573_H +#define DEVICES_MACHINE_DP8573_H + +#pragma once + +#include "dirtc.h" + +class dp8573a_device : public device_t, public device_nvram_interface, public device_rtc_interface +{ +public: + dp8573a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 32'768); + + virtual void write(offs_t offset, uint8_t data); + virtual uint8_t read(offs_t offset); + void pfail_w(int state) {} + + auto intr() { return m_intr_cb.bind(); } + auto mfo() { return m_mfo_cb.bind(); } + +protected: + dp8573a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device_t implementation + virtual void device_start() override; + + // device_nvram_interface implementation + virtual void nvram_default() override; + virtual bool nvram_read(util::read_stream &file) override; + virtual bool nvram_write(util::write_stream &file) override; + + // device_rtc_interface implementation + virtual bool rtc_feature_y2k() const override { return false; } + virtual bool rtc_feature_leap_year() const override { return true; } + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override; + + void save_registers(); + void set_interrupt(uint8_t mask); + void clear_interrupt(uint8_t mask); + + TIMER_CALLBACK_MEMBER(msec_tick); + + virtual unsigned const ram_size() { return 32; } + + std::unique_ptr m_ram; + uint8_t m_tscr; + uint8_t m_pfr; + uint8_t m_millis; + + emu_timer *m_timer; + + devcb_write_line m_intr_cb; + devcb_write_line m_mfo_cb; +}; + +class dp8572a_device : public dp8573a_device +{ +public: + dp8572a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual void write(offs_t offset, uint8_t data) override; + virtual uint8_t read(offs_t offset) override; + +protected: + virtual unsigned const ram_size() override { return 64; } +}; + +DECLARE_DEVICE_TYPE(DP8572A, dp8572a_device) +DECLARE_DEVICE_TYPE(DP8573A, dp8573a_device) + +#endif // DEVICES_MACHINE_DP8573_H diff --git a/src/mame/sgi/4dpi.cpp b/src/mame/sgi/4dpi.cpp index f99f4824fed..5a3d97a893c 100644 --- a/src/mame/sgi/4dpi.cpp +++ b/src/mame/sgi/4dpi.cpp @@ -45,7 +45,7 @@ #include "machine/am79c90.h" #include "machine/mc68681.h" #include "machine/pit8253.h" -#include "machine/dp8573.h" +#include "machine/dp8573a.h" #include "machine/z80scc.h" #include "machine/edlc.h" #include "machine/input_merger.h" @@ -102,7 +102,7 @@ private: required_device m_ram; required_device m_eeprom; - required_device m_rtc; + required_device m_rtc; required_device m_pit; required_device m_scsi; required_device m_enet; @@ -264,7 +264,7 @@ private: required_region_ptr m_eprom; required_device m_eeprom; - required_device m_rtc; + required_device m_rtc; required_device m_pit; required_device m_scsi; required_device m_enet; @@ -495,7 +495,7 @@ void pi4d2x_state::map(address_map &map) NAME([this](offs_t offset) { return m_duart[BIT(offset, 0)]->read(offset >> 2); }), NAME([this](offs_t offset, u8 data) { m_duart[BIT(offset, 0)]->write(offset >> 2, data); })).umask32(0xff000000); - map(0x1fbc0000, 0x1fbc007f).rw(m_rtc, FUNC(dp8573_device::read), FUNC(dp8573_device::write)).umask32(0xff000000); + map(0x1fbc0000, 0x1fbc007f).rw(m_rtc, FUNC(dp8572a_device::read), FUNC(dp8572a_device::write)).umask32(0xff000000); map(0x1fc00000, 0x1fc3ffff).rom().region("boot", 0); @@ -597,7 +597,7 @@ void pi4d3x_state::map(address_map &map) map(0x1fb80d10, 0x1fb80d1f).rw(m_duart[1], FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0x000000ff); map(0x1fb80d20, 0x1fb80d2f).rw(m_duart[2], FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0x000000ff); - map(0x1fb80e00, 0x1fb80e7f).rw(m_rtc, FUNC(dp8573_device::read), FUNC(dp8573_device::write)).umask32(0x000000ff); + map(0x1fb80e00, 0x1fb80e7f).rw(m_rtc, FUNC(dp8572a_device::read), FUNC(dp8572a_device::write)).umask32(0x000000ff); map(0x1fbe0000, 0x1fbfffff).ram().share("dsp_sram"); // 3xTC55328J-25 32KiB CMOS static RAM @@ -662,7 +662,7 @@ void pi4d2x_state::common(machine_config &config) EEPROM_93C56_16BIT(config, m_eeprom); - DP8573(config, m_rtc); // DP8572AN + DP8572A(config, m_rtc, 32.768_KHz_XTAL); PIT8254(config, m_pit); m_pit->set_clk<2>(3.6864_MHz_XTAL); @@ -792,7 +792,7 @@ void pi4d3x_state::common(machine_config &config) EEPROM_93C56_16BIT(config, m_eeprom); - DP8573(config, m_rtc); // DP8572AV + DP8572A(config, m_rtc, 32.768_KHz_XTAL); // 1: local0 // 2: local1 diff --git a/src/mame/sgi/hpc1.cpp b/src/mame/sgi/hpc1.cpp index 537bb9096da..478a0465a3a 100644 --- a/src/mame/sgi/hpc1.cpp +++ b/src/mame/sgi/hpc1.cpp @@ -184,7 +184,7 @@ void hpc1_device::device_add_mconfig(machine_config &config) NSCSI_CONNECTOR(config, "scsibus:6", scsi_devices, nullptr, false); NSCSI_CONNECTOR(config, "scsibus:7", scsi_devices, nullptr, false); - DP8573(config, m_rtc).set_use_utc(true); + DP8572A(config, m_rtc, 32.768_KHz_XTAL).set_use_utc(true); PIT8254(config, m_pit, 0); m_pit->set_clk<0>(1000000); diff --git a/src/mame/sgi/hpc1.h b/src/mame/sgi/hpc1.h index b2b2a17c023..34b1c15de67 100644 --- a/src/mame/sgi/hpc1.h +++ b/src/mame/sgi/hpc1.h @@ -11,7 +11,7 @@ #pragma once -#include "machine/dp8573.h" +#include "machine/dp8573a.h" #include "machine/eepromser.h" #include "machine/pit8253.h" #include "machine/wd33c9x.h" @@ -65,7 +65,7 @@ protected: required_device m_wd33c93; required_device_array m_scc; required_device m_pit; - required_device m_rtc; + required_device m_rtc; enum { -- cgit v1.2.3