diff options
-rw-r--r-- | scripts/src/machine.lua | 12 | ||||
-rw-r--r-- | scripts/target/mame/arcade.lua | 1 | ||||
-rw-r--r-- | scripts/target/mame/mess.lua | 1 | ||||
-rw-r--r-- | src/devices/machine/ds1386.cpp | 594 | ||||
-rw-r--r-- | src/devices/machine/ds1386.h | 210 | ||||
-rw-r--r-- | src/devices/machine/mm58167.cpp | 22 | ||||
-rw-r--r-- | src/devices/machine/timehelp.h | 51 | ||||
-rw-r--r-- | src/devices/machine/timekpr.cpp | 71 |
8 files changed, 897 insertions, 65 deletions
diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 647e815f242..9aaa54e4cc3 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -671,6 +671,18 @@ end --------------------------------------------------- -- +--@src/devices/machine/ds1386.h,MACHINES["DS1386"] = true +--------------------------------------------------- + +if (MACHINES["DS1386"]~=null) then + files { + MAME_DIR .. "src/devices/machine/ds1386.cpp", + MAME_DIR .. "src/devices/machine/ds1386.h", + } +end + +--------------------------------------------------- +-- --@src/devices/machine/ds2401.h,MACHINES["DS2401"] = true --------------------------------------------------- diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 43a57585f2c..1e4cb98bcc4 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -388,6 +388,7 @@ MACHINES["CR589"] = true MACHINES["DS1204"] = true MACHINES["DS1302"] = true --MACHINES["DS1315"] = true +--MACHINES["DS1386"] = true MACHINES["DS2401"] = true MACHINES["DS2404"] = true MACHINES["DS75160A"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 32496e693d8..604e780377e 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -394,6 +394,7 @@ MACHINES["DP8390"] = true --MACHINES["DS1204"] = true MACHINES["DS1302"] = true MACHINES["DS1315"] = true +MACHINES["DS1386"] = true MACHINES["DS2401"] = true MACHINES["DS2404"] = true MACHINES["DS75160A"] = true diff --git a/src/devices/machine/ds1386.cpp b/src/devices/machine/ds1386.cpp new file mode 100644 index 00000000000..91a6e2f9c06 --- /dev/null +++ b/src/devices/machine/ds1386.cpp @@ -0,0 +1,594 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/********************************************************************** + + Dallas DS1386/DS1386P RAMified Watchdog Timekeeper + + Note: Largely untested. + +**********************************************************************/ + +#include "ds1386.h" +#include "machine/timehelp.h" + +#define DISABLE_OSC (0x80) +#define DISABLE_SQW (0x40) + +#define COMMAND_TE (0x80) +#define COMMAND_IPSW (0x40) +#define COMMAND_IBH_LO (0x20) +#define COMMAND_PU_LVL (0x10) +#define COMMAND_WAM (0x08) +#define COMMAND_TDM (0x04) +#define COMMAND_WAF (0x02) +#define COMMAND_TDF (0x01) + +#define HOURS_12_24 (0x40) +#define HOURS_AM_PM (0x20) + +const device_type DS1386_8K = &device_creator<ds1386_8k_device>; +const device_type DS1386_32K = &device_creator<ds1386_32k_device>; + +ds1386_device::ds1386_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, size_t size) + : device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , device_nvram_interface(mconfig, *this) + , m_tod_alarm(0) + , m_watchdog_alarm(0) + , m_square(1) + , m_inta_cb(*this) + , m_intb_cb(*this) + , m_sqw_cb(*this) + , m_clock_timer(nullptr) + , m_square_timer(nullptr) + , m_watchdog_timer(nullptr) + , m_inta_timer(nullptr) + , m_intb_timer(nullptr) + , m_default_data(*this, DEVICE_SELF, size) + , m_hundredths(0) + , m_seconds(0) + , m_minutes(0) + , m_minutes_alarm(0) + , m_hours(0) + , m_hours_alarm(0) + , m_days(0) + , m_days_alarm(0) + , m_date(0) + , m_months_enables(0) + , m_years(0) + , m_ram_size(size) +{ +} + +ds1386_8k_device::ds1386_8k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ds1386_device(mconfig, DS1386_8K, "DS1386-8K", tag, owner, clock, "ds1386_8k", 8192) +{ +} + +ds1386_32k_device::ds1386_32k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ds1386_device(mconfig, DS1386_32K, "DS1386-32K", tag, owner, clock, "ds1386_32k", 32768) +{ +} + +void ds1386_device::safe_inta_cb(int state) +{ + if (!m_inta_cb.isnull()) + m_inta_cb(state); +} + +void ds1386_device::safe_intb_cb(int state) +{ + if (!m_intb_cb.isnull()) + m_intb_cb(state); +} + +void ds1386_device::safe_sqw_cb(int state) +{ + if (!m_sqw_cb.isnull()) + m_sqw_cb(state); +} + +void ds1386_device::device_start() +{ + m_inta_cb.resolve(); + m_intb_cb.resolve(); + m_sqw_cb.resolve(); + + m_tod_alarm = 0; + m_watchdog_alarm = 0; + m_square = 1; + + safe_inta_cb(0); + safe_intb_cb(0); + safe_sqw_cb(1); + + // allocate timers + m_clock_timer = timer_alloc(CLOCK_TIMER); + m_clock_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100)); + m_square_timer = timer_alloc(SQUAREWAVE_TIMER); + m_square_timer->adjust(attotime::never); + m_watchdog_timer = timer_alloc(WATCHDOG_TIMER); + m_watchdog_timer->adjust(attotime::never); + m_inta_timer= timer_alloc(INTA_TIMER); + m_inta_timer->adjust(attotime::never); + m_intb_timer= timer_alloc(INTB_TIMER); + m_intb_timer->adjust(attotime::never); + + set_current_time(); + + // state saving + save_item(NAME(m_tod_alarm)); + save_item(NAME(m_watchdog_alarm)); + save_item(NAME(m_square)); + + m_ram = std::make_unique<UINT8[]>(m_ram_size); + memset(&m_ram[0], 0, m_ram_size); +} + +void ds1386_device::device_reset() +{ + m_tod_alarm = 0; + m_watchdog_alarm = 0; + m_square = 1; + + safe_inta_cb(0); + safe_intb_cb(0); + safe_sqw_cb(1); + + m_clock_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100)); + m_square_timer->adjust(attotime::never); + m_watchdog_timer->adjust(attotime::never); + + set_current_time(); +} + + +void ds1386_device::set_current_time() +{ + system_time systime; + machine().base_datetime(systime); + + m_hundredths = 0; + m_seconds = time_helper::make_bcd(systime.local_time.second); + m_minutes = time_helper::make_bcd(systime.local_time.minute); + m_hours = time_helper::make_bcd(systime.local_time.hour); + m_days = time_helper::make_bcd(systime.local_time.weekday + 1); + m_date = time_helper::make_bcd(systime.local_time.mday); + m_months_enables = time_helper::make_bcd(systime.local_time.month + 1); + m_years = time_helper::make_bcd(systime.local_time.year % 100); +} + +void ds1386_device::time_of_day_alarm() +{ + m_ram[REGISTER_COMMAND] |= COMMAND_TDF; + m_tod_alarm = 1; + + if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW) + { + safe_inta_cb(m_tod_alarm); + if (m_ram[REGISTER_COMMAND] & COMMAND_PU_LVL) + { + m_inta_timer->adjust(attotime::from_msec(3)); + } + } + else + { + safe_intb_cb(m_tod_alarm); + if (m_ram[REGISTER_COMMAND] & COMMAND_PU_LVL) + { + m_intb_timer->adjust(attotime::from_msec(3)); + } + } +} + +void ds1386_device::watchdog_alarm() +{ + m_ram[REGISTER_COMMAND] |= COMMAND_WAF; + m_watchdog_alarm = 1; + + if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW) + { + safe_intb_cb(m_watchdog_alarm); + if (m_ram[REGISTER_COMMAND] & COMMAND_PU_LVL) + { + m_intb_timer->adjust(attotime::from_msec(3)); + } + } + else + { + safe_inta_cb(m_watchdog_alarm); + if (m_ram[REGISTER_COMMAND] & COMMAND_PU_LVL) + { + m_inta_timer->adjust(attotime::from_msec(3)); + } + } +} + +void ds1386_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case CLOCK_TIMER: + advance_hundredths(); + break; + + case SQUAREWAVE_TIMER: + m_square = ((m_square == 0) ? 1 : 0); + safe_sqw_cb(m_square); + break; + + case WATCHDOG_TIMER: + if ((m_ram[REGISTER_COMMAND] & COMMAND_WAF) == 0) + watchdog_alarm(); + break; + + case INTA_TIMER: + if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW) + { + m_tod_alarm = 0; + } + else + { + m_watchdog_alarm = 0; + } + safe_inta_cb(0); + break; + + case INTB_TIMER: + if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW) + { + m_watchdog_alarm = 0; + } + else + { + m_tod_alarm = 0; + } + safe_intb_cb(0); + break; + } +} + +void ds1386_device::advance_hundredths() +{ + if ((m_ram[REGISTER_COMMAND] & COMMAND_TE) != 0) + { + copy_ram_to_registers(); + } + + int carry = time_helper::inc_bcd(&m_hundredths, 0xff, 0x00, 0x99); + if (carry) + { + carry = time_helper::inc_bcd(&m_seconds, 0x7f, 0x00, 0x59); + } + if (carry) + { + carry = time_helper::inc_bcd(&m_minutes, 0x7f, 0x00, 0x59); + } + if (carry) + { + UINT8 value = 0; + UINT8 min_value = 0; + UINT8 max_value = 0; + if (m_hours & HOURS_12_24) + { + value = m_hours & 0x1f; + min_value = 0x01; + max_value = 0x12; + } + else + { + value = m_hours & 0x3f; + min_value = 0x00; + max_value = 0x23; + } + carry = time_helper::inc_bcd(&value, 0x1f, min_value, max_value); + + m_hours &= ~0x1f; + if (carry) + { + if (m_hours & HOURS_12_24) + { + if (m_hours & HOURS_AM_PM) + carry = 1; + else + carry = 0; + + m_hours = m_hours ^ HOURS_AM_PM; + } + else + { + m_hours &= ~0x3f; + } + } + else + { + if ((m_hours & HOURS_12_24) == 0) + m_hours &= ~0x3f; + } + m_hours |= value; + } + + if (carry) + { + UINT8 maxdays; + static const UINT8 daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + + time_helper::inc_bcd(&m_days, 0x07, 0x01, 0x07); + + UINT8 month = time_helper::from_bcd(m_months_enables); + UINT8 year = time_helper::from_bcd(m_years); + + if (month == 2 && (year % 4) == 0) + { + maxdays = 0x29; + } + else if (month >= 1 && month <= 12) + { + maxdays = daysinmonth[month - 1]; + } + else + { + maxdays = 0x31; + } + + carry = time_helper::inc_bcd(&m_date, 0x3f, 0x01, maxdays); + } + if (carry) + { + UINT8 enables = m_months_enables & 0xc0; + carry = time_helper::inc_bcd(&m_months_enables, 0x1f, 0x01, 0x12); + m_months_enables &= 0x3f; + m_months_enables |= enables; + } + if (carry) + { + carry = time_helper::inc_bcd(&m_years, 0xff, 0x00, 0x99); + } + + if ((m_ram[REGISTER_COMMAND] & COMMAND_TE) != 0) + { + copy_registers_to_ram(); + } + + check_tod_alarm(); +} + +void ds1386_device::copy_ram_to_registers() +{ + m_hundredths = m_ram[REGISTER_HUNDREDTHS]; + m_seconds = m_ram[REGISTER_SECONDS]; + m_minutes = m_ram[REGISTER_MINUTES]; + m_hours = m_ram[REGISTER_HOURS]; + m_days = m_ram[REGISTER_DAYS]; + m_date = m_ram[REGISTER_DATE]; + m_months_enables = m_ram[REGISTER_MONTHS]; + m_years = m_ram[REGISTER_YEARS]; +} + +void ds1386_device::copy_registers_to_ram() +{ + m_ram[REGISTER_HUNDREDTHS] = m_hundredths; + m_ram[REGISTER_SECONDS] = m_seconds; + m_ram[REGISTER_MINUTES] = m_minutes; + m_ram[REGISTER_HOURS] = m_hours; + m_ram[REGISTER_DAYS] = m_days; + m_ram[REGISTER_DATE] = m_date; + m_ram[REGISTER_MONTHS] = m_months_enables; + m_ram[REGISTER_YEARS] = m_years; +} + +void ds1386_device::check_tod_alarm() +{ + UINT8 mode = BIT(m_days_alarm, 7) | (BIT(m_hours_alarm, 5) << 1) | (BIT(m_minutes_alarm, 3) << 2); + bool zeroes = (m_hundredths == 0 && m_seconds == 0); + if (zeroes && (m_ram[REGISTER_COMMAND] & COMMAND_TDF) == 0) + { + bool minutes_match = (m_minutes & 0x7f) == (m_minutes_alarm & 0x7f); + bool hours_match = (m_hours & 0x7f) == (m_hours_alarm & 0x7f); + bool days_match = (m_days & 0x7) == (m_days_alarm & 0x07); + bool alarm_match = false; + switch (mode) + { + case ALARM_PER_MINUTE: + alarm_match = true; + break; + case ALARM_MINUTES_MATCH: + alarm_match = minutes_match; + break; + case ALARM_HOURS_MATCH: + alarm_match = hours_match; + break; + case ALARM_DAYS_MATCH: + alarm_match = days_match; + break; + default: + break; + } + if (alarm_match) + { + time_of_day_alarm(); + } + } +} + +void ds1386_device::nvram_default() +{ + memset(&m_ram[0], 0, m_ram_size); +} + +void ds1386_device::nvram_read(emu_file &file) +{ + file.read(&m_ram[0], m_ram_size); +} + +void ds1386_device::nvram_write(emu_file &file) +{ + file.write(&m_ram[0], m_ram_size); +} + +WRITE8_MEMBER( ds1386_device::data_w ) +{ + if (offset >= m_ram_size) + return; + + if (offset >= 0xe) + { + m_ram[offset] = data; + } + else + { + switch (offset) + { + case 0x00: // hundredths + case 0x03: // minutes alarm + case 0x05: // horus alarm + case 0x0a: // years + m_ram[offset] = data; + break; + + case 0x01: // seconds + case 0x02: // minutes + case 0x04: // hours + m_ram[offset] = data & 0x7f; + break; + + case 0x06: // days + m_ram[offset] = data & 0x07; + break; + + case 0x07: // days alarm + m_ram[offset] = data & 0x87; + break; + + case 0x08: // date + m_ram[offset] = data & 0x3f; + break; + + case 0x09: // months + { + UINT8 old_value = m_ram[offset]; + m_ram[offset] = data & 0xdf; + UINT8 changed = old_value ^ data; + if (changed & DISABLE_SQW) + { + if (m_ram[offset] & DISABLE_SQW) + { + m_square_timer->adjust(attotime::never); + } + else + { + m_square_timer->adjust(attotime::from_hz(2048)); + } + } + if (changed & DISABLE_OSC) + { + if (m_ram[offset] & DISABLE_OSC) + { + m_clock_timer->adjust(attotime::never); + } + else + { + m_clock_timer->adjust(attotime::from_hz(100)); + } + } + break; + } + + case 0x0c: // watchdog hundredths + case 0x0d: // watchdog seconds + { + if ((m_ram[REGISTER_COMMAND] & COMMAND_WAF) != 0 && (m_ram[REGISTER_COMMAND] & COMMAND_WAM) == 0) + { + m_ram[REGISTER_COMMAND] &= ~COMMAND_WAF; + m_watchdog_alarm = 0; + if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW) + safe_intb_cb(0); + else + safe_inta_cb(0); + } + m_ram[offset] = data; + UINT8 wd_hundredths = m_ram[REGISTER_WATCHDOG_HUNDREDTHS]; + UINT8 wd_seconds = m_ram[REGISTER_WATCHDOG_SECONDS]; + int total_hundredths = (wd_hundredths & 0xf) + ((wd_hundredths >> 4) & 0xf) * 10 + (wd_seconds & 0xf) * 100 + ((wd_seconds >> 4) & 0xf) * 1000; + m_watchdog_timer->adjust(attotime::from_msec(total_hundredths * 10)); + break; + } + + case 0x0b: // command + { + UINT8 old = m_ram[offset]; + m_ram[offset] = data & 0xfc; + UINT8 changed = old ^ m_ram[offset]; + if (changed & COMMAND_IPSW) + { + int old_a = (old & COMMAND_IPSW) ? m_tod_alarm : m_watchdog_alarm; + int old_b = (old & COMMAND_IPSW) ? m_watchdog_alarm : m_tod_alarm; + int new_a = old_b; + int new_b = old_a; + + bool a_changed = old_a != new_a; + bool b_changed = old_b != new_b; + + std::swap(m_tod_alarm, m_watchdog_alarm); + + if (a_changed) + { + if (m_ram[offset] & COMMAND_IPSW) + safe_inta_cb(m_tod_alarm); + else + safe_inta_cb(m_watchdog_alarm); + } + if (b_changed) + { + if (m_ram[offset] & COMMAND_IPSW) + safe_intb_cb(m_watchdog_alarm); + else + safe_intb_cb(m_tod_alarm); + } + } + if (changed & COMMAND_WAM) + { + if (m_ram[offset] & COMMAND_WAF) + { + if (m_ram[offset] & COMMAND_IPSW) + safe_intb_cb(0); + else + safe_inta_cb(0); + } + else if (m_watchdog_alarm) + { + if (m_ram[offset] & COMMAND_IPSW) + safe_intb_cb(m_watchdog_alarm); + else + safe_inta_cb(m_watchdog_alarm); + } + } + if (changed & COMMAND_TDM) + { + if (m_ram[offset] & COMMAND_TDF) + { + if (m_ram[offset] & COMMAND_IPSW) + safe_inta_cb(0); + else + safe_intb_cb(0); + } + else if (m_tod_alarm) + { + if (m_ram[offset] & COMMAND_IPSW) + safe_inta_cb(m_tod_alarm); + else + safe_intb_cb(m_tod_alarm); + } + } + break; + } + } + } +} + +READ8_MEMBER( ds1386_device::data_r ) +{ + if (offset >= m_ram_size) + return 0; + + return m_ram[offset]; +} diff --git a/src/devices/machine/ds1386.h b/src/devices/machine/ds1386.h new file mode 100644 index 00000000000..1146416b923 --- /dev/null +++ b/src/devices/machine/ds1386.h @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/********************************************************************** + + Dallas DS1386/DS1386P RAMified Watchdog Timekeeper + +*********************************************************************** + _____________ + /INTA 1 | | 32 Vcc + /INTB 2 | | 31 SQW + NC/A14 3 | | 30 Vcc + A12 4 | | 29 /WE + A7 5 | | 28 NC/A13 + A6 6 | | 27 A8 + A5 7 | | 26 A9 + A4 8 | | 25 A11 + A3 9 | | 24 /OE + A2 10 | | 23 A10 + A1 11 | | 22 /CE + A0 12 | | 21 DQ7 + DQ0 13 | | 20 DQ6 + DQ1 14 | | 19 DQ5 + DQ2 15 | | 18 DQ4 + GND 16 |_____________| 17 DQ3 + + DS1386 8k/32k x 8 + + __________________________________ + / | + / | + /INTB | 1 34 | /INTA + NC | 2 33 | SQW + NC | 3 32 | NC/A13 + /PFO | 4 31 | NC/A14 + Vcc | 5 30 | A12 + /WE | 6 29 | A11 + /OE | 7 28 | A10 + /CE | 8 27 | A9 + DQ7 | 9 26 | A8 + DQ6 | 10 25 | A7 + DQ5 | 11 24 | A6 + DQ4 | 12 23 | A5 + DQ3 | 13 22 | A4 + DQ2 | 14 X1 GND Vbat X2 21 | A3 + DQ1 | 15 ____ ____ ____ ____ 20 | A2 + DQ0 | 16 | | | | | | | | 19 | A1 + GND | 17 |____| |____| |____| |____| 18 | A0 + |____________________________________| + + DS1386 8k/32k x 8, 34-Pin PowerCap Module Board + +**********************************************************************/ + +#pragma once + +#ifndef DS1386_H +#define DS1386_H + +#include "emu.h" + +// handlers + +#define MCFG_DS1386_INTA_HANDLER(_devcb) \ + devcb = &ds1386_device::set_inta_cb(*device, DEVCB_##_devcb); + +#define MCFG_DS1386_INTB_HANDLER(_devcb) \ + devcb = &ds1386_device::set_inta_cb(*device, DEVCB_##_devcb); + +#define MCFG_DS1386_SQW_HANDLER(_devcb) \ + devcb = &ds1386_device::set_sqw_cb(*device, DEVCB_##_devcb); + +// devices + +#define MCFG_DS1386_8K_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, DS1386_8K, _clock) + +#define MCFG_DS1386_32K_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, DS1386_32K, _clock) + +class ds1386_device : public device_t, + public device_nvram_interface +{ +public: + ds1386_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, size_t size); + + DECLARE_WRITE8_MEMBER( data_w ); + DECLARE_READ8_MEMBER( data_r ); + + DECLARE_WRITE_LINE_MEMBER( ce_w ); + DECLARE_WRITE_LINE_MEMBER( oe_w ); + DECLARE_WRITE_LINE_MEMBER( we_w ); + + template<class _Object> static devcb_base &set_inta_cb(device_t &device, _Object object) { return downcast<ds1386_device &>(device).m_inta_cb.set_callback(object); } + template<class _Object> static devcb_base &set_intb_cb(device_t &device, _Object object) { return downcast<ds1386_device &>(device).m_intb_cb.set_callback(object); } + template<class _Object> static devcb_base &set_sqw_cb(device_t &device, _Object object) { return downcast<ds1386_device &>(device).m_sqw_cb.set_callback(object); } + +protected: + enum + { + REGISTER_HUNDREDTHS = 0, + REGISTER_SECONDS, + REGISTER_MINUTES, + REGISTER_MINUTE_ALARM, + REGISTER_HOURS, + REGISTER_HOUR_ALARM, + REGISTER_DAYS, + REGISTER_DAY_ALARM, + REGISTER_DATE, + REGISTER_MONTHS, + REGISTER_EN_OUTS = REGISTER_MONTHS, + REGISTER_YEARS, + REGISTER_COMMAND, + REGISTER_WATCHDOG_HUNDREDTHS, + REGISTER_WATCHDOG_SECONDS, + REGISTER_USER = 0xE, + }; + + enum + { + ALARM_DAYS_MATCH = 0x0, + ALARM_HOURS_MATCH = 0x1, + ALARM_MINUTES_MATCH = 0x3, + ALARM_PER_MINUTE = 0x7 + }; + + // 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_nvram_interface overrides + virtual void nvram_default() override; + virtual void nvram_read(emu_file &file) override; + virtual void nvram_write(emu_file &file) override; + + static const device_timer_id CLOCK_TIMER = 0; + static const device_timer_id SQUAREWAVE_TIMER = 1; + static const device_timer_id WATCHDOG_TIMER = 2; + static const device_timer_id INTA_TIMER = 3; + static const device_timer_id INTB_TIMER = 4; + +protected: + void safe_inta_cb(int state); + void safe_intb_cb(int state); + void safe_sqw_cb(int state); + + void set_current_time(); + + void check_tod_alarm(); + void time_of_day_alarm(); + void watchdog_alarm(); + + void advance_hundredths(); + + void copy_ram_to_registers(); + void copy_registers_to_ram(); + + int m_tod_alarm; + int m_watchdog_alarm; + int m_square; + + // interfacing with other devices + devcb_write_line m_inta_cb; + devcb_write_line m_intb_cb; + devcb_write_line m_sqw_cb; + + // timers + emu_timer *m_clock_timer; + emu_timer *m_square_timer; + emu_timer *m_watchdog_timer; + emu_timer *m_inta_timer; + emu_timer *m_intb_timer; + + std::unique_ptr<UINT8[]> m_ram; + optional_region_ptr<UINT8> m_default_data; + + UINT8 m_hundredths; + UINT8 m_seconds; + UINT8 m_minutes; + UINT8 m_minutes_alarm; + UINT8 m_hours; + UINT8 m_hours_alarm; + UINT8 m_days; + UINT8 m_days_alarm; + UINT8 m_date; + UINT8 m_months_enables; + UINT8 m_years; + + const size_t m_ram_size; +}; + +class ds1386_8k_device : public ds1386_device +{ +public: + // construction/destruction + ds1386_8k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class ds1386_32k_device : public ds1386_device +{ +public: + // construction/destruction + ds1386_32k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// device type definition +extern const device_type DS1386_8K; +extern const device_type DS1386_32K; + +#endif diff --git a/src/devices/machine/mm58167.cpp b/src/devices/machine/mm58167.cpp index 75e9e799004..148d97260e8 100644 --- a/src/devices/machine/mm58167.cpp +++ b/src/devices/machine/mm58167.cpp @@ -9,6 +9,7 @@ **********************************************************************/ #include "mm58167.h" +#include "machine/timehelp.h" //************************************************************************** // LIVE DEVICE @@ -91,11 +92,6 @@ void mm58167_device::device_reset() } -static inline UINT8 make_bcd(UINT8 data) -{ - return ((data / 10) << 4) | (data % 10); -} - //------------------------------------------------- // device_timer - handler timer events //------------------------------------------------- @@ -124,8 +120,8 @@ void mm58167_device::device_timer(emu_timer &timer, device_timer_id id, int para if ((m_regs[R_CTL_IRQCONTROL] & 0x80) && m_regs[R_CNT_MONTH] != old_month) set_irq(7); // every month } - m_regs[R_CNT_MILLISECONDS] = make_bcd(m_milliseconds % 10); - m_regs[R_CNT_HUNDTENTHS] = make_bcd(m_milliseconds / 10); + m_regs[R_CNT_MILLISECONDS] = time_helper::make_bcd(m_milliseconds % 10); + m_regs[R_CNT_HUNDTENTHS] = time_helper::make_bcd(m_milliseconds / 10); // 10Hz IRQ if ((m_regs[R_CTL_IRQCONTROL] & 0x02) && (m_milliseconds % 100) == 0) @@ -158,12 +154,12 @@ void mm58167_device::device_timer(emu_timer &timer, device_timer_id id, int para void mm58167_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) { - m_regs[R_CNT_SECONDS] = make_bcd(second); // seconds (BCD) - m_regs[R_CNT_MINUTES] = make_bcd(minute); // minutes (BCD) - m_regs[R_CNT_HOURS] = make_bcd(hour); // hour (BCD) - m_regs[R_CNT_DAYOFWEEK] = make_bcd(day_of_week); // day of the week (BCD) - m_regs[R_CNT_DAYOFMONTH] = make_bcd(day); // day of the month (BCD) - m_regs[R_CNT_MONTH] = make_bcd(month); // month (BCD) + m_regs[R_CNT_SECONDS] = time_helper::make_bcd(second); // seconds (BCD) + m_regs[R_CNT_MINUTES] = time_helper::make_bcd(minute); // minutes (BCD) + m_regs[R_CNT_HOURS] = time_helper::make_bcd(hour); // hour (BCD) + m_regs[R_CNT_DAYOFWEEK] = time_helper::make_bcd(day_of_week); // day of the week (BCD) + m_regs[R_CNT_DAYOFMONTH] = time_helper::make_bcd(day); // day of the month (BCD) + m_regs[R_CNT_MONTH] = time_helper::make_bcd(month); // month (BCD) } void mm58167_device::set_irq(int bit) diff --git a/src/devices/machine/timehelp.h b/src/devices/machine/timehelp.h new file mode 100644 index 00000000000..38adfdee502 --- /dev/null +++ b/src/devices/machine/timehelp.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,smf +/*************************************************************************** + + timehelp.h + + Assorted shared functionality between timekeeping chips and RTCs. + +***************************************************************************/ + +#pragma once + +#ifndef SRC_DEVICES_MACHINE_TIMEHELP_H +#define SRC_DEVICES_MACHINE_TIMEHELP_H + +class time_helper +{ +public: + static inline UINT8 make_bcd(UINT8 data) + { + return (((data / 10) % 10) << 4) + (data % 10); + } + + static inline UINT8 from_bcd(UINT8 data) + { + return (((data >> 4) & 15) * 10) + (data & 15); + } + + static int inc_bcd(UINT8 *data, int mask, int min, int max) + { + int bcd = (*data + 1) & mask; + int carry = 0; + + if ((bcd & 0x0f) > 9) + { + bcd &= 0xf0; + bcd += 0x10; + if (bcd > max) + { + bcd = min; + carry = 1; + } + } + + *data = (*data & ~mask) | (bcd & mask); + return carry; + } + +}; + +#endif // SRC_DEVICES_MACHINE_TIMEHELP_H
\ No newline at end of file diff --git a/src/devices/machine/timekpr.cpp b/src/devices/machine/timekpr.cpp index 4b87d43ff69..e11cd089b1c 100644 --- a/src/devices/machine/timekpr.cpp +++ b/src/devices/machine/timekpr.cpp @@ -16,7 +16,7 @@ #include "emu.h" #include "machine/timekpr.h" - +#include "machine/timehelp.h" // device type definition const device_type M48T02 = &device_creator<m48t02_device>; @@ -63,39 +63,6 @@ const device_type MK48T12 = &device_creator<mk48t12_device>; INLINE FUNCTIONS ***************************************************************************/ -static inline UINT8 make_bcd(UINT8 data) -{ - return ( ( ( data / 10 ) % 10 ) << 4 ) + ( data % 10 ); -} - -static inline UINT8 from_bcd( UINT8 data ) -{ - return ( ( ( data >> 4 ) & 15 ) * 10 ) + ( data & 15 ); -} - -static int inc_bcd( UINT8 *data, int mask, int min, int max ) -{ - int bcd; - int carry; - - bcd = ( *( data ) + 1 ) & mask; - carry = 0; - - if( ( bcd & 0x0f ) > 9 ) - { - bcd &= 0xf0; - bcd += 0x10; - if( bcd > max ) - { - bcd = min; - carry = 1; - } - } - - *( data ) = ( *( data ) & ~mask ) | ( bcd & mask ); - return carry; -} - static void counter_to_ram( UINT8 *data, int offset, int counter ) { if( offset >= 0 ) @@ -233,14 +200,14 @@ void timekeeper_device::device_start() machine().base_datetime(systime); m_control = 0; - m_seconds = make_bcd( systime.local_time.second ); - m_minutes = make_bcd( systime.local_time.minute ); - m_hours = make_bcd( systime.local_time.hour ); - m_day = make_bcd( systime.local_time.weekday + 1 ); - m_date = make_bcd( systime.local_time.mday ); - m_month = make_bcd( systime.local_time.month + 1 ); - m_year = make_bcd( systime.local_time.year % 100 ); - m_century = make_bcd( systime.local_time.year / 100 ); + m_seconds = time_helper::make_bcd( systime.local_time.second ); + m_minutes = time_helper::make_bcd( systime.local_time.minute ); + m_hours = time_helper::make_bcd( systime.local_time.hour ); + m_day = time_helper::make_bcd( systime.local_time.weekday + 1 ); + m_date = time_helper::make_bcd( systime.local_time.mday ); + m_month = time_helper::make_bcd( systime.local_time.month + 1 ); + m_year = time_helper::make_bcd( systime.local_time.year % 100 ); + m_century = time_helper::make_bcd( systime.local_time.year / 100 ); m_data.resize( m_size ); save_item( NAME(m_control) ); @@ -298,14 +265,14 @@ void timekeeper_device::device_timer(emu_timer &timer, device_timer_id id, int p return; } - int carry = inc_bcd( &m_seconds, MASK_SECONDS, 0x00, 0x59 ); + int carry = time_helper::inc_bcd( &m_seconds, MASK_SECONDS, 0x00, 0x59 ); if( carry ) { - carry = inc_bcd( &m_minutes, MASK_MINUTES, 0x00, 0x59 ); + carry = time_helper::inc_bcd( &m_minutes, MASK_MINUTES, 0x00, 0x59 ); } if( carry ) { - carry = inc_bcd( &m_hours, MASK_HOURS, 0x00, 0x23 ); + carry = time_helper::inc_bcd( &m_hours, MASK_HOURS, 0x00, 0x23 ); } if( carry ) @@ -313,10 +280,10 @@ void timekeeper_device::device_timer(emu_timer &timer, device_timer_id id, int p UINT8 maxdays; static const UINT8 daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; - inc_bcd( &m_day, MASK_DAY, 0x01, 0x07 ); + time_helper::inc_bcd( &m_day, MASK_DAY, 0x01, 0x07 ); - UINT8 month = from_bcd( m_month ); - UINT8 year = from_bcd( m_year ); + UINT8 month = time_helper::from_bcd( m_month ); + UINT8 year = time_helper::from_bcd( m_year ); if( month == 2 && ( year % 4 ) == 0 ) { @@ -331,19 +298,19 @@ void timekeeper_device::device_timer(emu_timer &timer, device_timer_id id, int p maxdays = 0x31; } - carry = inc_bcd( &m_date, MASK_DATE, 0x01, maxdays ); + carry = time_helper::inc_bcd( &m_date, MASK_DATE, 0x01, maxdays ); } if( carry ) { - carry = inc_bcd( &m_month, MASK_MONTH, 0x01, 0x12 ); + carry = time_helper::inc_bcd( &m_month, MASK_MONTH, 0x01, 0x12 ); } if( carry ) { - carry = inc_bcd( &m_year, MASK_YEAR, 0x00, 0x99 ); + carry = time_helper::inc_bcd( &m_year, MASK_YEAR, 0x00, 0x99 ); } if( carry ) { - carry = inc_bcd( &m_century, MASK_CENTURY, 0x00, 0x99 ); + carry = time_helper::inc_bcd( &m_century, MASK_CENTURY, 0x00, 0x99 ); if( type() == M48T35 || type() == M48T58 ) |