mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
-Added: Dallas DS1386-8K and DS1386-32K timekeepers (largely untested). [Ryan Holtz]
This commit is contained in:
parent
4d75e88ddd
commit
8682c73305
@ -669,6 +669,18 @@ if (MACHINES["DS1315"]~=null) then
|
||||
}
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
594
src/devices/machine/ds1386.cpp
Normal file
594
src/devices/machine/ds1386.cpp
Normal file
@ -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];
|
||||
}
|
210
src/devices/machine/ds1386.h
Normal file
210
src/devices/machine/ds1386.h
Normal file
@ -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
|
@ -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)
|
||||
|
51
src/devices/machine/timehelp.h
Normal file
51
src/devices/machine/timehelp.h
Normal file
@ -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
|
@ -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 )
|
||||
|
Loading…
Reference in New Issue
Block a user