// license:BSD-3-Clause // copyright-holders:R. Belmont /*************************************************************************** macrtc.c - the real-time clock & NVRAM chip used in early 680x0 Macs, Apple part numbers 343-0040 (original) and 343-0042 (with extended PRAM) The IIgs has this chip also, but the VGC contains a relatively sophisticated logic block that offloads the low-level serial comms from the CPU, which makes it look quite different to software. ***************************************************************************/ #include "emu.h" #include "macrtc.h" #ifdef MAME_DEBUG #define LOG_RTC 0 #else #define LOG_RTC 0 #endif enum { RTC_STATE_NORMAL, RTC_STATE_WRITE, RTC_STATE_XPCOMMAND, RTC_STATE_XPWRITE }; //************************************************************************** // LIVE DEVICE //************************************************************************** // device type definition DEFINE_DEVICE_TYPE(RTC3430042, rtc3430042_device, "rtc3430042", "Apple 343-0042 clock/PRAM") //------------------------------------------------- // rtc4543_device - constructor //------------------------------------------------- rtc3430042_device::rtc3430042_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, RTC3430042, tag, owner, clock), device_rtc_interface(mconfig, *this), device_nvram_interface(mconfig, *this) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void rtc3430042_device::device_start() { // allocate timers m_clock_timer = timer_alloc(); m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); // state saving } void rtc3430042_device::device_reset() { m_rtc_rTCEnb = 0; m_rtc_rTCClk = 0; m_rtc_bit_count = 0; m_rtc_data_dir = 0; m_rtc_data_out = 0; m_rtc_cmd = 0; m_rtc_write_protect = 0; m_rtc_state = 0; ce_w(1); m_rtc_state = RTC_STATE_NORMAL; } //------------------------------------------------- // device_timer - handler timer events //------------------------------------------------- void rtc3430042_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { advance_seconds(); } //------------------------------------------------- // rtc_clock_updated - called by the RTC base class when the time changes //------------------------------------------------- void rtc3430042_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) { struct tm cur_time, mac_reference; uint32_t seconds; cur_time.tm_sec = second; cur_time.tm_min = minute; cur_time.tm_hour = hour; cur_time.tm_mday = day; cur_time.tm_mon = month-1; cur_time.tm_year = year+100; // assumes post-2000 current system time cur_time.tm_isdst = 0; /* The count starts on 1st January 1904 */ mac_reference.tm_sec = 0; mac_reference.tm_min = 0; mac_reference.tm_hour = 0; mac_reference.tm_mday = 1; mac_reference.tm_mon = 0; mac_reference.tm_year = 4; mac_reference.tm_isdst = 0; seconds = difftime(mktime(&cur_time), mktime(&mac_reference)); if (LOG_RTC) logerror("second count 0x%lX\n", (unsigned long) seconds); m_rtc_seconds[0] = seconds & 0xff; m_rtc_seconds[1] = (seconds >> 8) & 0xff; m_rtc_seconds[2] = (seconds >> 16) & 0xff; m_rtc_seconds[3] = (seconds >> 24) & 0xff; } /* write the rTCEnb state */ WRITE_LINE_MEMBER( rtc3430042_device::ce_w ) { if (state && (! m_rtc_rTCEnb)) { /* rTCEnb goes high (inactive) */ m_rtc_rTCEnb = 1; /* abort current transmission */ m_rtc_data_byte = m_rtc_bit_count = m_rtc_data_dir = m_rtc_data_out = 0; m_rtc_state = RTC_STATE_NORMAL; } else if ((!state) && m_rtc_rTCEnb) { /* rTCEnb goes low (active) */ m_rtc_rTCEnb = 0; /* abort current transmission */ m_rtc_data_byte = m_rtc_bit_count = m_rtc_data_dir = m_rtc_data_out = 0; m_rtc_state = RTC_STATE_NORMAL; } m_rtc_rTCEnb = state; } WRITE_LINE_MEMBER( rtc3430042_device::clk_w ) { if ((!state) && (m_rtc_rTCClk)) { rtc_shift_data(m_data_latch & 0x01); } m_rtc_rTCClk = state; } READ_LINE_MEMBER( rtc3430042_device::data_r ) { return m_rtc_data_out; } WRITE_LINE_MEMBER( rtc3430042_device::data_w ) { m_data_latch = state; } /* shift data (called on rTCClk high-to-low transition (?)) */ void rtc3430042_device::rtc_shift_data(int data) { if (m_rtc_rTCEnb) /* if enable line inactive (high), do nothing */ return; if (m_rtc_data_dir) { /* RTC -> VIA transmission */ m_rtc_data_out = (m_rtc_data_byte >> --m_rtc_bit_count) & 0x01; if (LOG_RTC) logerror("RTC shifted new data %d\n", m_rtc_data_out); } else { /* VIA -> RTC transmission */ m_rtc_data_byte = (m_rtc_data_byte << 1) | (data ? 1 : 0); if (++m_rtc_bit_count == 8) { /* if one byte received, send to command interpreter */ rtc_execute_cmd(m_rtc_data_byte); } } } /* Executes a command. Called when the first byte after "enable" is received, and when the data byte after a write command is received. */ void rtc3430042_device::rtc_execute_cmd(int data) { int i; if (LOG_RTC) printf("rtc_execute_cmd: data=%x, state=%x\n", data, m_rtc_state); if (m_rtc_state == RTC_STATE_XPCOMMAND) { m_rtc_xpaddr = ((m_rtc_cmd & 7)<<5) | ((data&0x7c)>>2); if ((m_rtc_cmd & 0x80) != 0) { // read command if (LOG_RTC) printf("RTC: Reading extended address %x = %x\n", m_rtc_xpaddr, m_pram[m_rtc_xpaddr]); m_rtc_data_dir = 1; m_rtc_data_byte = m_pram[m_rtc_xpaddr]; m_rtc_state = RTC_STATE_NORMAL; } else { // write command m_rtc_state = RTC_STATE_XPWRITE; m_rtc_data_byte = 0; m_rtc_bit_count = 0; } } else if (m_rtc_state == RTC_STATE_XPWRITE) { if (LOG_RTC) printf("RTC: writing %x to extended address %x\n", data, m_rtc_xpaddr); m_pram[m_rtc_xpaddr] = data; m_rtc_state = RTC_STATE_NORMAL; } else if (m_rtc_state == RTC_STATE_WRITE) { m_rtc_state = RTC_STATE_NORMAL; /* Writing an RTC register */ i = (m_rtc_cmd >> 2) & 0x1f; if (m_rtc_write_protect && (i != 13)) /* write-protection : only write-protect can be written again */ return; switch(i) { case 0: case 1: case 2: case 3: /* seconds register */ case 4: case 5: case 6: case 7: /* ??? (not described in IM III) */ { /* after various tries, I assumed m_rtc_seconds[4+i] is mapped to m_rtc_seconds[i] */ if (LOG_RTC) logerror("RTC clock write, address = %X, data = %X\n", i, (int) m_rtc_data_byte); m_rtc_seconds[i & 3] = m_rtc_data_byte; // TODO: call the base class's time set here } break; case 8: case 9: case 10: case 11: /* RAM address $10-$13 */ if (LOG_RTC) printf("PRAM write, address = %X, data = %X\n", i, (int) m_rtc_data_byte); m_pram[i] = m_rtc_data_byte; break; case 12: /* Test register - do nothing */ if (LOG_RTC) logerror("RTC write to test register, data = %X\n", (int) m_rtc_data_byte); break; case 13: /* Write-protect register */ if (LOG_RTC) printf("RTC write to write-protect register, data = %X\n", (int) m_rtc_data_byte&0x80); m_rtc_write_protect = (m_rtc_data_byte & 0x80) ? true : false; break; case 16: case 17: case 18: case 19: /* RAM address $00-$0f */ case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: if (LOG_RTC) printf("PRAM write, address = %X, data = %X\n", i, (int) m_rtc_data_byte); m_pram[i] = m_rtc_data_byte; break; default: printf("Unknown RTC write command : %X, data = %d\n", (int) m_rtc_cmd, (int) m_rtc_data_byte); break; } } else { // always save this byte to m_rtc_cmd m_rtc_cmd = m_rtc_data_byte; if ((m_rtc_cmd & 0x78) == 0x38) // extended command { m_rtc_state = RTC_STATE_XPCOMMAND; m_rtc_data_byte = 0; m_rtc_bit_count = 0; } else { if (m_rtc_cmd & 0x80) { m_rtc_state = RTC_STATE_NORMAL; /* Reading an RTC register */ m_rtc_data_dir = 1; i = (m_rtc_cmd >> 2) & 0x1f; switch(i) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: m_rtc_data_byte = m_rtc_seconds[i & 3]; if (LOG_RTC) printf("RTC clock read, address = %X -> data = %X\n", i, m_rtc_data_byte); break; case 8: case 9: case 10: case 11: if (LOG_RTC) printf("PRAM read, address = %X data = %x\n", i, m_pram[i]); m_rtc_data_byte = m_pram[i]; break; case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: if (LOG_RTC) printf("PRAM read, address = %X data = %x\n", i, m_pram[i]); m_rtc_data_byte = m_pram[i]; break; default: if (LOG_RTC) logerror("Unknown RTC read command : %X\n", (int) m_rtc_cmd); m_rtc_data_byte = 0; break; } } else { /* Writing an RTC register */ /* wait for extra data byte */ if (LOG_RTC) logerror("RTC write, waiting for data byte : %X\n", (int) m_rtc_cmd); m_rtc_state = RTC_STATE_WRITE; m_rtc_data_byte = 0; m_rtc_bit_count = 0; } } } } void rtc3430042_device::nvram_default() { memset(m_pram, 0, 0x100); } void rtc3430042_device::nvram_read(emu_file &file) { file.read(m_pram, 0x100); } void rtc3430042_device::nvram_write(emu_file &file) { file.write(m_pram, 0x100); }