diff options
Diffstat (limited to 'src/devices/machine/ds17x85.cpp')
-rw-r--r-- | src/devices/machine/ds17x85.cpp | 286 |
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); +} |