summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/pcf8593.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/pcf8593.cpp')
-rw-r--r--src/devices/machine/pcf8593.cpp285
1 files changed, 285 insertions, 0 deletions
diff --git a/src/devices/machine/pcf8593.cpp b/src/devices/machine/pcf8593.cpp
new file mode 100644
index 00000000000..48e002fdf2d
--- /dev/null
+++ b/src/devices/machine/pcf8593.cpp
@@ -0,0 +1,285 @@
+// license:BSD-3-Clause
+// copyright-holders:Tim Schuerewegen
+/*********************************************************************
+
+ Philips PCF8593 CMOS clock/calendar circuit
+
+ (c) 2001-2007 Tim Schuerewegen
+
+*********************************************************************/
+
+#include "pcf8593.h"
+
+
+/***************************************************************************
+ PARAMETERS/CONSTANTS/MACROS
+***************************************************************************/
+
+#define LOG_LEVEL 1
+#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+
+// get/set date
+#define RTC_GET_DATE_YEAR ((m_data[5] >> 6) & 3)
+#define RTC_SET_DATE_YEAR(x) m_data[5] = (m_data[5] & 0x3F) | (((x) % 4) << 6)
+#define RTC_GET_DATE_MONTH bcd_to_integer( m_data[6])
+#define RTC_SET_DATE_MONTH(x) m_data[6] = convert_to_bcd( x)
+#define RTC_GET_DATE_DAY (bcd_to_integer( m_data[5] & 0x3F))
+#define RTC_SET_DATE_DAY(x) m_data[5] = (m_data[5] & 0xC0) | convert_to_bcd( x)
+
+// get/set time
+#define RTC_GET_TIME_HOUR bcd_to_integer( m_data[4])
+#define RTC_SET_TIME_HOUR(x) m_data[4] = convert_to_bcd( x)
+#define RTC_GET_TIME_MINUTE bcd_to_integer( m_data[3])
+#define RTC_SET_TIME_MINUTE(x) m_data[3] = convert_to_bcd( x)
+#define RTC_GET_TIME_SECOND bcd_to_integer( m_data[2])
+#define RTC_SET_TIME_SECOND(x) m_data[2] = convert_to_bcd( x)
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type PCF8593 = &device_creator<pcf8593_device>;
+
+
+//-------------------------------------------------
+// pcf8593_device - constructor
+//-------------------------------------------------
+
+pcf8593_device::pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, PCF8593, "PCF8593 RTC", tag, owner, clock, "pcf8593", __FILE__),
+ device_rtc_interface(mconfig, *this),
+ device_nvram_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void pcf8593_device::device_start()
+{
+ _logerror( 0, ("pcf8593_init\n"));
+ memset(m_register, 0, sizeof(m_register));
+ m_timer = timer_alloc(TIMER_UPDATE_COUNTER);
+ m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void pcf8593_device::device_reset()
+{
+ _logerror( 0, ("pcf8593_reset\n"));
+ m_pin_scl = 1;
+ m_pin_sda = 1;
+ m_active = FALSE;
+ m_inp = 0;
+ m_mode = RTC_MODE_RECV;
+ m_bits = 0;
+ m_pos = 0;
+ clear_buffer_rx();
+ set_time(true, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND);
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void pcf8593_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_UPDATE_COUNTER:
+ _logerror( 2, ("pcf8593_timer_callback (%d)\n", param));
+ // check if counting is enabled
+ if (!(m_data[0] & 0x80))
+ advance_seconds();
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// rtc_clock_updated -
+//-------------------------------------------------
+
+void pcf8593_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ RTC_SET_TIME_SECOND(second);
+ RTC_SET_TIME_MINUTE(minute);
+ RTC_SET_TIME_HOUR(hour);
+ RTC_SET_DATE_DAY(day);
+ RTC_SET_DATE_MONTH(month);
+ RTC_SET_DATE_YEAR(year);
+}
+
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void pcf8593_device::nvram_default()
+{
+ memset(m_data, 0, sizeof(m_data));
+}
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+void pcf8593_device::nvram_read(emu_file &file)
+{
+ file.read(m_data, sizeof(m_data));
+}
+
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+void pcf8593_device::nvram_write(emu_file &file)
+{
+ file.write(m_data, sizeof(m_data));
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_scl
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER(pcf8593_device::scl_w)
+{
+ // send bit
+ if ((m_active) && (!m_pin_scl) && (state))
+ {
+ switch (m_mode)
+ {
+ // HOST -> RTC
+ case RTC_MODE_RECV :
+ {
+ // get bit
+ if (m_pin_sda) m_data_recv[m_data_recv_index] = m_data_recv[m_data_recv_index] | (0x80 >> m_bits);
+ m_bits++;
+ // bit 9 = end
+ if (m_bits > 8)
+ {
+ _logerror( 2, ("pcf8593_write_byte(%02X)\n", m_data_recv[m_data_recv_index]));
+ // enter receive mode when 1st byte = 0xA3
+ if ((m_data_recv[0] == 0xA3) && (m_data_recv_index == 0))
+ {
+ m_mode = RTC_MODE_SEND;
+ }
+ // A2 + xx = "read from pos xx" command
+ if ((m_data_recv[0] == 0xA2) && (m_data_recv_index == 1))
+ {
+ m_pos = m_data_recv[1];
+ }
+ // A2 + xx + .. = write byte
+ if ((m_data_recv[0] == 0xA2) && (m_data_recv_index >= 2))
+ {
+ UINT8 rtc_pos, rtc_val;
+ rtc_pos = m_data_recv[1] + (m_data_recv_index - 2);
+ rtc_val = m_data_recv[m_data_recv_index];
+ //if (rtc_pos == 0) rtc_val = rtc_val & 3; // what is this doing here?
+ m_data[rtc_pos] = rtc_val;
+ set_time(false, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND);
+ }
+ // next byte
+ m_bits = 0;
+ m_data_recv_index++;
+ }
+ }
+ break;
+ // RTC -> HOST
+ case RTC_MODE_SEND :
+ {
+ // set bit
+ m_inp = (m_data[m_pos] >> (7 - m_bits)) & 1;
+ m_bits++;
+ // bit 9 = end
+ if (m_bits > 8)
+ {
+ _logerror( 2, ("pcf8593_read_byte(%02X)\n", m_data[m_pos]));
+ // end ?
+ if (m_pin_sda)
+ {
+ _logerror( 2, ("pcf8593 end\n"));
+ m_mode = RTC_MODE_RECV;
+ clear_buffer_rx();
+ }
+ // next byte
+ m_bits = 0;
+ m_pos++;
+ }
+ }
+ break;
+ }
+ }
+ // save scl
+ m_pin_scl = state;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_sda_w
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER(pcf8593_device::sda_w)
+{
+ // clock is high
+ if (m_pin_scl)
+ {
+ // log init I2C
+ if (state) _logerror( 1, ("pcf8593 init i2c\n"));
+ // start condition (high to low when clock is high)
+ if ((!state) && (m_pin_sda))
+ {
+ _logerror( 1, ("pcf8593 start condition\n"));
+ m_active = TRUE;
+ m_bits = 0;
+ m_data_recv_index = 0;
+ clear_buffer_rx();
+ //m_pos = 0;
+ }
+ // stop condition (low to high when clock is high)
+ if ((state) && (!m_pin_sda))
+ {
+ _logerror( 1, ("pcf8593 stop condition\n"));
+ m_active = FALSE;
+ }
+ }
+ // save sda
+ m_pin_sda = state;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_sda_r
+-------------------------------------------------*/
+
+READ_LINE_MEMBER(pcf8593_device::sda_r)
+{
+ return m_inp;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_clear_buffer_rx
+-------------------------------------------------*/
+
+void pcf8593_device::clear_buffer_rx()
+{
+ memset(&m_data_recv[0], 0, sizeof( m_data_recv));
+ m_data_recv_index = 0;
+}