diff options
Diffstat (limited to 'sys/pc98/i386/microtime.s')
-rw-r--r-- | sys/pc98/i386/microtime.s | 262 |
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 |