summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/ds17x85.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/ds17x85.cpp')
-rw-r--r--src/devices/machine/ds17x85.cpp286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/devices/machine/ds17x85.cpp b/src/devices/machine/ds17x85.cpp
new file mode 100644
index 00000000000..af6837cf621
--- /dev/null
+++ b/src/devices/machine/ds17x85.cpp
@@ -0,0 +1,286 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Dallas DS17x85/DS17x87 Real Time Clocks with extended NVSRAM
+
+ These MC146818-compatible RTCs overlay the last 64 bytes of user
+ RAM (not provided by the MC146818) with a second page of registers,
+ including a Y2K-updated century count and registers for indirectly
+ accessing extended SRAM which is backed with a separate auxiliary
+ battery power input.
+
+ The DS1685 and DS17x85 use conventional PDIP/SO/TSOP packages,
+ while the DS1687 and DS17x87 integrate battery, oscillator and chip
+ into one of Dallas's trademark EDIPs. They are indistinguishable
+ from the perspective of software.
+
+ Currently unemulated features include:
+ - Kickstart input
+ - Date alarm wakeup
+ - Increment in progress flag
+ - RAM clear function (software-enabled, hardware-triggered)
+ - 32.768 kHz frequency option for SQW output
+
+**********************************************************************/
+
+#include "emu.h"
+#include "ds17x85.h"
+
+#define VERBOSE 0
+#include "logmacro.h"
+
+// device type definitions
+DEFINE_DEVICE_TYPE(DS1685, ds1685_device, "ds1685", "DS1685 RTC")
+DEFINE_DEVICE_TYPE(DS1687, ds1687_device, "ds1687", "DS1687 RTC")
+DEFINE_DEVICE_TYPE(DS17285, ds17285_device, "ds17285", "DS17285 RTC")
+DEFINE_DEVICE_TYPE(DS17287, ds17287_device, "ds17287", "DS17287 RTC")
+DEFINE_DEVICE_TYPE(DS17485, ds17485_device, "ds17485", "DS17485 RTC")
+DEFINE_DEVICE_TYPE(DS17487, ds17487_device, "ds17487", "DS17487 RTC")
+DEFINE_DEVICE_TYPE(DS17885, ds17885_device, "ds17885", "DS17885 RTC")
+DEFINE_DEVICE_TYPE(DS17887, ds17887_device, "ds17887", "DS17887 RTC")
+
+//-------------------------------------------------
+// ds17x85_device - constructor
+//-------------------------------------------------
+
+ds17x85_device::ds17x85_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 model, u32 extram_size)
+ : mc146818_device(mconfig, type, tag, owner, clock)
+ , m_model(model)
+ , m_extram_size(extram_size)
+ , m_smi_stack1(0)
+{
+ m_century_index = REG_EXT_CENTURY;
+}
+
+//-------------------------------------------------
+// ds1685_device - constructor
+//-------------------------------------------------
+
+ds1685_device::ds1685_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds17x85_device(mconfig, DS1685, tag, owner, clock, 0x71, 128)
+{
+}
+
+//-------------------------------------------------
+// ds1687_device - constructor
+//-------------------------------------------------
+
+ds1687_device::ds1687_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds17x85_device(mconfig, DS1687, tag, owner, clock, 0x71, 128)
+{
+}
+
+//-------------------------------------------------
+// ds17285_device - constructor
+//-------------------------------------------------
+
+ds17285_device::ds17285_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds17x85_device(mconfig, DS17285, tag, owner, clock, 0x72, 2048)
+{
+}
+
+//-------------------------------------------------
+// ds17287_device - constructor
+//-------------------------------------------------
+
+ds17287_device::ds17287_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds17x85_device(mconfig, DS17287, tag, owner, clock, 0x72, 2048)
+{
+}
+
+//-------------------------------------------------
+// ds17485_device - constructor
+//-------------------------------------------------
+
+ds17485_device::ds17485_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds17x85_device(mconfig, DS17485, tag, owner, clock, 0x74, 4096)
+{
+}
+
+//-------------------------------------------------
+// ds17487_device - constructor
+//-------------------------------------------------
+
+ds17487_device::ds17487_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds17x85_device(mconfig, DS17487, tag, owner, clock, 0x74, 4096)
+{
+}
+
+//-------------------------------------------------
+// ds17885_device - constructor
+//-------------------------------------------------
+
+ds17885_device::ds17885_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds17x85_device(mconfig, DS17885, tag, owner, clock, 0x78, 8192)
+{
+}
+
+//-------------------------------------------------
+// ds17887_device - constructor
+//-------------------------------------------------
+
+ds17887_device::ds17887_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds17x85_device(mconfig, DS17887, tag, owner, clock, 0x78, 8192)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ds17x85_device::device_start()
+{
+ mc146818_device::device_start();
+
+ save_item(NAME(m_smi_stack1));
+}
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void ds17x85_device::nvram_default()
+{
+ mc146818_device::nvram_default();
+
+ if (!m_region.found())
+ {
+ // initialize read-only model number and 64-bit serial number
+ m_data[REG_EXT_MODEL] = m_model;
+ m_data[REG_EXT_SERIAL1] = 0x4d;
+ m_data[REG_EXT_SERIAL2] = 0x41;
+ m_data[REG_EXT_SERIAL3] = 0x4d;
+ m_data[REG_EXT_SERIAL4] = 0x45;
+ m_data[REG_EXT_SERIAL5] = 0x64;
+ m_data[REG_EXT_SERIAL6] = 0x76;
+ m_data[REG_EXT_SERIAL_CRC] = 0xf8;
+ }
+}
+
+//---------------------------------------------------------------
+// get_timer_bypass - get main clock divisor based on A register
+//---------------------------------------------------------------
+
+int ds17x85_device::get_timer_bypass() const
+{
+ int bypass;
+
+ // DV0 is used for bank switching only
+ switch (m_data[REG_A] & (REG_A_DV2 | REG_A_DV1))
+ {
+ case REG_A_DV1:
+ bypass = 7;
+ break;
+
+ case REG_A_DV2 | REG_A_DV1:
+ bypass = 22;
+ break;
+
+ default:
+ // TODO: other combinations of divider bits disable the oscillator
+ bypass = 22;
+ break;
+ }
+
+ return bypass;
+}
+
+//---------------------------------------------------------------
+// internal_set_address - latch address on ALE
+//---------------------------------------------------------------
+
+void ds17x85_device::internal_set_address(uint8_t address)
+{
+ // push previous address onto SMI recovery stack
+ m_data[REG_EXT_SMI_STACK3] = m_data[REG_EXT_SMI_STACK2];
+ m_data[REG_EXT_SMI_STACK2] = m_smi_stack1;
+ m_smi_stack1 = m_index | ((m_data[REG_A] & REG_A_DV0) ? 0x80 : 0x00);
+
+ mc146818_device::internal_set_address(address);
+}
+
+//---------------------------------------------------------------
+// internal_read - read internal data
+//---------------------------------------------------------------
+
+uint8_t ds17x85_device::internal_read(offs_t offset)
+{
+ if (offset >= 0x40 && (m_data[REG_A] & REG_A_DV0))
+ {
+ offset += 0x40;
+ switch (offset)
+ {
+ case REG_EXT_4A:
+ return m_data[offset] | REG_EXT_4A_VRT2;
+
+ case REG_EXT_RAM_DATA:
+ LOG("%s: Reading from extended RAM at %04X\n", machine().describe_context(),
+ m_data[REG_EXT_RAM_ADDRL] | offs_t(m_data[REG_EXT_RAM_ADDRH]) << 8);
+ offset = REG_EXT_RAM_BASE + (m_data[REG_EXT_RAM_ADDRL] | offs_t(m_data[REG_EXT_RAM_ADDRH]) << 8) % m_extram_size;
+ if ((m_data[REG_EXT_4A] & REG_EXT_4A_BME) && !machine().side_effects_disabled())
+ {
+ m_data[REG_EXT_RAM_ADDRL]++;
+ if (m_data[REG_EXT_RAM_ADDRL] == 0 && m_extram_size > 256)
+ m_data[REG_EXT_RAM_ADDRH]++;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return mc146818_device::internal_read(offset);
+}
+
+//---------------------------------------------------------------
+// internal_write - write internal data
+//---------------------------------------------------------------
+
+void ds17x85_device::internal_write(offs_t offset, uint8_t data)
+{
+ if (!machine().side_effects_disabled())
+ m_data[REG_EXT_WRITE_COUNTER]++;
+
+ if (offset >= 0x40 && (m_data[REG_A] & REG_A_DV0))
+ {
+ offset += 0x40;
+ switch (offset)
+ {
+ case REG_EXT_RAM_DATA:
+ LOG("%s: Writing %02X to extended RAM at %04X\n", machine().describe_context(),
+ data, m_data[REG_EXT_RAM_ADDRL] | offs_t(m_data[REG_EXT_RAM_ADDRH]) << 8);
+ offset = REG_EXT_RAM_BASE + (m_data[REG_EXT_RAM_ADDRL] | offs_t(m_data[REG_EXT_RAM_ADDRH]) << 8) % m_extram_size;
+ if ((m_data[REG_EXT_4A] & REG_EXT_4A_BME) && !machine().side_effects_disabled())
+ {
+ m_data[REG_EXT_RAM_ADDRL]++;
+ if (m_data[REG_EXT_RAM_ADDRL] == 0 && m_extram_size > 256)
+ m_data[REG_EXT_RAM_ADDRH]++;
+ }
+ break;
+
+ case REG_EXT_CENTURY:
+ case REG_EXT_DATE_ALARM: // TODO: unimplemented
+ case REG_EXT_4A: // TODO: mostly unimplemented
+ case REG_EXT_4B: // TODO: unimplemented
+ case REG_EXT_RAM_ADDRL:
+ break;
+
+ case REG_EXT_RAM_ADDRH:
+ if (m_extram_size <= 256)
+ {
+ logerror("%s: RTC extended addressing uses one byte only\n", machine().describe_context());
+ return;
+ }
+ break;
+
+ default:
+ logerror("%s: Write to reserved/read-only bank 1 register %02X\n", machine().describe_context(), offset - 0x40);
+ return;
+ }
+ }
+
+ mc146818_device::internal_write(offset, data);
+}