summaryrefslogtreecommitdiffstats
path: root/sys/pc98/i386/microtime.s
diff options
context:
space:
mode:
Diffstat (limited to 'sys/pc98/i386/microtime.s')
-rw-r--r--sys/pc98/i386/microtime.s262
1 files changed, 262 insertions, 0 deletions
diff --git a/sys/pc98/i386/microtime.s b/sys/pc98/i386/microtime.s
new file mode 100644
index 0000000..cd08213
--- /dev/null
+++ b/sys/pc98/i386/microtime.s
@@ -0,0 +1,262 @@
+/* -*- Fundamental -*- keep Emacs from f***ing up the formatting */
+/*
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Steve McCanne's microtime code
+ * $Id: microtime.s,v 1.13 1996/05/31 01:08:02 peter Exp $
+ */
+
+#include <machine/asmacros.h>
+#include <machine/clock.h>
+
+#ifdef PC98
+#include <pc98/pc98/icu.h>
+#include <pc98/pc98/pc98.h>
+#include <pc98/pc98/timerreg.h>
+#else
+#include <i386/isa/icu.h>
+#include <i386/isa/isa.h>
+#include <i386/isa/timerreg.h>
+#endif
+
+ENTRY(microtime)
+
+#if defined(I586_CPU) || defined(I686_CPU)
+ movl _i586_ctr_rate, %ecx
+ testl %ecx, %ecx
+ jne pentium_microtime
+#else
+ xorl %ecx, %ecx /* clear ecx */
+#endif
+
+ movb $TIMER_SEL0|TIMER_LATCH, %al /* prepare to latch */
+
+ cli /* disable interrupts */
+
+ outb %al, $TIMER_MODE /* latch timer 0's counter */
+ inb $TIMER_CNTR0, %al /* read counter value, LSB first */
+ movb %al, %cl
+ inb $TIMER_CNTR0, %al
+ movb %al, %ch
+
+ /*
+ * Now check for counter overflow. This is tricky because the
+ * timer chip doesn't let us atomically read the current counter
+ * value and the output state (i.e., overflow state). We have
+ * to read the ICU interrupt request register (IRR) to see if the
+ * overflow has occured. Because we lack atomicity, we use
+ * the (very accurate) heuristic that we only check for
+ * overflow if the value read is close to the interrupt period.
+ * E.g., if we just checked the IRR, we might read a non-overflowing
+ * value close to 0, experience overflow, then read this overflow
+ * from the IRR, and mistakenly add a correction to the "close
+ * to zero" value.
+ *
+ * We compare the counter value to the prepared overflow threshold.
+ * If the counter value is less than this, we assume the counter
+ * didn't overflow between disabling timer interrupts and latching
+ * the counter value above. For example, we assume that interrupts
+ * are enabled when we are called (or were disabled just a few
+ * cycles before we are called and that the instructions before the
+ * "cli" are fast) and that the "cli" and "outb" instructions take
+ * less than 10 timer cycles to execute. The last assumption is
+ * very safe.
+ *
+ * Otherwise, the counter might have overflowed. We check for this
+ * condition by reading the interrupt request register out of the ICU.
+ * If it overflowed, we add in one clock period.
+ *
+ * The heuristic is "very accurate" because it works 100% if we're
+ * called with interrupts enabled. Otherwise, it might not work.
+ * Currently, only siointrts() calls us with interrupts disabled, so
+ * the problem can be avoided at some cost to the general case. The
+ * costs are complications in callers to disable interrupts in
+ * IO_ICU1 and extra reads of the IRR forced by a conservative
+ * overflow threshold.
+ *
+ * In 2.0, we are called at splhigh() from mi_switch(), so we have
+ * to allow for the overflow bit being in ipending instead of in
+ * the IRR. Our caller may have executed many instructions since
+ * ipending was set, so the heuristic for the IRR is inappropriate
+ * for ipending. However, we don't need another heuristic, since
+ * the "cli" suffices to lock ipending.
+ */
+
+ movl _timer0_max_count, %edx /* prepare for 2 uses */
+
+ testb $IRQ0, _ipending /* is a soft timer interrupt pending? */
+ jne overflow
+
+ /* Do we have a possible overflow condition? */
+ cmpl _timer0_overflow_threshold, %ecx
+ jbe 1f
+
+ inb $IO_ICU1, %al /* read IRR in ICU */
+ testb $IRQ0, %al /* is a hard timer interrupt pending? */
+ je 1f
+overflow:
+ subl %edx, %ecx /* some intr pending, count timer down through 0 */
+1:
+
+ /*
+ * Subtract counter value from max count since it is a count-down value.
+ */
+ subl %ecx, %edx
+
+ /* Adjust for partial ticks. */
+ addl _timer0_prescaler_count, %edx
+
+ /*
+ * To divide by 1.193200, we multiply by 27465 and shift right by 15.
+ *
+ * The multiplier was originally calculated to be
+ *
+ * 2^18 * 1000000 / 1193200 = 219698.
+ *
+ * The frequency is 1193200 to be compatible with rounding errors in
+ * the calculation of the usual maximum count. 2^18 is the largest
+ * power of 2 such that multiplying `i' by it doesn't overflow for i
+ * in the range of interest ([0, 11932 + 5)). We adjusted the
+ * multiplier a little to minimise the average of
+ *
+ * fabs(i / 1.1193200 - ((multiplier * i) >> 18))
+ *
+ * for i in the range and then removed powers of 2 to speed up the
+ * multiplication and to avoid overflow for i outside the range
+ * (i may be as high as 2^17 if the timer is programmed to its
+ * maximum maximum count). The absolute error is less than 1 for
+ * all i in the range.
+ */
+
+#ifdef PC98
+#ifndef AUTO_CLOCK
+#ifndef PC98_8M
+#if 0
+ imul $6667, %edx
+#else
+ leal (%edx,%edx,4), %eax /* a = 5 */
+ leal (%edx,%eax,2), %eax /* a = 11 */
+ movl %eax, %ecx /* c = 11 */
+ addl %edx, %eax /* a = 12 */
+ addl %edx, %eax /* a = 13 */
+ shl $9, %eax /* a = 6656 */
+ addl %ecx, %eax /* a = 6667 */
+#endif /* 0 */
+ shr $14, %eax
+#else /* !PC98_8M */
+#if 0
+ imul $16411, %edx
+#else
+ leal (%edx,%edx,2), %eax /* a = 3 */
+ leal (%eax,%eax,8), %eax /* a = 27 */
+ movl %eax, %ecx /* c = 27 */
+ movl %edx, %eax /* a = 1 */
+ shl $14, %eax /* a = 16384 */
+ addl %ecx, %eax /* a = 16411 */
+#endif /* 0 */
+ shr $15, %eax
+#endif /* !PC98_8M */
+#else /* !AUTO_CLOCK */
+ .globl _pc98_system_parameter
+ testb $0x80, _pc98_system_parameter + 0x501 - 0x400
+ jnz 1f
+#if 0
+ imul $6667, %edx
+#else
+ leal (%edx,%edx,4), %eax /* a = 5 */
+ leal (%edx,%eax,2), %eax /* a = 11 */
+ movl %eax, %ecx /* c = 11 */
+ addl %edx, %eax /* a = 12 */
+ addl %edx, %eax /* a = 13 */
+ shl $9, %eax /* a = 6656 */
+ addl %ecx, %eax /* a = 6667 */
+#endif /* 0 */
+ shr $14, %eax
+ jmp 2f
+1:
+#if 0
+ imul $16411, %edx
+#else
+ leal (%edx,%edx,2), %eax /* a = 3 */
+ leal (%eax,%eax,8), %eax /* a = 27 */
+ movl %eax, %ecx /* c = 27 */
+ movl %edx, %eax /* a = 1 */
+ shl $14, %eax /* a = 16384 */
+ addl %ecx, %eax /* a = 16411 */
+#endif /* 0 */
+ shr $15, %eax
+2:
+#endif /* !AUTO_CLOCK */
+#else /* IBM-PC */
+#if 0
+ imul $27645, %edx /* 25 cycles on a 486 */
+#else
+ leal (%edx,%edx,2), %eax /* a = 3 2 cycles on a 486 */
+ leal (%edx,%eax,4), %eax /* a = 13 2 */
+ movl %eax, %ecx /* c = 13 1 */
+ shl $5, %eax /* a = 416 2 */
+ addl %ecx, %eax /* a = 429 1 */
+ leal (%edx,%eax,8), %eax /* a = 3433 2 */
+ leal (%edx,%eax,8), %eax /* a = 27465 2 (total 12 cycles) */
+#endif /* 0 */
+ shr $15, %eax
+#endif /* PC98 */
+
+common_microtime:
+ addl _time+4, %eax /* usec += time.tv_sec */
+ movl _time, %edx /* sec = time.tv_sec */
+
+ sti /* enable interrupts */
+
+ cmpl $1000000, %eax /* usec valid? */
+ jb 1f
+ subl $1000000, %eax /* adjust usec */
+ incl %edx /* bump sec */
+1:
+ movl 4(%esp), %ecx /* load timeval pointer arg */
+ movl %edx, (%ecx) /* tvp->tv_sec = sec */
+ movl %eax, 4(%ecx) /* tvp->tv_usec = usec */
+
+ ret
+
+#if defined(I586_CPU) || defined(I686_CPU)
+ ALIGN_TEXT
+pentium_microtime:
+ cli
+ .byte 0x0f, 0x31 /* RDTSC */
+ subl _i586_ctr_bias, %eax
+ sbbl _i586_ctr_bias+4, %edx
+ shldl $I586_CTR_RATE_SHIFT, %eax, %edx /* magic suggested by */
+ shll $I586_CTR_RATE_SHIFT, %eax /* math_emulate.c */
+ divl %ecx /* get value in usec */
+ jmp common_microtime
+#endif
OpenPOWER on IntegriCloud