// license:BSD-3-Clause // copyright-holders:Tim Lindner, R. Belmont /***************************************************************************************** ds1315.cpp Dallas Semiconductor's Phantom Time Chip DS1315. NOTE: writes are decoded, but the host's time will always be returned when asked. November 2017: R. Belmont added capability to emulate DS1216 and other DS121x parts where the clock sits in the same place as a ROM. The backing callback returns the ROM contents when the RTC is locked. April 2015: chip enable / chip reset / phantom writes by Karl-Ludwig Deisenhofer November 2001: implementation by Tim Lindner HOW DOES IT WORK? READS: pattern recognition (64 bits in correct order). When RTC finally enables 64 bits of data can be read. Chance of accidential pattern recognition is minimal. WRITES: two different locations (bits 0 and 1) are used to transfer data to the DS1315. 64 bit with time/date info are transmitted directly after recognition of the magic 64 bit pattern (see read above). **************************************************************************************/ #include "emu.h" #include "ds1315.h" #include "coreutil.h" DEFINE_DEVICE_TYPE(DS1315, ds1315_device, "ds1315", "Dallas DS1315 Phantom Time Chip") ds1315_device::ds1315_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, DS1315, tag, owner, clock), m_backing_read(*this), m_mode(), m_count(0) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void ds1315_device::device_start() { m_backing_read.resolve_safe(0xff); save_item(NAME(m_count)); save_item(NAME(m_mode)); save_item(NAME(m_raw_data)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void ds1315_device::device_reset() { chip_reset(); } /*************************************************************************** LOCAL VARIABLES ***************************************************************************/ static const uint8_t ds1315_pattern[] = { 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0 }; /*************************************************************************** IMPLEMENTATION ***************************************************************************/ // automated read, does all the work the real Dallas chip does uint8_t ds1315_device::read(offs_t offset) { if (m_mode == DS_SEEK_MATCHING) { if (offset & 1) { read_1(); } else { read_0(); } if (offset & 4) { m_count = 0; m_mode = DS_SEEK_MATCHING; } return m_backing_read(offset); } else if (m_mode == DS_CALENDAR_IO) { return read_data(); } return 0xff; // shouldn't happen, but compilers don't know that } /*------------------------------------------------- read_0 (actual data) -------------------------------------------------*/ uint8_t ds1315_device::read_0() { if (ds1315_pattern[m_count++] == 0) { if (m_count == 64) { /* entire pattern matched */ m_count = 0; m_mode = DS_CALENDAR_IO; fill_raw_data(); } return 0; } m_count = 0; m_mode = DS_SEEK_MATCHING; return 0; } /*------------------------------------------------- read_1 (actual data) -------------------------------------------------*/ uint8_t ds1315_device::read_1() { if (ds1315_pattern[m_count++] == 1) { m_count %= 64; return 0; } m_count = 0; m_mode = DS_SEEK_MATCHING; return 0; } /*------------------------------------------------- read_data -------------------------------------------------*/ uint8_t ds1315_device::read_data() { uint8_t result; if (m_mode == DS_CALENDAR_IO) { result = m_raw_data[m_count++]; if (m_count == 64) { m_mode = DS_SEEK_MATCHING; m_count = 0; } return result; } m_count = 0; return 0; } /*------------------------------------------------- fill_raw_data -------------------------------------------------*/ void ds1315_device::fill_raw_data() { /* This routine calls a standard 'C' library routine to get the current date and time and then fill in the raw data struct. */ system_time systime; int raw[8], i, j; /* get the current date/time from the core */ machine().current_datetime(systime); raw[0] = 0; /* tenths and hundreths of seconds are always zero */ raw[1] = dec_2_bcd(systime.local_time.second); raw[2] = dec_2_bcd(systime.local_time.minute); raw[3] = dec_2_bcd(systime.local_time.hour); raw[4] = dec_2_bcd((systime.local_time.weekday != 0) ? systime.local_time.weekday : 7); raw[5] = dec_2_bcd(systime.local_time.mday); raw[6] = dec_2_bcd(systime.local_time.month + 1); raw[7] = dec_2_bcd(systime.local_time.year - 1900); /* Epoch is 1900 */ /* Ok now we have the raw bcd bytes. Now we need to push them into our bit array */ for (i = 0; i < 64; i++) { j = i / 8; m_raw_data[i] = (raw[j] & 0x0001); raw[j] = raw[j] >> 1; } } /*------------------------------------------------- write_data -------------------------------------------------*/ uint8_t ds1315_device::write_data(offs_t offset) { static int write_count; if (write_count >= 64) write_count = 0; if (m_mode == DS_CALENDAR_IO) { m_raw_data[write_count++] = offset & 0x01; if (write_count == 64) { write_count = 0; m_mode = DS_SEEK_MATCHING; m_count = 0; input_raw_data(); } } return 0; // ignore } /*------------------------------------------------- ds1315_input_raw_data Routine is called when new date and time has been written to the clock chip. Currently we ignore setting the date and time in the clock chip. -------------------------------------------------*/ void ds1315_device::input_raw_data() { int raw[8], i, j; raw[0] = raw[1] = raw[2] = raw[3] = raw[4] = raw[5] = raw[6] = raw[7] = 0; uint8_t flag = 1; for (i = 0; i < 64; i++) { j = i / 8; if ((i % 8) == 0) flag = 1; if (m_raw_data[i] & 1) raw[j] |= flag; flag <<= 1; } raw[0] = bcd_2_dec(raw[0]); // hundreds of seconds raw[1] = bcd_2_dec(raw[1]); // seconds (often set to zero) raw[2] = bcd_2_dec(raw[2]); // minute raw[3] = bcd_2_dec(raw[3]); // hour raw[4] = bcd_2_dec(raw[4]); // weekday (10 for Friday ?!) raw[5] = bcd_2_dec(raw[5]); // mday raw[6] = bcd_2_dec(raw[6]); // month raw[7] = bcd_2_dec(raw[7]); // year (two digits) logerror("\nDS1315 RTC INPUT (WILL BE IGNORED) mm/dd/yy hh:mm:ss - %02d/%02d/%02d %02d/%02d/%02d", raw[6], raw[5], raw[7], raw[3], raw[2], raw[1] ); } /*------------------------------------------------- query and reset chip status -------------------------------------------------*/ bool ds1315_device::chip_enable() { return (m_mode == DS_CALENDAR_IO); } // Set a defined state (important for pattern detection) void ds1315_device::chip_reset() { memset(m_raw_data, 0, sizeof(m_raw_data)); m_count = 0; m_mode = DS_SEEK_MATCHING; }