Home | History | Annotate | Line # | Download | only in isa
clock.c revision 1.3
      1 /*	$NetBSD: clock.c,v 1.3 2002/10/05 17:01:49 chs Exp $	*/
      2 
      3 /*
      4  * Copyright 1997
      5  * Digital Equipment Corporation. All rights reserved.
      6  *
      7  * This software is furnished under license and may be used and
      8  * copied only in accordance with the following terms and conditions.
      9  * Subject to these conditions, you may download, copy, install,
     10  * use, modify and distribute this software in source and/or binary
     11  * form. No title or ownership is transferred hereby.
     12  *
     13  * 1) Any source code used, modified or distributed must reproduce
     14  *    and retain this copyright notice and list of conditions as
     15  *    they appear in the source file.
     16  *
     17  * 2) No right is granted to use any trade name, trademark, or logo of
     18  *    Digital Equipment Corporation. Neither the "Digital Equipment
     19  *    Corporation" name nor any trademark or logo of Digital Equipment
     20  *    Corporation may be used to endorse or promote products derived
     21  *    from this software without the prior written permission of
     22  *    Digital Equipment Corporation.
     23  *
     24  * 3) This software is provided "AS-IS" and any express or implied
     25  *    warranties, including but not limited to, any implied warranties
     26  *    of merchantability, fitness for a particular purpose, or
     27  *    non-infringement are disclaimed. In no event shall DIGITAL be
     28  *    liable for any damages whatsoever, and in particular, DIGITAL
     29  *    shall not be liable for special, indirect, consequential, or
     30  *    incidental damages or damages for lost profits, loss of
     31  *    revenue or loss of use, whether such damages arise in contract,
     32  *    negligence, tort, under statute, in equity, at law or otherwise,
     33  *    even if advised of the possibility of such damage.
     34  */
     35 
     36 /*-
     37  * Copyright (c) 1993, 1994 Charles M. Hannum.
     38  * Copyright (c) 1990 The Regents of the University of California.
     39  * All rights reserved.
     40  *
     41  * This code is derived from software contributed to Berkeley by
     42  * William Jolitz and Don Ahn.
     43  *
     44  * Redistribution and use in source and binary forms, with or without
     45  * modification, are permitted provided that the following conditions
     46  * are met:
     47  * 1. Redistributions of source code must retain the above copyright
     48  *    notice, this list of conditions and the following disclaimer.
     49  * 2. Redistributions in binary form must reproduce the above copyright
     50  *    notice, this list of conditions and the following disclaimer in the
     51  *    documentation and/or other materials provided with the distribution.
     52  * 3. All advertising materials mentioning features or use of this software
     53  *    must display the following acknowledgement:
     54  *	This product includes software developed by the University of
     55  *	California, Berkeley and its contributors.
     56  * 4. Neither the name of the University nor the names of its contributors
     57  *    may be used to endorse or promote products derived from this software
     58  *    without specific prior written permission.
     59  *
     60  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     61  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     62  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     63  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     64  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     65  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     66  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     67  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     68  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     69  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     70  * SUCH DAMAGE.
     71  *
     72  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
     73  */
     74 /*
     75  * Mach Operating System
     76  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
     77  * All Rights Reserved.
     78  *
     79  * Permission to use, copy, modify and distribute this software and its
     80  * documentation is hereby granted, provided that both the copyright
     81  * notice and this permission notice appear in all copies of the
     82  * software, derivative works or modified versions, and any portions
     83  * thereof, and that both notices appear in supporting documentation.
     84  *
     85  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     86  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     87  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     88  *
     89  * Carnegie Mellon requests users of this software to return to
     90  *
     91  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     92  *  School of Computer Science
     93  *  Carnegie Mellon University
     94  *  Pittsburgh PA 15213-3890
     95  *
     96  * any improvements or extensions that they make and grant Carnegie Mellon
     97  * the rights to redistribute these changes.
     98  */
     99 /*
    100   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
    101 
    102 		All Rights Reserved
    103 
    104 Permission to use, copy, modify, and distribute this software and
    105 its documentation for any purpose and without fee is hereby
    106 granted, provided that the above copyright notice appears in all
    107 copies and that both the copyright notice and this permission notice
    108 appear in supporting documentation, and that the name of Intel
    109 not be used in advertising or publicity pertaining to distribution
    110 of the software without specific, written prior permission.
    111 
    112 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
    113 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
    114 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
    115 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    116 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
    117 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
    118 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    119 */
    120 
    121 /*
    122  * Primitive clock interrupt routines.
    123  */
    124 #include <sys/param.h>
    125 #include <sys/systm.h>
    126 #include <sys/time.h>
    127 #include <sys/kernel.h>
    128 #include <sys/device.h>
    129 
    130 #include <machine/cpu.h>
    131 #include <machine/intr.h>
    132 #include <machine/pio.h>
    133 #include <arm/cpufunc.h>
    134 
    135 #include <dev/isa/isareg.h>
    136 #include <dev/isa/isavar.h>
    137 #include <dev/ic/mc146818reg.h>
    138 #include <dev/ic/i8253reg.h>
    139 #include <shark/isa/nvram.h>
    140 #include <shark/isa/spkrreg.h>
    141 #include <shark/shark/hat.h>
    142 
    143 void	sysbeepstop(void *);
    144 void	sysbeep(int, int);
    145 void	rtcinit(void);
    146 int     timer_hz_to_count(int);
    147 
    148 static void findcpuspeed(void);
    149 static void init_isa_timer_tables(void);
    150 static void delayloop(int);
    151 static int  clockintr(void *);
    152 static int  gettick(void);
    153 
    154 void startrtclock(void);
    155 
    156 __inline u_int mc146818_read(void *, u_int);
    157 __inline void mc146818_write(void *, u_int, u_int);
    158 
    159 #define	SECMIN	((unsigned)60)			/* seconds per minute */
    160 #define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
    161 #define	SECDAY	((unsigned)(24*SECHOUR))	/* seconds per day */
    162 #define	SECYR	((unsigned)(365*SECDAY))	/* seconds per common year */
    163 
    164 __inline u_int
    165 mc146818_read(sc, reg)
    166 	void *sc;					/* XXX use it? */
    167 	u_int reg;
    168 {
    169 
    170 	outb(IO_RTC, reg);
    171 	return (inb(IO_RTC+1));
    172 }
    173 
    174 __inline void
    175 mc146818_write(sc, reg, datum)
    176 	void *sc;					/* XXX use it? */
    177 	u_int reg, datum;
    178 {
    179 
    180 	outb(IO_RTC, reg);
    181 	outb(IO_RTC+1, datum);
    182 }
    183 
    184 unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */
    185 
    186 /* number of timer ticks in a Musec = 2^20 usecs */
    187 #define TIMER_MUSECFREQ\
    188     (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000)
    189 #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x))
    190 
    191 /*
    192  * microtime() makes use of the following globals.
    193  * timer_msb_table[] and timer_lsb_table[] are used to compute the
    194  * microsecond increment.
    195  *
    196  * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb];
    197  */
    198 
    199 u_short	isa_timer_msb_table[256];	/* timer->usec MSB */
    200 u_short	isa_timer_lsb_table[256];	/* timer->usec conversion for LSB */
    201 
    202 /* 64 bit counts from timer 0 */
    203 struct count64 {
    204   unsigned lo;   /* low 32 bits */
    205   unsigned hi;   /* high 32 bits */
    206 };
    207 
    208 #define TIMER0_ROLLOVER  0xFFFF  /* maximum rollover for 8254 counter */
    209 
    210 struct count64 timer0count;
    211 struct count64 timer0_at_last_clockintr;
    212 unsigned       timer0last;
    213 
    214 /*#define TESTHAT*/
    215 #ifdef TESTHAT
    216 #define HATSTACKSIZE 1024
    217 #define HATHZ  50000
    218 #define HATHZ2 10000
    219 unsigned char hatStack[HATSTACKSIZE];
    220 
    221 unsigned testHatOn = 0;
    222 unsigned nHats = 0;
    223 unsigned nHatWedges = 0;
    224 unsigned fiqReason = 0;
    225 unsigned hatCount = 0;
    226 unsigned hatCount2 = 0;
    227 
    228 void hatTest(int testReason)
    229 {
    230   fiqReason |= testReason;
    231   nHats++;
    232 
    233 }
    234 
    235 void hatWedge(int nFIQs)
    236 {
    237     printf("Unwedging the HAT.  fiqs_happened = %d\n", nFIQs);
    238     nHatWedges++;
    239 }
    240 #endif
    241 
    242 void
    243 startrtclock()
    244 {
    245 	findcpuspeed();		/* use the clock (while it's free)
    246 					to find the cpu speed */
    247 
    248 	init_isa_timer_tables();
    249 
    250 	timer0count.lo = 0;
    251 	timer0count.hi = 0;
    252 	timer0_at_last_clockintr.lo = 0;
    253 	timer0_at_last_clockintr.hi = 0;
    254 	timer0last     = 0;
    255 
    256 	/* initialize 8253 clock */
    257 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
    258 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256);
    259 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256);
    260 
    261 #ifdef TESTHAT
    262 	hatCount = timer_hz_to_count(HATHZ);
    263 	hatCount2 = timer_hz_to_count(HATHZ2);
    264 	printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount);
    265 #endif
    266 }
    267 
    268 static void
    269 init_isa_timer_tables()
    270 {
    271 	int s;
    272 	u_long t, msbmillion, quotient, remainder;
    273 
    274 	for (s = 0; s < 256; s++) {
    275 	        /* LSB table is easy, just divide and round */
    276 		t = ((u_long) s * 1000000 * 2) / TIMER_FREQ;
    277 		isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1));
    278 
    279 		msbmillion = s * 1000000;
    280 		quotient = msbmillion / TIMER_FREQ;
    281 		remainder = msbmillion % TIMER_FREQ;
    282 		t = (remainder * 256 * 2) / TIMER_FREQ;
    283 		isa_timer_msb_table[s] =
    284 		  (u_short)((t / 2) + (t & 1) + (quotient * 256));
    285 
    286 #ifdef DIAGNOSTIC
    287 		if ((s > 0) &&
    288 		    (isa_timer_msb_table[s] <
    289 		     (isa_timer_msb_table[s - 1] + isa_timer_lsb_table[0xFF])))
    290 		  panic ("time tables not monotonic %d: %d < (%d + %d) = %d\n",
    291 			 s, isa_timer_msb_table[s],
    292 			 isa_timer_msb_table[s - 1],
    293 			 isa_timer_lsb_table[0xFF],
    294 			 isa_timer_msb_table[s - 1] +
    295 			 isa_timer_lsb_table[0xFF]);
    296 #endif
    297 	} /* END for */
    298 }
    299 
    300 int
    301 timer_hz_to_count(timer_hz)
    302 	int timer_hz;
    303 {
    304 	u_long tval;
    305 
    306 	tval = (TIMER_FREQ * 2) / (u_long) timer_hz;
    307 	tval = (tval / 2) + (tval & 0x1);
    308 
    309 	return (int)tval;
    310 
    311 }
    312 
    313 void gettimer0count(struct count64 *);
    314 
    315 /* must be called at SPL_CLOCK or higher */
    316 void gettimer0count(pcount)
    317 	struct count64 *pcount;
    318 {
    319 	unsigned current, ticks, oldlo;
    320 
    321 	/*
    322 	 * Latch the current value of the timer and then read it.
    323 	 * This guarentees an atomic reading of the time.
    324 	 */
    325 
    326 	current = gettick();
    327 
    328 	if (timer0last >= current)
    329 	  ticks = timer0last - current;
    330 	else
    331 	  ticks = timer0last + (TIMER0_ROLLOVER - current);
    332 
    333 	timer0last = current;
    334 
    335 	oldlo = timer0count.lo;
    336 
    337 	if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */
    338 	  timer0count.hi++;
    339 
    340 	*pcount = timer0count;
    341 }
    342 
    343 static int
    344 clockintr(arg)
    345 	void *arg;
    346 {
    347 	struct clockframe *frame = arg;		/* not strictly necessary */
    348 	extern void isa_specific_eoi(int irq);
    349 #ifdef TESTHAT
    350 	static int ticks = 0;
    351 #endif
    352 	static int hatUnwedgeCtr = 0;
    353 
    354 	gettimer0count(&timer0_at_last_clockintr);
    355 
    356 	mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */
    357 
    358 	/* check to see if the high-availability timer needs to be unwedged */
    359 	if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) {
    360 	  hatUnwedgeCtr = 0;
    361 	  hatUnwedge();
    362 	}
    363 
    364 #ifdef TESTHAT
    365 	++ticks;
    366 
    367 	if (testHatOn && ((ticks & 0x3f) == 0)) {
    368 	  if (testHatOn == 1) {
    369 	    hatClkAdjust(hatCount2);
    370 	    testHatOn = 2;
    371 	  } else {
    372 	    testHatOn = 0;
    373 	    hatClkOff();
    374 	    printf("hat off status: %d %d %x\n", nHats, nHatWedges, fiqReason);
    375 	  }
    376 	} else if (!testHatOn && (ticks & 0x1ff) == 0) {
    377 	  printf("hat on status: %d %d %x\n", nHats, nHatWedges, fiqReason);
    378 	  testHatOn = 1;
    379 	  nHats = 0;
    380 	  fiqReason = 0;
    381 	  hatClkOn(hatCount, hatTest, 0xfeedface,
    382 		   hatStack + HATSTACKSIZE - sizeof(unsigned),
    383 		   hatWedge);
    384 	}
    385 #endif
    386 	hardclock(frame);
    387 	return(0);
    388 }
    389 
    390 static int
    391 gettick()
    392 {
    393 	u_char lo, hi;
    394 	u_int savedints;
    395 
    396 	/* Don't want someone screwing with the counter while we're here. */
    397 	savedints = disable_interrupts(I32_bit);
    398 	/* Select counter 0 and latch it. */
    399 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
    400 	lo = inb(IO_TIMER1 + TIMER_CNTR0);
    401 	hi = inb(IO_TIMER1 + TIMER_CNTR0);
    402 	restore_interrupts(savedints);
    403 	return ((hi << 8) | lo);
    404 }
    405 
    406 /* modifications from i386 to shark isa version:
    407    - removed hardcoded "n -=" values that approximated the time to
    408      calculate delay ticks
    409    - made the time to calculate delay ticks almost negligable. 4 multiplies
    410      = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts;
    411      as opposed to 4 multiplies plus a bunch of divides.
    412    - removed i386 assembly language hack
    413    - put code in findcpuspeed that works even if FIRST_GUESS is orders
    414      of magnitude low
    415    - put code in delay() to use delayloop() for short delays
    416    - microtime no longer in assembly language
    417 */
    418 
    419 /*
    420  * Wait "n" microseconds.
    421  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
    422  * Note: timer had better have been programmed before this is first used!
    423  * (Note that we use `rate generator' mode, which counts at 1:1; `square
    424  * wave' mode counts at 2:1).
    425  */
    426 void
    427 delay(n)
    428 	unsigned n;
    429 {
    430 	int tick, otick;
    431 	int nticks;
    432 
    433 	if (n < 100) {
    434 	  /* it can take a long time (1 usec or longer) just for 1 ISA read,
    435 	     so it's best not to use the timer for short delays */
    436 	  delayloop((n * count1024usec) >> 10);
    437 	  return;
    438 	}
    439 
    440 	/*
    441 	 * Read the counter first, so that the rest of the setup overhead is
    442 	 * counted.
    443 	 */
    444 	otick = gettick();
    445 
    446 	/*
    447 	 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
    448 	 * without any avoidable overflows.
    449 	 */
    450 	{
    451 	        /* a Musec = 2^20 usec */
    452 		int Musec = n >> 20,
    453 		    usec = n & ((1 << 20) - 1);
    454 		nticks
    455 		  = (Musec * TIMER_MUSECFREQ) +
    456 		    (usec * (TIMER_MUSECFREQ >> 20)) +
    457 		    ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) +
    458 		    ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20);
    459 	}
    460 
    461 	while (nticks > 0) {
    462 		tick = gettick();
    463 		if (tick > otick)
    464 			nticks -= TIMER0_ROLLOVER - (tick - otick);
    465 		else
    466 			nticks -= otick - tick;
    467 		otick = tick;
    468 	}
    469 
    470 }
    471 
    472 void
    473 sysbeepstop(arg)
    474 	void *arg;
    475 {
    476 }
    477 
    478 void
    479 sysbeep(pitch, period)
    480 	int pitch, period;
    481 {
    482 }
    483 
    484 #define FIRST_GUESS   0x2000
    485 
    486 static void
    487 findcpuspeed()
    488 {
    489 	int ticks;
    490 	unsigned int guess = FIRST_GUESS;
    491 
    492 	while (1) { /* loop until accurate enough */
    493 	  /* Put counter in count down mode */
    494 	  outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
    495 	  outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    496 	  outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    497 	  delayloop(guess);
    498 
    499 	  /* Read the value left in the counter */
    500 	  /*
    501 	   * Formula for delaycount is:
    502 	   *  (loopcount * timer clock speed) / (counter ticks * 1000)
    503 	   */
    504 	  ticks = 0xFFFF - gettick();
    505 	  if (ticks == 0) ticks = 1; /* just in case */
    506 	  if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */
    507 	    guess *= max(2, (TIMER_MUSECDIV(1024) / ticks));
    508 	    continue;
    509 	  }
    510 	  count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks;
    511 	  return;
    512 	}
    513 }
    514 
    515 static void
    516 delayloop(counts)
    517 {
    518   while (counts--);
    519 }
    520 
    521 void
    522 cpu_initclocks()
    523 {
    524         unsigned hzval;
    525 
    526 	printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
    527 
    528 	/* install RTC interrupt handler */
    529 	(void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK,
    530 				 clockintr, 0);
    531 
    532 	/* code for values of hz that don't divide 1000000 exactly */
    533         tickfix = 1000000 - (hz * tick);
    534         if (tickfix) {
    535                 int ftp;
    536 
    537                 ftp = min(ffs(tickfix), ffs(hz));
    538                 tickfix >>= (ftp - 1);
    539                 tickfixinterval = hz >> (ftp - 1);
    540         }
    541 
    542 	/* set  up periodic interrupt @ hz
    543 	   this is the subset of hz values in kern_clock.c that are
    544 	   supported by the ISA RTC */
    545 	switch (hz) {
    546 	case 64:
    547 		hzval = MC_RATE_64_Hz;
    548 		break;
    549 	case 128:
    550 		hzval = MC_RATE_128_Hz;
    551 		break;
    552 	case 256:
    553 		hzval = MC_RATE_256_Hz;
    554 		break;
    555 	case 1024:
    556 		hzval = MC_RATE_1024_Hz;
    557 		break;
    558 	default:
    559 		panic("cannot configure hz = %d", hz);
    560         }
    561 
    562 	rtcinit(); /* make sure basics are done by now */
    563 
    564 	/* blast values to set up clock interrupt */
    565 	mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval);
    566 	/* enable periodic interrupt */
    567 	mc146818_write(NULL, MC_REGB,
    568 		       mc146818_read(NULL, MC_REGB) | MC_REGB_PIE);
    569 }
    570 
    571 void
    572 rtcinit()
    573 {
    574 	static int first_rtcopen_ever = 1;
    575 
    576 	if (!first_rtcopen_ever)
    577 		return;
    578 	first_rtcopen_ever = 0;
    579 
    580 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
    581 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
    582 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
    583 }
    584 
    585 void
    586 setstatclockrate(arg)
    587 	int arg;
    588 {
    589 }
    590 
    591 /*
    592  * void microtime(struct timeval *tvp)
    593  *
    594  * Fill in the specified timeval struct with the current time
    595  * accurate to the microsecond.
    596  */
    597 
    598 void
    599 microtime(tvp)
    600 	struct timeval *tvp;
    601 {
    602         int s;
    603 	unsigned lsb, msb;
    604 	int tm;
    605 	static struct timeval oldtv;
    606 	struct count64 timer0current;
    607 	int ticks;
    608 
    609 	s = splstatclock();
    610 
    611 	gettimer0count(&timer0current);
    612 
    613 	tm = time.tv_usec;
    614 
    615 	/* unsigned arithmetic should take care of overflow */
    616 	/* with a >= 32 Hz clock, ticks will always be < 0x7FFF */
    617 	ticks = (int)((unsigned)
    618 		      (timer0current.lo - timer0_at_last_clockintr.lo));
    619 
    620 #ifdef DIAGNOSTIC
    621 	if ((ticks < 0) || (ticks > 0xffff))
    622 	  printf("microtime bug: ticks = %x\n", ticks);
    623 #endif
    624 
    625 	while (ticks > 0) {
    626 
    627 	  if (ticks < 0xffff) {
    628 	    msb = (ticks >> 8) & 0xFF;
    629 	    lsb = ticks & 0xFF;
    630 	  } else {
    631 	    msb = 0xff;
    632 	    lsb = 0xff;
    633 	  }
    634 
    635 	  /* see comments above */
    636 	  tm  += isa_timer_msb_table[msb] + isa_timer_lsb_table[lsb];
    637 
    638 	  /* for a 64 Hz RTC, ticks will never overflow table */
    639 	  /* microtime will be less accurate if the RTC is < 36 Hz */
    640 	  ticks -= 0xffff;
    641 	}
    642 
    643 	tvp->tv_sec = time.tv_sec;
    644 	if (tm >= 1000000) {
    645 	  tvp->tv_sec += 1;
    646 	  tm -= 1000000;
    647 	}
    648 
    649 	tvp->tv_usec = tm;
    650 
    651 	/* Make sure the time has advanced. */
    652 
    653 	if (tvp->tv_sec == oldtv.tv_sec &&
    654 	    tvp->tv_usec <= oldtv.tv_usec) {
    655 		tvp->tv_usec = oldtv.tv_usec + 1;
    656 		if (tvp->tv_usec >= 1000000) {
    657 			tvp->tv_usec -= 1000000;
    658 			++tvp->tv_sec;
    659 		}
    660 	}
    661 
    662 	oldtv = *tvp;
    663 	(void)splx(s);
    664 }
    665 
    666 /* End of clock.c */
    667