From 7c8744d1e0961433aef3b7e9380c93b0999f32b8 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 18 Dec 2022 22:29:12 -0500 Subject: [PATCH] Read RTC date and time --- src/hulk/rtc.d | 112 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 12 deletions(-) diff --git a/src/hulk/rtc.d b/src/hulk/rtc.d index 6f8e4af..93f8957 100644 --- a/src/hulk/rtc.d +++ b/src/hulk/rtc.d @@ -13,32 +13,67 @@ struct rtc private enum ubyte DISABLE_NMI = 0x80u; - private enum ubyte SR_A = 0xAu; - private enum ubyte SR_B = 0xBu; - private enum ubyte SR_C = 0xCu; + private enum ubyte REG_RTC_SECONDS = 0x0u; + private enum ubyte REG_RTC_MINUTES = 0x2u; + private enum ubyte REG_RTC_HOURS = 0x4u; + private enum ubyte REG_RTC_DAY = 0x7u; + private enum ubyte REG_RTC_MONTH = 0x8u; + private enum ubyte REG_RTC_YEAR = 0x9u; + private enum ubyte REG_SR_A = 0xAu; + private enum ubyte REG_SR_B = 0xBu; + private enum ubyte REG_SR_C = 0xCu; + private enum ubyte SR_A_RTC_UPDATE_IN_PROGRESS = 0x80u; + private enum ubyte SR_B_24HOUR = 0x02u; + private enum ubyte SR_B_BINARY = 0x04u; private enum ubyte SR_B_ENABLE_IRQ = 0x40u; + private static __gshared bool rtc_24hour_mode; + private static __gshared bool rtc_binary_mode; + + static struct time + { + public ubyte year; + public ubyte month; + public ubyte day; + public ubyte hour; + public ubyte minute; + public ubyte second; + } + public static void initialize() { - /* Enable IRQ 8 to receive RTC interrupts. */ - out8(PORT_SELECT, DISABLE_NMI | SR_B); - ubyte sr_b = in8(PORT_DATA); - out8(PORT_SELECT, DISABLE_NMI | SR_B); - out8(PORT_DATA, sr_b | SR_B_ENABLE_IRQ); + time t = read_rtc_time(); + klog.writefln("System time is 20%02u-%02u-%02u %02u:%02u:%02u", + t.year, t.month, t.day, t.hour, t.minute, t.second); - out8(PORT_SELECT, DISABLE_NMI | SR_A); - klog.writefln("SR_A = 0x%x", in8(PORT_DATA)); + /* Enable IRQ 8 to receive RTC interrupts. */ + ubyte sr_b = read_register(REG_SR_B, true); + write_register(REG_SR_B, sr_b | SR_B_ENABLE_IRQ, true); + + rtc_24hour_mode = (sr_b & SR_B_24HOUR) != 0u; + rtc_binary_mode = (sr_b & SR_B_BINARY) != 0u; /* Send EOI to enable more RTC interrupts and re-enable NMIs. */ eoi(); } + private static ubyte read_register(ubyte register, bool disable_nmi = false) + { + out8(PORT_SELECT, register | (disable_nmi ? DISABLE_NMI : 0u)); + return in8(PORT_DATA); + } + + private static void write_register(ubyte register, ubyte value, bool disable_nmi = false) + { + out8(PORT_SELECT, register | (disable_nmi ? DISABLE_NMI : 0u)); + out8(PORT_DATA, value); + } + private static void eoi() { /* Read from status register C to clear the interrupt. */ - out8(PORT_SELECT, SR_C); - in8(PORT_DATA); + read_register(REG_SR_C); } public static void isr() @@ -53,4 +88,57 @@ struct rtc } eoi(); } + + private static time read_rtc_time() + { + time[2] times; + size_t reads; + do + { + times[reads & 1] = read_rtc_time_unsafe(); + reads++; + } while ((reads < 2u) || (times[0] != times[1])); + return times[0]; + } + + private static time read_rtc_time_unsafe() + { + time t; + while ((read_register(REG_SR_A) & SR_A_RTC_UPDATE_IN_PROGRESS) != 0u) + { + } + t.year = read_rtc_time_register(REG_RTC_YEAR); + t.month = read_rtc_time_register(REG_RTC_MONTH); + t.day = read_rtc_time_register(REG_RTC_DAY); + t.hour = read_register(REG_RTC_HOURS); + t.minute = read_rtc_time_register(REG_RTC_MINUTES); + t.second = read_rtc_time_register(REG_RTC_SECONDS); + if (!rtc_24hour_mode) + { + ubyte pm = (t.hour & 0x80u) >> 7u; + t.hour &= 0x7Fu; + if (!rtc_binary_mode) + { + t.hour = bcd_to_binary(t.hour); + } + /* Hour is in 12-hour format; convert to 24-hour format. */ + t.hour = cast(ubyte)((t.hour % 12u) + pm * 12u); + } + return t; + } + + private static ubyte read_rtc_time_register(ubyte register) + { + ubyte value = read_register(register); + if (!rtc_binary_mode) + { + value = bcd_to_binary(value); + } + return value; + } + + private static ubyte bcd_to_binary(ubyte bcd) + { + return (bcd & 0xFu) + ((bcd & 0xF0u) >> 4u) * 10u; + } }