summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/ds17x85.cpp
blob: af6837cf62140d025d192ae1c15a77801a6c7011 (plain) (tree)





























































































































































































































































































                                                                                                                                                       
// 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);
}