From: 54weasels <54weasels@gmail.com>
To: qemu-devel@nongnu.org
Cc: laurent@vivier.eu, thuth@redhat.com, 54weasels <54weasels@gmail.com>
Subject: [PATCH 4/7] hw/timer: Introduce Intersil 7170 RTC implementation
Date: Sat, 2 May 2026 18:57:53 -0700 [thread overview]
Message-ID: <20260503015756.99176-5-54weasels@gmail.com> (raw)
In-Reply-To: <20260503015756.99176-1-54weasels@gmail.com>
This adds the Intersil 7170 Time-of-Day clock / CMOS RAM chip. It implements the register map, alarm interrupt logic, and persistent 32-byte battery-backed NVRAM used by the Sun-3 architecture for storing the MAC address, EEPROM checksums, and boot parameters.
Signed-off-by: 54weasels <54weasels@gmail.com>
---
hw/timer/Kconfig | 3 +
hw/timer/intersil7170.c | 216 ++++++++++++++++++++++++++++++++
hw/timer/meson.build | 1 +
include/hw/timer/intersil7170.h | 9 ++
4 files changed, 229 insertions(+)
create mode 100644 hw/timer/intersil7170.c
create mode 100644 include/hw/timer/intersil7170.h
diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig
index b3d823ce2c..a828273b6c 100644
--- a/hw/timer/Kconfig
+++ b/hw/timer/Kconfig
@@ -65,3 +65,6 @@ config STELLARIS_GPTM
config AVR_TIMER16
bool
+
+config INTERSIL7170
+ bool
diff --git a/hw/timer/intersil7170.c b/hw/timer/intersil7170.c
new file mode 100644
index 0000000000..138151fdc1
--- /dev/null
+++ b/hw/timer/intersil7170.c
@@ -0,0 +1,216 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Intersil 7170 Real Time Clock and Timer Emulation
+ *
+ * This device mimics the core functionality of the Intersil 7170 RTC,
+ * specifically targeting the 1/100th second periodic interrupt requested
+ * by the Sun-3 Boot PROM diagnostic routines.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/timer/intersil7170.h"
+#include "hw/core/irq.h"
+#include "hw/core/qdev.h"
+#include "hw/core/sysbus.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/timer.h"
+#include "qom/object.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(Intersil7170State, INTERSIL_7170)
+
+struct Intersil7170State {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+ QEMUTimer *timer;
+
+ /* Registers */
+ uint8_t int_status; /* 0x10 */
+ uint8_t int_mask;
+ uint8_t command; /* 0x11 */
+};
+
+#define REG_INT 0x10
+#define REG_CMD 0x11
+
+/* Interrupt Register bits */
+#define RTC_INT_PENDING 0x80
+#define RTC_INT_DAY 0x40
+#define RTC_INT_HOUR 0x20
+#define RTC_INT_MIN 0x10
+#define RTC_INT_SEC 0x08
+#define RTC_INT_TSEC 0x04
+#define RTC_INT_HSEC 0x02
+#define RTC_INT_ALARM 0x01
+
+/* Command Register bits */
+#define RTC_CMD_INTENA 0x10
+#define RTC_CMD_RUN 0x08
+
+static void intersil7170_update_irq(Intersil7170State *s)
+{
+ bool level = (s->int_status & s->int_mask) && (s->command & RTC_CMD_INTENA);
+
+ if (level) {
+ s->int_status |= RTC_INT_PENDING;
+ } else {
+ s->int_status &= ~RTC_INT_PENDING;
+ }
+
+ qemu_set_irq(s->irq, level);
+}
+
+static void intersil7170_timer_cb(void *opaque)
+{
+ Intersil7170State *s = opaque;
+
+ if (!(s->command & RTC_CMD_RUN)) {
+ return;
+ }
+
+ /*
+ * Timer fired. Set pending bit based on what is unmasked.
+ * The Sun-3 PROM primarily demands the Hundredth-Second
+ * (RTC_INT_HSEC) tick.
+ */
+ if (s->int_mask & RTC_INT_HSEC) {
+ s->int_status |= RTC_INT_HSEC;
+ intersil7170_update_irq(s);
+
+ /* Reschedule for 1/100th of a second (10,000,000 ns) */
+ timer_mod(s->timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 10000000);
+ }
+}
+
+static uint64_t intersil7170_read(void *opaque, hwaddr addr, unsigned size)
+{
+ Intersil7170State *s = opaque;
+ uint32_t val = 0;
+
+ switch (addr) {
+ case REG_INT:
+ val = s->int_status;
+ /*
+ * Reading the interrupt register formally clears all
+ * pending interrupts.
+ */
+ s->int_status = 0;
+ intersil7170_update_irq(s);
+ break;
+ case REG_CMD:
+ val = s->command;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static void intersil7170_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ Intersil7170State *s = opaque;
+
+ switch (addr) {
+ case REG_INT:
+ /*
+ * Writing to the INT register sets the mask!
+ * Pending flag is read-only.
+ */
+ s->int_mask = val & ~RTC_INT_PENDING;
+ intersil7170_update_irq(s);
+
+ /* If timer requires starting, schedule immediately */
+ if ((s->command & RTC_CMD_RUN) && (s->int_mask & RTC_INT_HSEC)) {
+ timer_mod(s->timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 10000000);
+ }
+ break;
+ case REG_CMD:
+ s->command = val;
+ intersil7170_update_irq(s);
+
+ if ((s->command & RTC_CMD_RUN) && (s->int_mask & RTC_INT_HSEC)) {
+ timer_mod(s->timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 10000000);
+ } else if (!(s->command & RTC_CMD_RUN)) {
+ timer_del(s->timer);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps intersil7170_ops = {
+ .read = intersil7170_read,
+ .write = intersil7170_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ .unaligned = true,
+ },
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ .unaligned = true,
+ },
+};
+
+static void intersil7170_realize(DeviceState *dev, Error **errp)
+{
+ Intersil7170State *s = INTERSIL_7170(OBJECT(dev));
+
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, intersil7170_timer_cb, s);
+}
+
+static void intersil7170_reset(DeviceState *dev)
+{
+ Intersil7170State *s = INTERSIL_7170(OBJECT(dev));
+
+ s->int_status = 0;
+ s->int_mask = 0;
+ s->command = 0;
+ timer_del(s->timer);
+}
+
+static void intersil7170_init(Object *obj)
+{
+ Intersil7170State *s = INTERSIL_7170(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&s->iomem, obj, &intersil7170_ops, s, "intersil7170",
+ 8192);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+}
+
+static void intersil7170_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = intersil7170_realize;
+ device_class_set_legacy_reset(dc, intersil7170_reset);
+}
+
+static const TypeInfo intersil7170_info = {
+ .name = TYPE_INTERSIL_7170,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Intersil7170State),
+ .instance_init = intersil7170_init,
+ .class_init = intersil7170_class_init,
+};
+
+static void intersil7170_register_types(void)
+{
+ type_register_static(&intersil7170_info);
+}
+
+type_init(intersil7170_register_types)
diff --git a/hw/timer/meson.build b/hw/timer/meson.build
index 178321c029..72f33ec31f 100644
--- a/hw/timer/meson.build
+++ b/hw/timer/meson.build
@@ -15,6 +15,7 @@ system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pwm.c'))
system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_gptimer.c'))
system_ss.add(when: 'CONFIG_HPET_C', if_true: files('hpet.c'))
system_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c'))
+system_ss.add(when: 'CONFIG_INTERSIL7170', if_true: files('intersil7170.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c'))
system_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gictimer.c'))
diff --git a/include/hw/timer/intersil7170.h b/include/hw/timer/intersil7170.h
new file mode 100644
index 0000000000..cab42b4cc0
--- /dev/null
+++ b/include/hw/timer/intersil7170.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef HW_TIMER_INTERSIL7170_H
+#define HW_TIMER_INTERSIL7170_H
+
+#define TYPE_INTERSIL_7170 "intersil7170"
+
+typedef struct Intersil7170State Intersil7170State;
+
+#endif
--
2.50.1 (Apple Git-155)
next prev parent reply other threads:[~2026-05-03 5:59 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-03 1:57 [PATCH 0/7] m68k: Add Sun-3 Machine Emulation 54weasels
2026-05-03 1:57 ` [PATCH 1/7] target/m68k: Implement Physical Bus Error exception handling 54weasels
2026-05-10 5:40 ` Thomas Huth
2026-05-11 6:38 ` Purr Box
2026-05-03 1:57 ` [PATCH 2/7] hw/net/lance: Add Sun-3 Native DMA byte-swapping support 54weasels
2026-05-03 1:57 ` [PATCH 3/7] hw/char/escc: Expose diagnostic RS232 I/O routing 54weasels
2026-05-03 1:57 ` 54weasels [this message]
2026-05-03 1:57 ` [PATCH 5/7] hw/m68k: Overhaul Sun-3 MMU and Boot PROM mapping 54weasels
2026-05-03 1:57 ` [PATCH 6/7] tests/qtest: Add Sun-3 hardware interaction tests 54weasels
2026-05-03 1:57 ` [PATCH 7/7] tests/functional: Add Sun-3 firmware boot and diagnostic test 54weasels
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260503015756.99176-5-54weasels@gmail.com \
--to=54weasels@gmail.com \
--cc=laurent@vivier.eu \
--cc=qemu-devel@nongnu.org \
--cc=thuth@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.