MM58167: implemented IRQs and counters write, this allow to pass the K803 diagnostic test. (nw)

dirtc: call clock_updated() after increasing the minutes counter. (nw)
This commit is contained in:
Sandro Ronco 2014-11-07 22:19:16 +01:00
parent 98c4b826c3
commit 55d38c3753
4 changed files with 102 additions and 2 deletions

View File

@ -129,5 +129,5 @@ WRITE_LINE_MEMBER(dmv_k803_device::rtc_irq_w)
void dmv_k803_device::update_int()
{
bool state = ((m_latch & 0x80) && m_rtc_int);
m_bus->m_out_irq_cb(state ? ASSERT_LINE : CLEAR_LINE);
m_bus->m_out_int_cb(state ? ASSERT_LINE : CLEAR_LINE);
}

View File

@ -177,6 +177,10 @@ void device_rtc_interface::advance_minutes()
m_register[RTC_HOUR] = 0;
advance_days();
}
else
{
clock_updated();
}
}

View File

@ -2,7 +2,7 @@
mm58167.c - National Semiconductor MM58167 real-time clock emulation
TODO: alarms and IRQs not used by the Apple /// and aren't implemented.
TODO: standby interrupt
**********************************************************************/
@ -70,6 +70,8 @@ void mm58167_device::device_start()
// state saving
save_item(NAME(m_regs));
save_item(NAME(m_milliseconds));
save_item(NAME(m_comparator_state));
}
@ -82,7 +84,9 @@ void mm58167_device::device_reset()
set_current_time(machine());
m_regs[R_CTL_STATUS] = 0; // not busy
m_regs[R_CTL_IRQSTATUS] = 0;
m_milliseconds = 0;
m_comparator_state = false;
}
@ -101,12 +105,49 @@ void mm58167_device::device_timer(emu_timer &timer, device_timer_id id, int para
if (m_milliseconds >= 999)
{
int old_seconds = m_regs[R_CNT_SECONDS];
int old_minutes = m_regs[R_CNT_MINUTES];
int old_hours = m_regs[R_CNT_HOURS];
int old_dayofmonth = m_regs[R_CNT_DAYOFMONTH];
int old_dayofweek = m_regs[R_CNT_DAYOFWEEK];
int old_month = m_regs[R_CNT_MONTH];
advance_seconds();
m_milliseconds = 0;
if ((m_regs[R_CTL_IRQCONTROL] & 0x04) && m_regs[R_CNT_SECONDS] != old_seconds) set_irq(2); // every second
if ((m_regs[R_CTL_IRQCONTROL] & 0x08) && m_regs[R_CNT_MINUTES] != old_minutes) set_irq(3); // every minute
if ((m_regs[R_CTL_IRQCONTROL] & 0x10) && m_regs[R_CNT_HOURS] != old_hours) set_irq(4); // every hour
if ((m_regs[R_CTL_IRQCONTROL] & 0x20) && m_regs[R_CNT_DAYOFMONTH] != old_dayofmonth) set_irq(5); // every day
if ((m_regs[R_CTL_IRQCONTROL] & 0x40) && m_regs[R_CNT_DAYOFWEEK] < old_dayofweek) set_irq(6); // every week
if ((m_regs[R_CTL_IRQCONTROL] & 0x80) && m_regs[R_CNT_MONTH] != old_month) set_irq(7); // every month
}
m_regs[R_CNT_MILLISECONDS] = make_bcd(m_milliseconds % 10);
m_regs[R_CNT_HUNDTENTHS] = make_bcd(m_milliseconds / 10);
// 10Hz IRQ
if ((m_regs[R_CTL_IRQCONTROL] & 0x02) && (m_milliseconds % 100) == 0)
set_irq(1);
// comparator IRQ
bool new_state = true;
for (int i = R_CNT_MILLISECONDS; i <= R_CNT_MONTH; i++)
{
// nibbles that have the 2 MSB set always compares true
// Milliseconds use only the high nibble and Day of Week only the low nibble
if ((i != R_CNT_MILLISECONDS && (m_regs[i + 8] & 0x0c) != 0x0c && (m_regs[i + 8] & 0x0f) != (m_regs[i] & 0x0f)) ||
(i != R_CNT_DAYOFWEEK && (m_regs[i + 8] & 0xc0) != 0xc0 && (m_regs[i + 8] & 0xf0) != (m_regs[i] & 0xf0)))
{
new_state = false;
break;
}
}
if ((m_regs[R_CTL_IRQCONTROL] & 0x01) && !m_comparator_state && new_state) // positive-edge-triggered
set_irq(0);
m_comparator_state = new_state;
}
@ -124,9 +165,36 @@ void mm58167_device::rtc_clock_updated(int year, int month, int day, int day_of_
m_regs[R_CNT_MONTH] = make_bcd(month); // month (BCD)
}
void mm58167_device::set_irq(int bit)
{
m_regs[R_CTL_IRQSTATUS] |= (1 << bit);
m_irq_w(ASSERT_LINE);
}
void mm58167_device::update_rtc()
{
set_clock_register(RTC_SECOND, bcd_to_integer(m_regs[R_CNT_SECONDS]));
set_clock_register(RTC_MINUTE, bcd_to_integer(m_regs[R_CNT_MINUTES]));
set_clock_register(RTC_HOUR, bcd_to_integer(m_regs[R_CNT_HOURS]));
set_clock_register(RTC_DAY, bcd_to_integer(m_regs[R_CNT_DAYOFMONTH]));
set_clock_register(RTC_DAY_OF_WEEK, bcd_to_integer(m_regs[R_CNT_DAYOFWEEK]));
set_clock_register(RTC_MONTH, bcd_to_integer(m_regs[R_CNT_MONTH]));
m_milliseconds = (bcd_to_integer(m_regs[R_CNT_HUNDTENTHS]) * 10) + (bcd_to_integer(m_regs[R_CNT_MILLISECONDS] >> 4) % 10);
}
READ8_MEMBER(mm58167_device::read)
{
// printf("read reg %x = %02x\n", offset, m_regs[offset]);
if (offset == R_CTL_IRQSTATUS && !space.debugger_access())
{
// reading the IRQ status clears IRQ line and IRQ status
UINT8 data = m_regs[offset];
m_regs[R_CTL_IRQSTATUS] = 0;
m_irq_w(CLEAR_LINE);
return data;
}
return m_regs[offset];
}
@ -141,11 +209,35 @@ WRITE8_MEMBER(mm58167_device::write)
switch (offset)
{
case R_CNT_MILLISECONDS:
case R_CNT_HUNDTENTHS:
case R_CNT_SECONDS:
case R_CNT_MINUTES:
case R_CNT_HOURS:
case R_CNT_DAYOFWEEK:
case R_CNT_DAYOFMONTH:
case R_CNT_MONTH:
m_regs[offset] = data;
update_rtc();
break;
// any write to this starts at the current time and zero milliseconds
case R_CTL_GOCMD:
m_milliseconds = 0;
break;
case R_CTL_RESETCOUNTERS:
if (data == 0xff)
{
for (int i = R_CNT_MILLISECONDS; i <= R_CNT_MONTH; i++)
{
m_regs[i] = 0;
}
update_rtc();
}
break;
case R_CTL_RESETRAM:
if (data == 0xff)
{

View File

@ -53,9 +53,13 @@ protected:
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second);
virtual bool rtc_feature_leap_year() { return true; }
void set_irq(int bit);
void update_rtc();
private:
int m_regs[32];
int m_milliseconds;
bool m_comparator_state;
// timers
emu_timer *m_clock_timer;