diff options
author | Patrick Mackinlay <pmackinlay@hotmail.com> | 2020-08-10 14:45:10 +0700 |
---|---|---|
committer | Patrick Mackinlay <pmackinlay@hotmail.com> | 2020-08-10 14:45:10 +0700 |
commit | 89452e9f1449c4fc0af8af4447cb00195bea9910 (patch) | |
tree | 462f74590489a0c3ded1abbd085da1ea468d22d9 /src/devices/machine | |
parent | 331145ba0e1338dd5331c5ffe70684cff82ac810 (diff) |
icm7170: make it tick and generate interrupts
Diffstat (limited to 'src/devices/machine')
-rw-r--r-- | src/devices/machine/icm7170.cpp | 140 | ||||
-rw-r--r-- | src/devices/machine/icm7170.h | 1 |
2 files changed, 136 insertions, 5 deletions
diff --git a/src/devices/machine/icm7170.cpp b/src/devices/machine/icm7170.cpp index 77a507ba8a1..005626b6348 100644 --- a/src/devices/machine/icm7170.cpp +++ b/src/devices/machine/icm7170.cpp @@ -10,7 +10,7 @@ #include "icm7170.h" #include "coreutil.h" -#define VERBOSE (1) +#define VERBOSE (0) #include "logmacro.h" DEFINE_DEVICE_TYPE(ICM7170, icm7170_device, "icm7170", "Intersil/Renesas ICM7170 Real Time Clock") @@ -73,7 +73,8 @@ icm7170_device::icm7170_device(const machine_config &mconfig, const char *tag, d : device_t(mconfig, ICM7170, tag, owner, clock), device_rtc_interface(mconfig, *this), device_nvram_interface(mconfig, *this), - m_out_irq_cb(*this) + m_out_irq_cb(*this), + m_out_irq_state(false) { } @@ -87,9 +88,13 @@ void icm7170_device::device_start() m_out_irq_cb.resolve_safe(); m_timer = timer_alloc(ICM7170_TIMER_ID); - m_timer->adjust(attotime::never); + + // TODO: frequency should be based on input clock and divisor + m_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100)); + m_timer->enable(false); save_item(NAME(m_regs)); + save_item(NAME(m_out_irq_state)); } //------------------------------------------------- @@ -109,6 +114,93 @@ void icm7170_device::device_reset() void icm7170_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { + // advance hundredths + m_irq_status |= IRQ_BIT_100TH_SECOND; + if (m_regs[REG_CNT_100TH_SEC]++ == 99) + { + m_regs[REG_CNT_100TH_SEC] = 0; + + if (m_regs[REG_COMMAND] & CMD_REG_24_HOUR) + LOG("device_timer %02d-%02d-%02d %02d:%02d:%02d\n", + m_regs[REG_CNT_YEAR], m_regs[REG_CNT_MONTH], m_regs[REG_CNT_DAY], + m_regs[REG_CNT_HOURS], m_regs[REG_CNT_MINUTES], m_regs[REG_CNT_SECONDS]); + else + LOG("device_timer %02d-%02d-%02d %02d:%02d:%02d %s\n", + m_regs[REG_CNT_YEAR], m_regs[REG_CNT_MONTH], m_regs[REG_CNT_DAY], + m_regs[REG_CNT_HOURS] & 0xf, m_regs[REG_CNT_MINUTES], m_regs[REG_CNT_SECONDS], + (m_regs[REG_CNT_HOURS] & 0x80) ? "pm" : "am"); + + // advance seconds + m_irq_status |= IRQ_BIT_SECOND; + if (m_regs[REG_CNT_SECONDS]++ == 59) + { + m_regs[REG_CNT_SECONDS] = 0; + + // advance minutes + m_irq_status |= IRQ_BIT_MINUTE; + if (m_regs[REG_CNT_MINUTES]++ == 59) + { + m_regs[REG_CNT_MINUTES] = 0; + + // invert am/pm bit at 12:00 + if (!(m_regs[REG_COMMAND] & CMD_REG_24_HOUR) && (m_regs[REG_CNT_HOURS] & 0xf) == 11) + m_regs[REG_CNT_HOURS] ^= 0x80; + + // advance hours + m_irq_status |= IRQ_BIT_HOUR; + if (((m_regs[REG_COMMAND] & CMD_REG_24_HOUR) && (m_regs[REG_CNT_HOURS] == 23)) + || (!(m_regs[REG_COMMAND] & CMD_REG_24_HOUR) && (m_regs[REG_CNT_HOURS] & 0xf) == 12)) + { + if (m_regs[REG_COMMAND] & CMD_REG_24_HOUR) + m_regs[REG_CNT_HOURS] = 0; + else + m_regs[REG_CNT_HOURS] = (m_regs[REG_CNT_HOURS] & 0x80) | 1; + + // advance days + m_irq_status |= IRQ_BIT_DAY; + if (m_regs[REG_CNT_DAY]++ == gregorian_days_in_month(m_regs[REG_CNT_MONTH] & 0xf, (m_regs[REG_CNT_YEAR] & 0x7f) + 2000)) + { + m_regs[REG_CNT_DAY] = 1; + + // advance months + if (m_regs[REG_CNT_MONTH]++ == 12) + { + m_regs[REG_CNT_MONTH] = 1; + + // advance years + if (m_regs[REG_CNT_YEAR]++ == 99) + m_regs[REG_CNT_YEAR] = 0; + } + } + + // advance day of week + if (m_regs[REG_CNT_DAY_OF_WEEK]++ == 6) + m_regs[REG_CNT_DAY_OF_WEEK] = 0; + } + else + m_regs[REG_CNT_HOURS]++; + } + } + } + + // check tenths interrupt + if (!(m_regs[REG_CNT_100TH_SEC] % 10)) + m_irq_status |= IRQ_BIT_10TH_SECOND; + + // check alarm + if (m_irq_mask & IRQ_BIT_ALARM) + if (BIT(m_regs[REG_RAM_YEAR], 7) || !((m_regs[REG_RAM_YEAR] ^ m_regs[REG_CNT_YEAR]) & 0x7f)) + if (BIT(m_regs[REG_RAM_MONTH], 7) || !((m_regs[REG_RAM_MONTH] ^ m_regs[REG_CNT_MONTH]) & 0xf)) + if (BIT(m_regs[REG_RAM_DAY], 7) || !((m_regs[REG_RAM_DAY] ^ m_regs[REG_CNT_DAY]) & 0x1f)) + if (BIT(m_regs[REG_RAM_HOURS], 6) + || ((m_regs[REG_COMMAND] & CMD_REG_24_HOUR) && !((m_regs[REG_RAM_HOURS] ^ m_regs[REG_CNT_HOURS]) & 0x1f)) + || (!(m_regs[REG_COMMAND] & CMD_REG_24_HOUR) && !((m_regs[REG_RAM_HOURS] ^ m_regs[REG_CNT_HOURS]) & 0x8f))) + if (BIT(m_regs[REG_RAM_MINUTES], 7) || !((m_regs[REG_RAM_MINUTES] ^ m_regs[REG_CNT_MINUTES]) & 0x3f)) + if (BIT(m_regs[REG_RAM_SECONDS], 7) || !((m_regs[REG_RAM_SECONDS] ^ m_regs[REG_CNT_SECONDS]) & 0x3f)) + if (BIT(m_regs[REG_RAM_100TH_SEC], 7) || !((m_regs[REG_RAM_100TH_SEC] ^ m_regs[REG_CNT_100TH_SEC]) & 0x7f)) + m_irq_status |= IRQ_BIT_ALARM; + + recalc_irqs(); } @@ -124,9 +216,29 @@ void icm7170_device::rtc_clock_updated(int year, int month, int day, int day_of_ m_regs[REG_CNT_MONTH] = month; m_regs[REG_CNT_DAY] = day; m_regs[REG_CNT_DAY_OF_WEEK] = day_of_week; - m_regs[REG_CNT_HOURS] = hour; + if (!(m_regs[REG_COMMAND] & CMD_REG_24_HOUR)) + { + // transform hours from 0..23 to 1..12 + m_regs[REG_CNT_HOURS] = (hour > 12) ? hour - 12 : hour ? hour : 1; + + // set am/pm bit + if (hour > 11) + m_regs[REG_CNT_HOURS] |= 0x80; + } + else + m_regs[REG_CNT_HOURS] = hour; m_regs[REG_CNT_MINUTES] = minute; m_regs[REG_CNT_SECONDS] = second; + + if (m_regs[REG_COMMAND] & CMD_REG_24_HOUR) + LOG("rtc_clock_updated %02d-%02d-%02d %02d:%02d:%02d\n", + m_regs[REG_CNT_YEAR], m_regs[REG_CNT_MONTH], m_regs[REG_CNT_DAY], + m_regs[REG_CNT_HOURS], m_regs[REG_CNT_MINUTES], m_regs[REG_CNT_SECONDS]); + else + LOG("rtc_clock_updated %02d-%02d-%02d %02d:%02d:%02d %s\n", + m_regs[REG_CNT_YEAR], m_regs[REG_CNT_MONTH], m_regs[REG_CNT_DAY], + m_regs[REG_CNT_HOURS] & 0xf, m_regs[REG_CNT_MINUTES], m_regs[REG_CNT_SECONDS], + (m_regs[REG_CNT_HOURS] & 0x80) ? "pm" : "am"); } } @@ -166,11 +278,13 @@ void icm7170_device::nvram_write(emu_file &file) // non-inherited device functions uint8_t icm7170_device::read(offs_t offset) { - uint8_t data = m_regs[offset & 0x1f]; + uint8_t data = m_regs[offset & 0x1f]; if ((offset & 0x1f) == REG_INT_STATUS_AND_MASK) { data = m_irq_status; + m_irq_status = 0; + recalc_irqs(); } LOG("ICM7170 Register %d Read %02x\n", offset, data); @@ -180,6 +294,7 @@ uint8_t icm7170_device::read(offs_t offset) void icm7170_device::write(offs_t offset, uint8_t data) { + // TODO: unused register bits should be masked switch (offset & 0x1f) { case REG_INT_STATUS_AND_MASK: @@ -188,6 +303,10 @@ void icm7170_device::write(offs_t offset, uint8_t data) recalc_irqs(); break; + case REG_COMMAND: + m_timer->enable(data & CMD_REG_RUN); + // fall through + default: m_regs[offset & 0x1f] = data; LOG("ICM7170 Register %d Write %02x\n", offset & 0x1f, data); @@ -197,5 +316,16 @@ void icm7170_device::write(offs_t offset, uint8_t data) void icm7170_device::recalc_irqs() { + if (m_irq_status & m_irq_mask & ~IRQ_BIT_GLOBAL) + m_irq_status |= IRQ_BIT_GLOBAL; + else + m_irq_status &= ~IRQ_BIT_GLOBAL; + + bool const irq_state = (m_regs[REG_COMMAND] & CMD_REG_IRQ_ENABLE) && (m_irq_status & IRQ_BIT_GLOBAL); + if (m_out_irq_state != irq_state) + { + m_out_irq_state = irq_state; + m_out_irq_cb(m_out_irq_state); + } } diff --git a/src/devices/machine/icm7170.h b/src/devices/machine/icm7170.h index 0d5a7fb262c..e38a556b06c 100644 --- a/src/devices/machine/icm7170.h +++ b/src/devices/machine/icm7170.h @@ -75,6 +75,7 @@ private: void recalc_irqs(); devcb_write_line m_out_irq_cb; + bool m_out_irq_state; uint8_t m_regs[0x20]; uint8_t m_irq_mask, m_irq_status; |