diff --git a/src/emu/bus/dmv/k803.c b/src/emu/bus/dmv/k803.c index 4e57aea8280..7f748cc4806 100644 --- a/src/emu/bus/dmv/k803.c +++ b/src/emu/bus/dmv/k803.c @@ -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); } diff --git a/src/emu/dirtc.c b/src/emu/dirtc.c index 68290dfb162..988024c7b48 100644 --- a/src/emu/dirtc.c +++ b/src/emu/dirtc.c @@ -177,6 +177,10 @@ void device_rtc_interface::advance_minutes() m_register[RTC_HOUR] = 0; advance_days(); } + else + { + clock_updated(); + } } diff --git a/src/emu/machine/mm58167.c b/src/emu/machine/mm58167.c index 40a93285480..962b681f39d 100644 --- a/src/emu/machine/mm58167.c +++ b/src/emu/machine/mm58167.c @@ -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) { diff --git a/src/emu/machine/mm58167.h b/src/emu/machine/mm58167.h index b54c743fc13..fed17010d20 100644 --- a/src/emu/machine/mm58167.h +++ b/src/emu/machine/mm58167.h @@ -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;