Move internal timer code from clock.c to a new file timer.c.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
diff --git a/Makefile b/Makefile
index 759bbbb..00ef346 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@
 
 # Source files
 SRCBOTH=misc.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \
-    kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
+    kbd.c pci.c serial.c timer.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
     pnpbios.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \
     usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \
     virtio-ring.c virtio-pci.c virtio-blk.c virtio-scsi.c apm.c ahci.c \
diff --git a/src/clock.c b/src/clock.c
index 2eedab8..b9a708b 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -10,6 +10,7 @@
 #include "disk.h" // floppy_tick
 #include "cmos.h" // inb_cmos
 #include "pic.h" // pic_eoi1
+#include "pit.h" // PM_SEL_TIMER0
 #include "bregs.h" // struct bregs
 #include "biosvar.h" // GET_GLOBAL
 #include "usb-hid.h" // usb_check_event
@@ -26,213 +27,6 @@
 #define RTC_B_DSE  0x01
 
 
-// Bits for PORT_PS2_CTRLB
-#define PPCB_T2GATE (1<<0)
-#define PPCB_SPKR   (1<<1)
-#define PPCB_T2OUT  (1<<5)
-
-// Bits for PORT_PIT_MODE
-#define PM_SEL_TIMER0   (0<<6)
-#define PM_SEL_TIMER1   (1<<6)
-#define PM_SEL_TIMER2   (2<<6)
-#define PM_SEL_READBACK (3<<6)
-#define PM_ACCESS_LATCH  (0<<4)
-#define PM_ACCESS_LOBYTE (1<<4)
-#define PM_ACCESS_HIBYTE (2<<4)
-#define PM_ACCESS_WORD   (3<<4)
-#define PM_MODE0 (0<<1)
-#define PM_MODE1 (1<<1)
-#define PM_MODE2 (2<<1)
-#define PM_MODE3 (3<<1)
-#define PM_MODE4 (4<<1)
-#define PM_MODE5 (5<<1)
-#define PM_CNT_BINARY (0<<0)
-#define PM_CNT_BCD    (1<<0)
-#define PM_READ_COUNTER0 (1<<1)
-#define PM_READ_COUNTER1 (1<<2)
-#define PM_READ_COUNTER2 (1<<3)
-#define PM_READ_STATUSVALUE (0<<4)
-#define PM_READ_VALUE       (1<<4)
-#define PM_READ_STATUS      (2<<4)
-
-
-/****************************************************************
- * TSC timer
- ****************************************************************/
-
-#define CALIBRATE_COUNT 0x800   // Approx 1.7ms
-
-u32 cpu_khz VARFSEG;
-u8 no_tsc VARFSEG;
-
-u16 pmtimer_ioport VARFSEG;
-u32 pmtimer_wraps VARLOW;
-u32 pmtimer_last VARLOW;
-
-static void
-calibrate_tsc(void)
-{
-    u32 eax, ebx, ecx, edx, cpuid_features = 0;
-
-    if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport)) {
-        dprintf(3, "pmtimer already configured; will not calibrate TSC\n");
-        return;
-    }
-
-    cpuid(0, &eax, &ebx, &ecx, &edx);
-    if (eax > 0)
-        cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
-
-    if (!(cpuid_features & CPUID_TSC)) {
-        SET_GLOBAL(no_tsc, 1);
-        SET_GLOBAL(cpu_khz, PIT_TICK_RATE / 1000);
-        dprintf(3, "386/486 class CPU. Using TSC emulation\n");
-        return;
-    }
-
-    // Setup "timer2"
-    u8 orig = inb(PORT_PS2_CTRLB);
-    outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB);
-    /* binary, mode 0, LSB/MSB, Ch 2 */
-    outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE);
-    /* LSB of ticks */
-    outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2);
-    /* MSB of ticks */
-    outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2);
-
-    u64 start = rdtscll();
-    while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0)
-        ;
-    u64 end = rdtscll();
-
-    // Restore PORT_PS2_CTRLB
-    outb(orig, PORT_PS2_CTRLB);
-
-    // Store calibrated cpu khz.
-    u64 diff = end - start;
-    dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n"
-            , (u32)start, (u32)end, (u32)diff);
-    u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT;
-    SET_GLOBAL(cpu_khz, hz / 1000);
-
-    dprintf(1, "CPU Mhz=%u\n", hz / 1000000);
-}
-
-/* TSC emulation timekeepers */
-u64 TSC_8254 VARLOW;
-int Last_TSC_8254 VARLOW;
-
-static u64
-emulate_tsc(void)
-{
-    /* read timer 0 current count */
-    u64 ret = GET_LOW(TSC_8254);
-    /* readback mode has slightly shifted registers, works on all
-     * 8254, readback PIT0 latch */
-    outb(PM_SEL_READBACK | PM_READ_VALUE | PM_READ_COUNTER0, PORT_PIT_MODE);
-    int cnt = (inb(PORT_PIT_COUNTER0) | (inb(PORT_PIT_COUNTER0) << 8));
-    int d = GET_LOW(Last_TSC_8254) - cnt;
-    /* Determine the ticks count from last invocation of this function */
-    ret += (d > 0) ? d : (PIT_TICK_INTERVAL + d);
-    SET_LOW(Last_TSC_8254, cnt);
-    SET_LOW(TSC_8254, ret);
-    return ret;
-}
-
-void pmtimer_setup(u16 ioport, u32 khz)
-{
-    if (!CONFIG_PMTIMER)
-        return;
-    dprintf(1, "Using pmtimer, ioport 0x%x, freq %d kHz\n", ioport, khz);
-    SET_GLOBAL(pmtimer_ioport, ioport);
-    SET_GLOBAL(cpu_khz, khz);
-}
-
-static u64 pmtimer_get(void)
-{
-    u16 ioport = GET_GLOBAL(pmtimer_ioport);
-    u32 wraps = GET_LOW(pmtimer_wraps);
-    u32 pmtimer = inl(ioport) & 0xffffff;
-
-    if (pmtimer < GET_LOW(pmtimer_last)) {
-        wraps++;
-        SET_LOW(pmtimer_wraps, wraps);
-    }
-    SET_LOW(pmtimer_last, pmtimer);
-
-    dprintf(9, "pmtimer: %u:%u\n", wraps, pmtimer);
-    return (u64)wraps << 24 | pmtimer;
-}
-
-static u64
-get_tsc(void)
-{
-    if (unlikely(GET_GLOBAL(no_tsc)))
-        return emulate_tsc();
-    if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport))
-        return pmtimer_get();
-    return rdtscll();
-}
-
-int
-check_tsc(u64 end)
-{
-    return (s64)(get_tsc() - end) > 0;
-}
-
-static void
-tscdelay(u64 diff)
-{
-    u64 start = get_tsc();
-    u64 end = start + diff;
-    while (!check_tsc(end))
-        cpu_relax();
-}
-
-static void
-tscsleep(u64 diff)
-{
-    u64 start = get_tsc();
-    u64 end = start + diff;
-    while (!check_tsc(end))
-        yield();
-}
-
-void ndelay(u32 count) {
-    tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000);
-}
-void udelay(u32 count) {
-    tscdelay(count * GET_GLOBAL(cpu_khz) / 1000);
-}
-void mdelay(u32 count) {
-    tscdelay(count * GET_GLOBAL(cpu_khz));
-}
-
-void nsleep(u32 count) {
-    tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000);
-}
-void usleep(u32 count) {
-    tscsleep(count * GET_GLOBAL(cpu_khz) / 1000);
-}
-void msleep(u32 count) {
-    tscsleep(count * GET_GLOBAL(cpu_khz));
-}
-
-// Return the TSC value that is 'msecs' time in the future.
-u64
-calc_future_tsc(u32 msecs)
-{
-    u32 khz = GET_GLOBAL(cpu_khz);
-    return get_tsc() + ((u64)khz * msecs);
-}
-u64
-calc_future_tsc_usec(u32 usecs)
-{
-    u32 khz = GET_GLOBAL(cpu_khz);
-    return get_tsc() + ((u64)(khz/1000) * usecs);
-}
-
-
 /****************************************************************
  * Init
  ****************************************************************/
@@ -290,10 +84,9 @@
 u8 Century VARLOW;
 
 void
-timer_setup(void)
+clock_setup(void)
 {
     dprintf(3, "init timer\n");
-    calibrate_tsc();
     pit_setup();
 
     rtc_setup();
@@ -326,35 +119,6 @@
  * Standard clock functions
  ****************************************************************/
 
-#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
-
-// Calculate the timer value at 'count' number of full timer ticks in
-// the future.
-u32
-calc_future_timer_ticks(u32 count)
-{
-    return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY;
-}
-
-// Return the timer value that is 'msecs' time in the future.
-u32
-calc_future_timer(u32 msecs)
-{
-    if (!msecs)
-        return GET_BDA(timer_counter);
-    u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL);
-    u32 ticks = DIV_ROUND_UP(kticks, 1000);
-    return calc_future_timer_ticks(ticks);
-}
-
-// Check if the given timer value has passed.
-int
-check_timer(u32 end)
-{
-    return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY)
-            < (TICKS_PER_DAY/2));
-}
-
 // get current clock count
 static void
 handle_1a00(struct bregs *regs)
diff --git a/src/csm.c b/src/csm.c
index 2886bba..e855d2c 100644
--- a/src/csm.c
+++ b/src/csm.c
@@ -170,6 +170,7 @@
     bda->hdcount = 0;
 
     timer_setup();
+    clock_setup();
     device_hardware_setup();
     wait_threads();
     interactive_bootmenu();
diff --git a/src/pit.h b/src/pit.h
new file mode 100644
index 0000000..6d58895
--- /dev/null
+++ b/src/pit.h
@@ -0,0 +1,33 @@
+// Definitions for the Intel 8253 Programmable Interrupt Timer (PIT).
+#ifndef __PIT_H
+#define __PIT_H
+
+#define PIT_TICK_RATE 1193180   // Underlying HZ of PIT
+#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
+#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
+
+// Bits for PORT_PIT_MODE
+#define PM_SEL_TIMER0   (0<<6)
+#define PM_SEL_TIMER1   (1<<6)
+#define PM_SEL_TIMER2   (2<<6)
+#define PM_SEL_READBACK (3<<6)
+#define PM_ACCESS_LATCH  (0<<4)
+#define PM_ACCESS_LOBYTE (1<<4)
+#define PM_ACCESS_HIBYTE (2<<4)
+#define PM_ACCESS_WORD   (3<<4)
+#define PM_MODE0 (0<<1)
+#define PM_MODE1 (1<<1)
+#define PM_MODE2 (2<<1)
+#define PM_MODE3 (3<<1)
+#define PM_MODE4 (4<<1)
+#define PM_MODE5 (5<<1)
+#define PM_CNT_BINARY (0<<0)
+#define PM_CNT_BCD    (1<<0)
+#define PM_READ_COUNTER0 (1<<1)
+#define PM_READ_COUNTER1 (1<<2)
+#define PM_READ_COUNTER2 (1<<3)
+#define PM_READ_STATUSVALUE (0<<4)
+#define PM_READ_VALUE       (1<<4)
+#define PM_READ_STATUS      (2<<4)
+
+#endif // pit.h
diff --git a/src/post.c b/src/post.c
index ff201fa..d706d4f 100644
--- a/src/post.c
+++ b/src/post.c
@@ -158,6 +158,7 @@
     pic_setup();
     mathcp_setup();
     timer_setup();
+    clock_setup();
 
     // Platform specific setup
     qemu_platform_setup();
diff --git a/src/timer.c b/src/timer.c
new file mode 100644
index 0000000..a491ef6
--- /dev/null
+++ b/src/timer.c
@@ -0,0 +1,225 @@
+// Internal timer support.
+//
+// Copyright (C) 2008-2013  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pit.h" // PM_SEL_TIMER0
+#include "ioport.h" // PORT_PIT_MODE
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_LOW
+
+// Bits for PORT_PS2_CTRLB
+#define PPCB_T2GATE (1<<0)
+#define PPCB_SPKR   (1<<1)
+#define PPCB_T2OUT  (1<<5)
+
+
+/****************************************************************
+ * TSC timer
+ ****************************************************************/
+
+#define CALIBRATE_COUNT 0x800   // Approx 1.7ms
+
+u32 cpu_khz VARFSEG;
+u8 no_tsc VARFSEG;
+
+u16 pmtimer_ioport VARFSEG;
+u32 pmtimer_wraps VARLOW;
+u32 pmtimer_last VARLOW;
+
+void
+timer_setup(void)
+{
+    u32 eax, ebx, ecx, edx, cpuid_features = 0;
+
+    if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport)) {
+        dprintf(3, "pmtimer already configured; will not calibrate TSC\n");
+        return;
+    }
+
+    cpuid(0, &eax, &ebx, &ecx, &edx);
+    if (eax > 0)
+        cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+
+    if (!(cpuid_features & CPUID_TSC)) {
+        SET_GLOBAL(no_tsc, 1);
+        SET_GLOBAL(cpu_khz, PIT_TICK_RATE / 1000);
+        dprintf(3, "386/486 class CPU. Using TSC emulation\n");
+        return;
+    }
+
+    // Setup "timer2"
+    u8 orig = inb(PORT_PS2_CTRLB);
+    outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB);
+    /* binary, mode 0, LSB/MSB, Ch 2 */
+    outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE);
+    /* LSB of ticks */
+    outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2);
+    /* MSB of ticks */
+    outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2);
+
+    u64 start = rdtscll();
+    while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0)
+        ;
+    u64 end = rdtscll();
+
+    // Restore PORT_PS2_CTRLB
+    outb(orig, PORT_PS2_CTRLB);
+
+    // Store calibrated cpu khz.
+    u64 diff = end - start;
+    dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n"
+            , (u32)start, (u32)end, (u32)diff);
+    u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT;
+    SET_GLOBAL(cpu_khz, hz / 1000);
+
+    dprintf(1, "CPU Mhz=%u\n", hz / 1000000);
+}
+
+/* TSC emulation timekeepers */
+u64 TSC_8254 VARLOW;
+int Last_TSC_8254 VARLOW;
+
+static u64
+emulate_tsc(void)
+{
+    /* read timer 0 current count */
+    u64 ret = GET_LOW(TSC_8254);
+    /* readback mode has slightly shifted registers, works on all
+     * 8254, readback PIT0 latch */
+    outb(PM_SEL_READBACK | PM_READ_VALUE | PM_READ_COUNTER0, PORT_PIT_MODE);
+    int cnt = (inb(PORT_PIT_COUNTER0) | (inb(PORT_PIT_COUNTER0) << 8));
+    int d = GET_LOW(Last_TSC_8254) - cnt;
+    /* Determine the ticks count from last invocation of this function */
+    ret += (d > 0) ? d : (PIT_TICK_INTERVAL + d);
+    SET_LOW(Last_TSC_8254, cnt);
+    SET_LOW(TSC_8254, ret);
+    return ret;
+}
+
+void pmtimer_setup(u16 ioport, u32 khz)
+{
+    if (!CONFIG_PMTIMER)
+        return;
+    dprintf(1, "Using pmtimer, ioport 0x%x, freq %d kHz\n", ioport, khz);
+    SET_GLOBAL(pmtimer_ioport, ioport);
+    SET_GLOBAL(cpu_khz, khz);
+}
+
+static u64 pmtimer_get(void)
+{
+    u16 ioport = GET_GLOBAL(pmtimer_ioport);
+    u32 wraps = GET_LOW(pmtimer_wraps);
+    u32 pmtimer = inl(ioport) & 0xffffff;
+
+    if (pmtimer < GET_LOW(pmtimer_last)) {
+        wraps++;
+        SET_LOW(pmtimer_wraps, wraps);
+    }
+    SET_LOW(pmtimer_last, pmtimer);
+
+    dprintf(9, "pmtimer: %u:%u\n", wraps, pmtimer);
+    return (u64)wraps << 24 | pmtimer;
+}
+
+static u64
+get_tsc(void)
+{
+    if (unlikely(GET_GLOBAL(no_tsc)))
+        return emulate_tsc();
+    if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport))
+        return pmtimer_get();
+    return rdtscll();
+}
+
+int
+check_tsc(u64 end)
+{
+    return (s64)(get_tsc() - end) > 0;
+}
+
+static void
+tscdelay(u64 diff)
+{
+    u64 start = get_tsc();
+    u64 end = start + diff;
+    while (!check_tsc(end))
+        cpu_relax();
+}
+
+static void
+tscsleep(u64 diff)
+{
+    u64 start = get_tsc();
+    u64 end = start + diff;
+    while (!check_tsc(end))
+        yield();
+}
+
+void ndelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000);
+}
+void udelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz) / 1000);
+}
+void mdelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz));
+}
+
+void nsleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000);
+}
+void usleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz) / 1000);
+}
+void msleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz));
+}
+
+// Return the TSC value that is 'msecs' time in the future.
+u64
+calc_future_tsc(u32 msecs)
+{
+    u32 khz = GET_GLOBAL(cpu_khz);
+    return get_tsc() + ((u64)khz * msecs);
+}
+u64
+calc_future_tsc_usec(u32 usecs)
+{
+    u32 khz = GET_GLOBAL(cpu_khz);
+    return get_tsc() + ((u64)(khz/1000) * usecs);
+}
+
+
+/****************************************************************
+ * IRQ based timer
+ ****************************************************************/
+
+// Calculate the timer value at 'count' number of full timer ticks in
+// the future.
+u32
+calc_future_timer_ticks(u32 count)
+{
+    return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY;
+}
+
+// Return the timer value that is 'msecs' time in the future.
+u32
+calc_future_timer(u32 msecs)
+{
+    if (!msecs)
+        return GET_BDA(timer_counter);
+    u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL);
+    u32 ticks = DIV_ROUND_UP(kticks, 1000);
+    return calc_future_timer_ticks(ticks);
+}
+
+// Check if the given timer value has passed.
+int
+check_timer(u32 end)
+{
+    return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY)
+            < (TICKS_PER_DAY/2));
+}
diff --git a/src/usb-ehci.c b/src/usb-ehci.c
index 144dec4..e1e659b 100644
--- a/src/usb-ehci.c
+++ b/src/usb-ehci.c
@@ -15,6 +15,7 @@
 #include "biosvar.h" // GET_LOWFLAT
 #include "usb-uhci.h" // uhci_setup
 #include "usb-ohci.h" // ohci_setup
+#include "pit.h" // PIT_TICK_RATE
 
 struct usb_ehci_s {
     struct usb_s usb;
diff --git a/src/usb-ohci.c b/src/usb-ohci.c
index ef6a52c..f3a3b3b 100644
--- a/src/usb-ohci.c
+++ b/src/usb-ohci.c
@@ -11,6 +11,7 @@
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "usb.h" // struct usb_s
 #include "biosvar.h" // GET_LOWFLAT
+#include "pit.h" // PIT_TICK_RATE
 
 #define FIT                     (1 << 31)
 
diff --git a/src/usb-uhci.c b/src/usb-uhci.c
index 4098bf2..e77f5c1 100644
--- a/src/usb-uhci.c
+++ b/src/usb-uhci.c
@@ -12,6 +12,7 @@
 #include "pci_regs.h" // PCI_BASE_ADDRESS_4
 #include "usb.h" // struct usb_s
 #include "biosvar.h" // GET_LOWFLAT
+#include "pit.h" // PIT_TICK_RATE
 
 struct usb_uhci_s {
     struct usb_s usb;
diff --git a/src/util.h b/src/util.h
index 8bde0b2..19733cd 100644
--- a/src/util.h
+++ b/src/util.h
@@ -275,8 +275,13 @@
 void lpt_setup(void);
 
 // clock.c
-#define PIT_TICK_RATE 1193180   // Underlying HZ of PIT
-#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
+void clock_setup(void);
+void handle_1583(struct bregs *regs);
+void handle_1586(struct bregs *regs);
+void useRTC(void);
+void releaseRTC(void);
+
+// timer.c
 void pmtimer_setup(u16 ioport, u32 khz);
 int check_tsc(u64 end);
 void timer_setup(void);
@@ -291,10 +296,6 @@
 u32 calc_future_timer_ticks(u32 count);
 u32 calc_future_timer(u32 msecs);
 int check_timer(u32 end);
-void handle_1583(struct bregs *regs);
-void handle_1586(struct bregs *regs);
-void useRTC(void);
-void releaseRTC(void);
 
 // apm.c
 void apm_shutdown(void);