diff --git a/src/hulk/pit.d b/src/hulk/pit.d new file mode 100644 index 0000000..6bd4e48 --- /dev/null +++ b/src/hulk/pit.d @@ -0,0 +1,42 @@ +/** + * PIT (Programmable Interval Timer) functionality. + */ +module hulk.pit; + +import hulk.cpu; +import hulk.klog; + +struct pit +{ + /** PIT input frequency in 1/1000 Hz. */ + private enum ulong PIT_FREQUENCY_1000HZ = 1_193_181_667u; + private enum ulong TARGET_INTERRUPT_HZ = 100u; + private enum ulong TARGET_INTERRUPT_1000HZ = TARGET_INTERRUPT_HZ * 1000u; + private enum ulong PIT_DIVIDER = (PIT_FREQUENCY_1000HZ + TARGET_INTERRUPT_1000HZ / 2u) / TARGET_INTERRUPT_1000HZ; + + /** PIT channel 0 I/O port. */ + private enum ubyte PORT_CH_0 = 0x40u; + /** PIT channel 1 I/O port. */ + private enum ubyte PORT_CH_1 = 0x41u; + /** PIT channel 2 I/O port. */ + private enum ubyte PORT_CH_2 = 0x42u; + /** PIT mode/command register I/O port. */ + private enum ubyte PORT_MC = 0x43u; + + private enum ubyte MC_CH_0 = 0x00u; + private enum ubyte MC_LO_HI = 0x30u; + private enum ubyte MC_RATE_GENERATOR = 0x04u; + private enum ubyte MC_BINARY = 0x00u; + + public static void initialize() + { + out8(PORT_MC, MC_CH_0 | MC_LO_HI | MC_RATE_GENERATOR | MC_BINARY); + out8(PORT_CH_0, PIT_DIVIDER & 0xFFu); + out8(PORT_CH_0, PIT_DIVIDER >> 8u); + } + + public static void isr() + { + klog.writefln("PIT ISR"); + } +} diff --git a/src/hulk/rtc.d b/src/hulk/rtc.d new file mode 100644 index 0000000..6f8e4af --- /dev/null +++ b/src/hulk/rtc.d @@ -0,0 +1,56 @@ +/** + * RTC (Real-Time Clock) functionality. + */ +module hulk.rtc; + +import hulk.cpu; +import hulk.klog; + +struct rtc +{ + private enum ubyte PORT_SELECT = 0x70u; + private enum ubyte PORT_DATA = 0x71u; + + 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 SR_B_ENABLE_IRQ = 0x40u; + + 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); + + out8(PORT_SELECT, DISABLE_NMI | SR_A); + klog.writefln("SR_A = 0x%x", in8(PORT_DATA)); + + /* Send EOI to enable more RTC interrupts and re-enable NMIs. */ + eoi(); + } + + private static void eoi() + { + /* Read from status register C to clear the interrupt. */ + out8(PORT_SELECT, SR_C); + in8(PORT_DATA); + } + + public static void isr() + { + static __gshared ulong count; + static __gshared ulong seconds; + count++; + if ((count % 1024) == 0u) + { + seconds++; + klog.writefln("Seconds: %u", seconds); + } + eoi(); + } +}