summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2020-05-28 07:47:50 -0400
committer GitHub <noreply@github.com>2020-05-28 07:47:50 -0400
commit3ed842c01cb666533da31a0bc0907ef8bd4a0f63 (patch)
treef8762514af0b4848052cf198a8d2991c5ccd7237 /src/devices/machine
parentd4956fe2a68be5116f0bed7a6777a4cb2f77a304 (diff)
parent963e16d63cefbb277d0a776fe94aa4184d05ae8e (diff)
Merge pull request #6750 from shattered/_100c143238a
Add MM58174 real time clock and use it (nw)
Diffstat (limited to 'src/devices/machine')
-rw-r--r--src/devices/machine/mm58174.cpp304
-rw-r--r--src/devices/machine/mm58174.h64
2 files changed, 368 insertions, 0 deletions
diff --git a/src/devices/machine/mm58174.cpp b/src/devices/machine/mm58174.cpp
new file mode 100644
index 00000000000..fe24c8091b5
--- /dev/null
+++ b/src/devices/machine/mm58174.cpp
@@ -0,0 +1,304 @@
+// license:BSD-3-Clause
+// copyright-holders:Raphael Nabet,Sergey Svishchev
+/***************************************************************************
+
+ mm58174.cpp
+
+ National Semiconductor MM58174 Microprocessor Compatible Real Time Clock
+
+ Docs:
+ * <http://www.bitsavers.org/components/national/_appNotes/AN-0359.pdf>
+ * <ftp://ftp.jameco.com/Archive/Obsolete-TechDocuments/26219.pdf>
+
+ Todo:
+ * data-changed flip-flop
+ * interrupts, MM58174A (no interrupt ack)
+ * loss of accuracy after restart
+
+***************************************************************************/
+
+#include "emu.h"
+#include "machine/mm58174.h"
+
+enum
+{
+ ctl_clkrun = 0x1, /* clock start/stop (1=run, 0=stop) */
+
+ year_leap = 0x8,
+
+ int_ctl_rpt = 0x8, /* 1 for repeated interrupt */
+ int_ctl_dly = 0x7 /* 0 no interrupt, 1 = .5 second, 2=5, 4=60 */
+};
+
+
+DEFINE_DEVICE_TYPE(MM58174, mm58174_device, "mm58174", "National Semiconductor MM58174 RTC")
+
+
+mm58174_device::mm58174_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MM58174, tag, owner, clock),
+ device_rtc_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mm58174_device::device_start()
+{
+ m_increment_rtc = timer_alloc();
+ m_increment_rtc->adjust(attotime::zero, 0, attotime::from_msec(100));
+ m_interrupt_timer = timer_alloc();
+
+ // register for state saving
+ save_item(NAME(m_control));
+ save_item(NAME(m_int_ctl));
+ save_item(NAME(m_wday));
+ save_item(NAME(m_months1));
+ save_item(NAME(m_months2));
+ save_item(NAME(m_days1));
+ save_item(NAME(m_days2));
+ save_item(NAME(m_hours1));
+ save_item(NAME(m_hours2));
+ save_item(NAME(m_minutes1));
+ save_item(NAME(m_minutes2));
+ save_item(NAME(m_seconds1));
+ save_item(NAME(m_seconds2));
+ save_item(NAME(m_tenths));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mm58174_device::device_reset()
+{
+ m_tenths = 0;
+ m_control = 0;
+}
+
+//-------------------------------------------------
+// rtc_clock_updated -
+//-------------------------------------------------
+
+void mm58174_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ m_seconds1 = second / 10;
+ m_seconds2 = second % 10;
+ m_minutes1 = minute / 10;
+ m_minutes2 = minute % 10;
+ m_hours1 = hour / 10;
+ m_hours2 = hour % 10;
+ m_wday = day_of_week;
+ m_days1 = day / 10;
+ m_days2 = day % 10;
+ m_months1 = month / 10;
+ m_months2 = month % 10;
+ m_years = 1 << (3 - (year & 3));
+}
+
+
+attotime mm58174_device::interrupt_period_table(int val)
+{
+ switch(val)
+ {
+ case 0: return attotime::from_msec(0);
+ case 1: return attotime::from_msec(500);
+ case 2: return attotime::from_seconds(5);
+ case 4: return attotime::from_seconds(60);
+ default: fatalerror("out of range\n");
+ }
+}
+
+void mm58174_device::update_rtc()
+{
+ set_clock_register(RTC_SECOND, m_seconds1 * 10 + m_seconds2);
+ set_clock_register(RTC_MINUTE, m_minutes1 * 10 + m_minutes2);
+ set_clock_register(RTC_HOUR, m_hours1 * 10 + m_hours2);
+ set_clock_register(RTC_DAY, m_days1 * 10 + m_days2);
+ set_clock_register(RTC_DAY_OF_WEEK, m_wday);
+ set_clock_register(RTC_MONTH, m_months1 * 10 + m_months2);
+}
+
+uint8_t mm58174_device::read(offs_t offset)
+{
+ int reply = 0;
+
+ offset &= 0xf;
+
+ switch (offset)
+ {
+ case 0x01: /* Tenths of Seconds */
+ reply = m_tenths;
+ break;
+
+ case 0x02: /* Units Seconds */
+ reply = m_seconds2;
+ break;
+
+ case 0x03: /* Tens Seconds */
+ reply = m_seconds1;
+ break;
+
+ case 0x04: /* Units Minutes */
+ reply = m_minutes2;
+ break;
+
+ case 0x05: /* Tens Minutes */
+ reply = m_minutes1;
+ break;
+
+ case 0x06: /* Units Hours */
+ reply = m_hours2;
+ break;
+
+ case 0x07: /* Tens Hours */
+ reply = m_hours1;
+ break;
+
+ case 0x08: /* Units Days */
+ reply = m_days2;
+ break;
+
+ case 0x09: /* Tens Days */
+ reply = m_days1;
+ break;
+
+ case 0x0a: /* Day of Week */
+ reply = m_wday;
+ break;
+
+ case 0x0b: /* Units Months */
+ reply = m_months2;
+ break;
+
+ case 0x0c: /* Tens Months */
+ reply = m_months1;
+ break;
+
+ case 0x0f: /* Clock Setting & Interrupt Registers */
+ reply = m_int_ctl;
+ break;
+
+ default:
+ reply = 0;
+ break;
+ }
+
+ logerror("reg %02x == %02x\n", offset, reply);
+
+ return reply;
+}
+
+
+void mm58174_device::write(offs_t offset, uint8_t data)
+{
+ offset &= 0xf;
+ data &= 0xf;
+
+ logerror("reg %02x <- %02x\n", offset, data);
+
+ switch (offset)
+ {
+ case 0x00: /* Test Mode Register (emulated) */
+ break;
+
+ case 0x01: /* Tenths of Seconds: cannot be written */
+ break;
+
+ case 0x02: /* Units Seconds: cannot be written */
+ break;
+
+ case 0x03: /* Tens Seconds: cannot be written */
+ break;
+
+ case 0x04: /* Units Minutes */
+ m_minutes2 = data;
+ update_rtc();
+ break;
+
+ case 0x05: /* Tens Minutes */
+ m_minutes1 = data;
+ update_rtc();
+ break;
+
+ case 0x06: /* Units Hours */
+ m_hours2 = data;
+ update_rtc();
+ break;
+
+ case 0x07: /* Tens Hours */
+ m_hours1 = data;
+ update_rtc();
+ break;
+
+ case 0x08: /* Units Days */
+ m_days2 = data;
+ update_rtc();
+ break;
+
+ case 0x09: /* Tens Days */
+ m_days1 = data;
+ update_rtc();
+ break;
+
+ case 0x0a: /* Day of Week */
+ m_wday = data;
+ update_rtc();
+ break;
+
+ case 0x0b: /* Units Months */
+ m_months2 = data;
+ update_rtc();
+ break;
+
+ case 0x0c: /* Tens Months */
+ m_months1 = data;
+ update_rtc();
+ break;
+
+ case 0x0d: /* Years Status */
+ break;
+
+ case 0x0e: /* Stop/Start */
+ if ((m_control & ctl_clkrun) && (!(data & ctl_clkrun))) /* interrupt stop */
+ m_interrupt_timer->enable(0);
+ else if ((!(m_control & ctl_clkrun)) && (data & ctl_clkrun)) /* interrupt run */
+ {
+ attotime period = interrupt_period_table(m_int_ctl & int_ctl_dly);
+
+ m_interrupt_timer->adjust(period, 0, m_int_ctl & int_ctl_rpt ? period : attotime::zero);
+ }
+ if (!(data & ctl_clkrun)) /* stopping the clock clears the tenth counter */
+ m_tenths = 0;
+ m_control = data;
+ break;
+
+ case 0x0f: /* Interrupt Register */
+ m_int_ctl = data;
+ if (m_control & ctl_clkrun) /* interrupt run */
+ {
+ attotime period = interrupt_period_table(m_int_ctl & int_ctl_dly);
+
+ m_interrupt_timer->adjust(period, 0, m_int_ctl & int_ctl_rpt ? period : attotime::zero);
+ }
+ break;
+ }
+}
+
+
+// Increment RTC clock (timed interrupt every 1/10s)
+void mm58174_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id > 0) return;
+
+ if (m_control & ctl_clkrun)
+ {
+ if ((++m_tenths) == 10)
+ {
+ m_tenths = 0;
+ advance_seconds();
+ }
+ }
+}
diff --git a/src/devices/machine/mm58174.h b/src/devices/machine/mm58174.h
new file mode 100644
index 00000000000..5d755627084
--- /dev/null
+++ b/src/devices/machine/mm58174.h
@@ -0,0 +1,64 @@
+// license:BSD-3-Clause
+// copyright-holders:Raphael Nabet,Sergey Svishchev
+
+#ifndef MAME_MACHINE_MM58174_H
+#define MAME_MACHINE_MM58174_H
+
+#pragma once
+
+#include "dirtc.h"
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+class mm58174_device : public device_t, public device_rtc_interface
+{
+public:
+ mm58174_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ uint8_t read(offs_t offset);
+ void write(offs_t offset, uint8_t data);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ // device_rtc_interface overrides
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+ virtual bool rtc_feature_leap_year() const override { return true; }
+
+ void update_rtc();
+
+private:
+ // internal state
+
+ attotime interrupt_period_table(int val);
+
+ int m_control; /* control register (write to address 14) */
+
+ int m_int_ctl; /* interrupt control register */
+
+ int m_years;
+ int m_wday; /* day of the week (1-7 (1=day1 as set in init)) */
+ int m_months1; /* months (BCD: 1-12) */
+ int m_months2;
+ int m_days1; /* days (BCD: 1-31) */
+ int m_days2;
+ int m_hours1; /* hours (BCD : 0-23) */
+ int m_hours2;
+ int m_minutes1; /* minutes (BCD : 0-59) */
+ int m_minutes2;
+ int m_seconds1; /* seconds (BCD : 0-59) */
+ int m_seconds2;
+ int m_tenths; /* tenths of second (BCD : 0-9) */
+
+ emu_timer *m_increment_rtc;
+ emu_timer *m_interrupt_timer;
+};
+
+DECLARE_DEVICE_TYPE(MM58174, mm58174_device)
+
+#endif // MAME_MACHINE_MM58174_H