diff options
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 |
commit | 3ed842c01cb666533da31a0bc0907ef8bd4a0f63 (patch) | |
tree | f8762514af0b4848052cf198a8d2991c5ccd7237 /src/devices/machine | |
parent | d4956fe2a68be5116f0bed7a6777a4cb2f77a304 (diff) | |
parent | 963e16d63cefbb277d0a776fe94aa4184d05ae8e (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.cpp | 304 | ||||
-rw-r--r-- | src/devices/machine/mm58174.h | 64 |
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 |