macrtc.cpp: Updates [R. Belmont]

- Cleaned up, modernized, converted logging to logmacro.h
- Improved documentation comments
- Supports both the original 343-0040 (Mac 128/512) and the 343-0042-B (Mac II, Apple IIgs) with unique behavior
This commit is contained in:
arbee 2022-12-16 13:41:36 -05:00
parent 0c3654a5c9
commit 14c3d33e86
3 changed files with 230 additions and 166 deletions

View File

@ -144,7 +144,7 @@ public:
m_iwm(*this, "fdc"),
m_floppy(*this, "fdc:%d", 0U),
m_mackbd(*this, "kbd"),
m_rtc(*this,"rtc"),
m_rtc(*this, "rtc"),
m_screen(*this, "screen"),
m_dac(*this, "macdac"),
m_filter(*this, "dacfilter"),
@ -1182,6 +1182,8 @@ void mac128_state::mac128k(machine_config &config)
mac512ke(config);
m_ram->set_default_size("128K");
RTC3430040(config.replace(), m_rtc, 32.768_kHz_XTAL);
IWM(config.replace(), m_iwm, C7M);
m_iwm->phases_cb().set(FUNC(mac128_state::phases_w));
m_iwm->devsel_cb().set(FUNC(mac128_state::devsel_w));

View File

@ -2,27 +2,45 @@
// 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)
macrtc.cpp
Real-time clock & NVRAM chips used in early 680x0 Macs and the Apple IIgs.
Apple part numbers 343-0040 (original, 20 bytes of PRAM) and 343-0042-B (256 bytes of PRAM).
By R. Belmont, based on previous work by Nathan Woods and Raphael Nabet
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.
Commands and data are sent and received serially, bit 7 first.
For reading the chip, the data is valid after the falling edge of the clock.
For writing, the data must be valid before the falling edge of the clock.
The time is the number of seconds since midnight on January 1, 1904.
Commands:
R/W 00x0001 - Seconds (least significant byte)
R/W 00x0101 - Seconds (2nd byte)
R/W 00x1001 - Seconds (3rd byte)
R/W 00x1101 - Seconds (most significant byte)
0 0110001 - Test register
0 0110101 - Write protect bit (343-0040) (When set, only the WP bit itself can be changed)
0 01101xx - Write protect bit (343-0042-B)
R/W 010aa01 - 4 PRAM addresses (aa is the address)
R/W 1aaaa01 - 16 PRAM addresses (aaaa is the address)
R/W 0111aaa - Extended PRAM address (aaa is the sector number. Sectors are 32 bytes)
***************************************************************************/
#include "emu.h"
#include "macrtc.h"
#ifdef MAME_DEBUG
#define LOG_RTC 0
#else
#define LOG_RTC 0
#endif
#define LOG_GENERAL (1U << 0)
#define LOG_COMMANDS (1U << 1)
//#define VERBOSE (LOG_COMMANDS)
#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
enum
{
RTC_STATE_NORMAL,
RTC_STATE_NORMAL = 0,
RTC_STATE_WRITE,
RTC_STATE_XPCOMMAND,
RTC_STATE_XPWRITE
@ -33,21 +51,33 @@ enum
//**************************************************************************
// device type definition
DEFINE_DEVICE_TYPE(RTC3430042, rtc3430042_device, "rtc3430042", "Apple 343-0042 clock/PRAM")
DEFINE_DEVICE_TYPE(RTC3430040, rtc3430040_device, "rtc3430040", "Apple 343-0040 clock/PRAM")
DEFINE_DEVICE_TYPE(RTC3430042, rtc3430042_device, "rtc3430042", "Apple 343-0042-B 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),
rtc3430042_device::rtc3430042_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool hasBigPRAM)
: device_t(mconfig, type, tag, owner, clock),
device_rtc_interface(mconfig, *this),
device_nvram_interface(mconfig, *this),
m_is_big_PRAM(hasBigPRAM),
m_cko_cb(*this)
{
}
rtc3430042_device::rtc3430042_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: rtc3430042_device(mconfig, RTC3430042, tag, owner, clock, true)
{
}
rtc3430040_device::rtc3430040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: rtc3430042_device(mconfig, RTC3430040, tag, owner, clock, false)
{
}
void rtc3430042_device::device_resolve_objects()
{
m_cko_cb.resolve_safe();
@ -66,35 +96,36 @@ void rtc3430042_device::device_start()
m_cko = true;
// state saving
save_item(NAME(m_rtc_rTCEnb));
save_item(NAME(m_rtc_rTCClk));
save_item(NAME(m_rtc_data_byte));
save_item(NAME(m_rtc_bit_count));
save_item(NAME(m_rtc_data_dir));
save_item(NAME(m_rtc_data_out));
save_item(NAME(m_rtc_cmd));
save_item(NAME(m_rtc_write_protect));
save_item(NAME(m_rtc_seconds));
save_item(NAME(m_rTCEnb));
save_item(NAME(m_rTCClk));
save_item(NAME(m_data_byte));
save_item(NAME(m_bit_count));
save_item(NAME(m_data_dir));
save_item(NAME(m_data_out));
save_item(NAME(m_cmd));
save_item(NAME(m_write_protect));
save_item(NAME(m_test_mode));
save_item(NAME(m_seconds));
save_item(NAME(m_pram));
save_item(NAME(m_rtc_xpaddr));
save_item(NAME(m_rtc_state));
save_item(NAME(m_xpaddr));
save_item(NAME(m_state));
save_item(NAME(m_data_latch));
save_item(NAME(m_cko));
}
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;
m_rTCEnb = 0;
m_rTCClk = 0;
m_bit_count = 0;
m_data_dir = 0;
m_data_out = 0;
m_cmd = 0;
m_write_protect = 0;
m_state = 0;
ce_w(1);
m_rtc_state = RTC_STATE_NORMAL;
m_state = RTC_STATE_NORMAL;
}
//-------------------------------------------------
@ -128,7 +159,7 @@ void rtc3430042_device::rtc_clock_updated(int year, int month, int day, int day_
cur_time.tm_year = year+100; // assumes post-2000 current system time
cur_time.tm_isdst = 0;
/* The count starts on 1st January 1904 */
// The count starts on January 1, 1904 at midnight
mac_reference.tm_sec = 0;
mac_reference.tm_min = 0;
mac_reference.tm_hour = 0;
@ -139,51 +170,48 @@ void rtc3430042_device::rtc_clock_updated(int year, int month, int day, int day_
seconds = difftime(mktime(&cur_time), mktime(&mac_reference));
if (LOG_RTC)
logerror("second count 0x%lX\n", (unsigned long) seconds);
LOGMASKED(LOG_GENERAL, "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;
m_seconds[0] = seconds & 0xff;
m_seconds[1] = (seconds >> 8) & 0xff;
m_seconds[2] = (seconds >> 16) & 0xff;
m_seconds[3] = (seconds >> 24) & 0xff;
}
/* write the rTCEnb state */
/* write the chip enable state */
WRITE_LINE_MEMBER( rtc3430042_device::ce_w )
{
if (state && (! m_rtc_rTCEnb))
if (state && (! m_rTCEnb))
{
/* rTCEnb goes high (inactive) */
m_rtc_rTCEnb = 1;
m_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;
m_data_byte = m_bit_count = m_data_dir = m_data_out = 0;
m_state = RTC_STATE_NORMAL;
}
else if ((!state) && m_rtc_rTCEnb)
else if ((!state) && m_rTCEnb)
{
/* rTCEnb goes low (active) */
m_rtc_rTCEnb = 0;
m_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_data_byte = m_bit_count = m_data_dir = m_data_out = 0;
m_state = RTC_STATE_NORMAL;
}
m_rtc_rTCEnb = state;
m_rTCEnb = state;
}
WRITE_LINE_MEMBER( rtc3430042_device::clk_w )
{
if ((!state) && (m_rtc_rTCClk))
if ((!state) && (m_rTCClk))
{
rtc_shift_data(m_data_latch & 0x01);
}
m_rtc_rTCClk = state;
m_rTCClk = state;
}
READ_LINE_MEMBER( rtc3430042_device::data_r )
{
return m_rtc_data_out;
return m_data_out;
}
WRITE_LINE_MEMBER( rtc3430042_device::data_w )
@ -191,184 +219,187 @@ WRITE_LINE_MEMBER( rtc3430042_device::data_w )
m_data_latch = state;
}
/* shift data (called on rTCClk high-to-low transition (?)) */
/* 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 */
// Chip enable must be asserted for the chip to listen
if (m_rTCEnb)
{
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);
// sending data to the host
if (m_data_dir)
{
m_data_out = (m_data_byte >> --m_bit_count) & 0x01;
LOGMASKED(LOG_GENERAL, "RTC shifted new data %d\n", m_data_out);
}
else
{ /* VIA -> RTC transmission */
m_rtc_data_byte = (m_rtc_data_byte << 1) | (data ? 1 : 0);
{
// receiving data from the host
m_data_byte = (m_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);
m_bit_count++;
if (m_bit_count == 8)
{
// got a byte, send it to the state machine
rtc_execute_cmd(m_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. */
/* 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);
LOGMASKED(LOG_COMMANDS, "rtc_execute_cmd: data=%x, state=%x\n", data, m_state);
if (m_rtc_state == RTC_STATE_XPCOMMAND)
if (m_state == RTC_STATE_XPCOMMAND)
{
m_rtc_xpaddr = ((m_rtc_cmd & 7)<<5) | ((data&0x7c)>>2);
if ((m_rtc_cmd & 0x80) != 0)
m_xpaddr = ((m_cmd & 7)<<5) | ((data&0x7c)>>2);
if ((m_cmd & 0x80) != 0)
{
// read command
if (LOG_RTC)
printf("RTC: Reading extended address %x = %x\n", m_rtc_xpaddr, m_pram[m_rtc_xpaddr]);
LOGMASKED(LOG_COMMANDS, "RTC: Reading extended address %x = %x\n", m_xpaddr, m_pram[m_xpaddr]);
m_rtc_data_dir = 1;
m_rtc_data_byte = m_pram[m_rtc_xpaddr];
m_rtc_state = RTC_STATE_NORMAL;
m_data_dir = 1;
m_data_byte = m_pram[m_xpaddr];
m_state = RTC_STATE_NORMAL;
}
else
{
// write command
m_rtc_state = RTC_STATE_XPWRITE;
m_rtc_data_byte = 0;
m_rtc_bit_count = 0;
m_state = RTC_STATE_XPWRITE;
m_data_byte = 0;
m_bit_count = 0;
}
}
else if (m_rtc_state == RTC_STATE_XPWRITE)
else if (m_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;
LOGMASKED(LOG_COMMANDS, "RTC: writing %x to extended address %x\n", data, m_xpaddr);
m_pram[m_xpaddr] = data;
m_state = RTC_STATE_NORMAL;
}
else if (m_rtc_state == RTC_STATE_WRITE)
else if (m_state == RTC_STATE_WRITE)
{
m_rtc_state = RTC_STATE_NORMAL;
m_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 */
// Register write
i = (m_cmd >> 2) & 0x1f;
if (m_write_protect && (i != 13))
{
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
}
case 0: case 1: case 2: case 3: // seconds register
case 4: case 5: case 6: case 7: // bit 4 is don't care
LOGMASKED(LOG_COMMANDS, "RTC clock write, address = %X, data = %X\n", i, (int)m_data_byte);
m_seconds[i & 3] = m_data_byte;
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;
case 8: case 9: case 10: case 11: // PRAM addresses 0x10-0x13
LOGMASKED(LOG_COMMANDS, "PRAM write, address = %X, data = %X\n", i, (int)m_data_byte);
m_pram[i] = m_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);
// Test register - resets the seconds counter and increments it on the raw clock (32768 Hz) instead of once a second (not implemented)
LOGMASKED(LOG_COMMANDS, "RTC write to test register, data = %X\n", (int)m_data_byte);
m_test_mode = BIT(m_data_byte, 7);
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;
// Write protect - when set, all registers become read-only except this one
if (!m_is_big_PRAM)
{
if (m_cmd == 0x35) // b00110101 for 343-0040
{
LOGMASKED(LOG_COMMANDS, "RTC write to write-protect register, data = %X\n", (int)m_data_byte & 0x80);
m_write_protect = BIT(m_data_byte, 7);
}
else
{
logerror("macrtc: 343-0040 illegal write protect command %02x\n", m_cmd);
}
}
else
{
LOGMASKED(LOG_COMMANDS, "RTC write to write-protect register, data = %X\n", (int)m_data_byte & 0x80);
m_write_protect = BIT(m_data_byte, 7);
}
break;
case 16: case 17: case 18: case 19: /* RAM address $00-$0f */
case 16: case 17: case 18: case 19: // PRAM addresses 0x00-0x0f
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;
LOGMASKED(LOG_COMMANDS, "PRAM write, address = %X, data = %X\n", i, (int)m_data_byte);
m_pram[i] = m_data_byte;
break;
default:
printf("Unknown RTC write command : %X, data = %d\n", (int) m_rtc_cmd, (int) m_rtc_data_byte);
LOGMASKED(LOG_COMMANDS, "Unknown RTC write command : %X, data = %d\n", (int)m_cmd, (int)m_data_byte);
break;
}
}
else
{
// always save this byte to m_rtc_cmd
m_rtc_cmd = m_rtc_data_byte;
// always save this byte to m_cmd
m_cmd = m_data_byte;
if ((m_rtc_cmd & 0x78) == 0x38) // extended command
if ((m_cmd & 0x78) == 0x38) // extended command
{
m_rtc_state = RTC_STATE_XPCOMMAND;
m_rtc_data_byte = 0;
m_rtc_bit_count = 0;
m_state = RTC_STATE_XPCOMMAND;
m_data_byte = 0;
m_bit_count = 0;
}
else
{
if (m_rtc_cmd & 0x80)
if (m_cmd & 0x80)
{
m_rtc_state = RTC_STATE_NORMAL;
m_state = RTC_STATE_NORMAL;
/* Reading an RTC register */
m_rtc_data_dir = 1;
i = (m_rtc_cmd >> 2) & 0x1f;
// RTC register read
m_data_dir = 1;
i = (m_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);
m_data_byte = m_seconds[i & 3];
LOGMASKED(LOG_COMMANDS, "RTC clock read, address = %X -> data = %X\n", i, m_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];
LOGMASKED(LOG_COMMANDS, "PRAM read, address = %X data = %x\n", i, m_pram[i]);
m_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];
LOGMASKED(LOG_COMMANDS, "PRAM read, address = %X data = %x\n", i, m_pram[i]);
m_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;
LOGMASKED(LOG_COMMANDS, "Unknown RTC read command : %X\n", (int)m_cmd);
m_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;
// RTC register write - wait for data byte
LOGMASKED(LOG_COMMANDS, "RTC write, waiting for data byte : %X\n", (int)m_cmd);
m_state = RTC_STATE_WRITE;
m_data_byte = 0;
m_bit_count = 0;
}
}
}
@ -390,3 +421,15 @@ bool rtc3430042_device::nvram_write(util::write_stream &file)
size_t actual;
return !file.write(m_pram, 0x100, actual) && actual == 0x100;
}
bool rtc3430040_device::nvram_read(util::read_stream &file)
{
size_t actual;
return !file.read(m_pram, 20, actual) && actual == 20;
}
bool rtc3430040_device::nvram_write(util::write_stream &file)
{
size_t actual;
return !file.write(m_pram, 20, actual) && actual == 20;
}

View File

@ -25,8 +25,11 @@ class rtc3430042_device : public device_t,
public device_rtc_interface,
public device_nvram_interface
{
friend class rtc3430040_device;
public:
// construction/destruction
rtc3430042_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool hasBigPRAM);
rtc3430042_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_WRITE_LINE_MEMBER( ce_w );
@ -55,35 +58,40 @@ protected:
TIMER_CALLBACK_MEMBER(half_seconds_tick);
private:
bool m_is_big_PRAM;
devcb_write_line m_cko_cb;
/* state of rTCEnb and rTCClk lines */
uint8_t m_rtc_rTCEnb = 0;
uint8_t m_rtc_rTCClk = 0;
u8 m_rTCEnb = 0;
u8 m_rTCClk = 0;
/* serial transmit/receive register : bits are shifted in/out of this byte */
uint8_t m_rtc_data_byte = 0;
u8 m_data_byte = 0;
/* serial transmitted/received bit count */
uint8_t m_rtc_bit_count = 0;
u8 m_bit_count = 0;
/* direction of the current transfer (0 : VIA->RTC, 1 : RTC->VIA) */
uint8_t m_rtc_data_dir = 0;
u8 m_data_dir = 0;
/* when rtc_data_dir == 1, state of rTCData as set by RTC (-> data bit seen by VIA) */
uint8_t m_rtc_data_out = 0;
u8 m_data_out = 0;
/* set to 1 when command in progress */
uint8_t m_rtc_cmd = 0;
u8 m_cmd = 0;
/* write protect flag */
uint8_t m_rtc_write_protect = 0;
u8 m_write_protect = 0;
// test mode flag
u8 m_test_mode = 0;
/* internal seconds register */
uint8_t m_rtc_seconds[/*8*/4]{};
u8 m_seconds[/*8*/4]{};
/* 20-byte long PRAM, or 256-byte long XPRAM */
uint8_t m_pram[256]{};
u8 m_pram[256]{};
/* current extended address and RTC state */
uint8_t m_rtc_xpaddr = 0;
uint8_t m_rtc_state = 0;
uint8_t m_data_latch = 0;
u8 m_xpaddr = 0;
u8 m_state = 0;
u8 m_data_latch = 0;
bool m_cko = false;
// timers
@ -93,8 +101,19 @@ private:
void rtc_execute_cmd(int data);
};
class rtc3430040_device: public rtc3430042_device
{
public:
rtc3430040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
virtual bool nvram_read(util::read_stream &file) override;
virtual bool nvram_write(util::write_stream &file) override;
};
// device type definition
DECLARE_DEVICE_TYPE(RTC3430040, rtc3430040_device)
DECLARE_DEVICE_TYPE(RTC3430042, rtc3430042_device)
#endif // MAME_MACHINE_MACRTC_H