Home | History | Annotate | Line # | Download | only in isa
clock.c revision 1.2
      1 /*	$NetBSD: clock.c,v 1.2 2002/09/27 15:36:42 provos 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 
    142 #ifdef SHARK
    143 #include <shark/shark/hat.h>
    144 #endif
    145 
    146 void	sysbeepstop __P((void *));
    147 void	sysbeep __P((int, int));
    148 void	rtcinit __P((void));
    149 int     timer_hz_to_count(int);
    150 
    151 static void findcpuspeed __P((void));
    152 static void init_isa_timer_tables();
    153 static void delayloop(int);
    154 static int  clockintr __P((void *));
    155 static int  gettick __P((void));
    156 
    157 __inline u_int mc146818_read __P((void *, u_int));
    158 __inline void mc146818_write __P((void *, u_int, u_int));
    159 
    160 #define	SECMIN	((unsigned)60)			/* seconds per minute */
    161 #define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
    162 #define	SECDAY	((unsigned)(24*SECHOUR))	/* seconds per day */
    163 #define	SECYR	((unsigned)(365*SECDAY))	/* seconds per common year */
    164 
    165 __inline u_int
    166 mc146818_read(sc, reg)
    167 	void *sc;					/* XXX use it? */
    168 	u_int reg;
    169 {
    170 
    171 	outb(IO_RTC, reg);
    172 	return (inb(IO_RTC+1));
    173 }
    174 
    175 __inline void
    176 mc146818_write(sc, reg, datum)
    177 	void *sc;					/* XXX use it? */
    178 	u_int reg, datum;
    179 {
    180 
    181 	outb(IO_RTC, reg);
    182 	outb(IO_RTC+1, datum);
    183 }
    184 
    185 unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */
    186 
    187 /* number of timer ticks in a Musec = 2^20 usecs */
    188 #define TIMER_MUSECFREQ\
    189     (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000)
    190 #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x))
    191 
    192 /*
    193  * microtime() makes use of the following globals.
    194  * timer_msb_table[] and timer_lsb_table[] are used to compute the
    195  * microsecond increment.
    196  *
    197  * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb];
    198  */
    199 
    200 u_short	isa_timer_msb_table[256];	/* timer->usec MSB */
    201 u_short	isa_timer_lsb_table[256];	/* timer->usec conversion for LSB */
    202 
    203 /* 64 bit counts from timer 0 */
    204 struct count64 {
    205   unsigned lo;   /* low 32 bits */
    206   unsigned hi;   /* high 32 bits */
    207 };
    208 
    209 #define TIMER0_ROLLOVER  0xFFFF  /* maximum rollover for 8254 counter */
    210 
    211 struct count64 timer0count;
    212 struct count64 timer0_at_last_clockintr;
    213 unsigned       timer0last;
    214 
    215 /*#define TESTHAT*/
    216 #ifdef TESTHAT
    217 #define HATSTACKSIZE 1024
    218 #define HATHZ  50000
    219 #define HATHZ2 10000
    220 unsigned char hatStack[HATSTACKSIZE];
    221 
    222 unsigned testHatOn = 0;
    223 unsigned nHats = 0;
    224 unsigned nHatWedges = 0;
    225 unsigned fiqReason = 0;
    226 unsigned hatCount = 0;
    227 unsigned hatCount2 = 0;
    228 
    229 void hatTest(int testReason)
    230 {
    231   fiqReason |= testReason;
    232   nHats++;
    233 
    234 }
    235 
    236 void hatWedge(int nFIQs)
    237 {
    238     printf("Unwedging the HAT.  fiqs_happened = %d\n", nFIQs);
    239     nHatWedges++;
    240 }
    241 #endif
    242 
    243 void
    244 startrtclock()
    245 {
    246 	findcpuspeed();		/* use the clock (while it's free)
    247 					to find the cpu speed */
    248 
    249 	init_isa_timer_tables();
    250 
    251 	timer0count.lo = 0;
    252 	timer0count.hi = 0;
    253 	timer0_at_last_clockintr.lo = 0;
    254 	timer0_at_last_clockintr.hi = 0;
    255 	timer0last     = 0;
    256 
    257 	/* initialize 8253 clock */
    258 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
    259 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256);
    260 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256);
    261 
    262 #ifdef TESTHAT
    263 	hatCount = timer_hz_to_count(HATHZ);
    264 	hatCount2 = timer_hz_to_count(HATHZ2);
    265 	printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount);
    266 #endif
    267 }
    268 
    269 static void
    270 init_isa_timer_tables()
    271 {
    272 	int s;
    273 	u_long t, msbmillion, quotient, remainder;
    274 
    275 	for (s = 0; s < 256; s++) {
    276 	        /* LSB table is easy, just divide and round */
    277 		t = ((u_long) s * 1000000 * 2) / TIMER_FREQ;
    278 		isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1));
    279 
    280 		msbmillion = s * 1000000;
    281 		quotient = msbmillion / TIMER_FREQ;
    282 		remainder = msbmillion % TIMER_FREQ;
    283 		t = (remainder * 256 * 2) / TIMER_FREQ;
    284 		isa_timer_msb_table[s] =
    285 		  (u_short)((t / 2) + (t & 1) + (quotient * 256));
    286 
    287 #ifdef DIAGNOSTIC
    288 		if ((s > 0) &&
    289 		    (isa_timer_msb_table[s] <
    290 		     (isa_timer_msb_table[s - 1] + isa_timer_lsb_table[0xFF])))
    291 		  panic ("time tables not monotonic %d: %d < (%d + %d) = %d\n",
    292 			 s, isa_timer_msb_table[s],
    293 			 isa_timer_msb_table[s - 1],
    294 			 isa_timer_lsb_table[0xFF],
    295 			 isa_timer_msb_table[s - 1] +
    296 			 isa_timer_lsb_table[0xFF]);
    297 #endif
    298 	} /* END for */
    299 }
    300 
    301 int
    302 timer_hz_to_count(timer_hz)
    303 	int timer_hz;
    304 {
    305 	u_long tval;
    306 
    307 	tval = (TIMER_FREQ * 2) / (u_long) timer_hz;
    308 	tval = (tval / 2) + (tval & 0x1);
    309 
    310 	return (int)tval;
    311 
    312 }
    313 
    314 /* must be called at SPL_CLOCK or higher */
    315 void gettimer0count(pcount)
    316 	struct count64 *pcount;
    317 {
    318 	unsigned current, ticks, oldlo;
    319 
    320 	/*
    321 	 * Latch the current value of the timer and then read it.
    322 	 * This guarentees an atomic reading of the time.
    323 	 */
    324 
    325 	current = gettick();
    326 
    327 	if (timer0last >= current)
    328 	  ticks = timer0last - current;
    329 	else
    330 	  ticks = timer0last + (TIMER0_ROLLOVER - current);
    331 
    332 	timer0last = current;
    333 
    334 	oldlo = timer0count.lo;
    335 
    336 	if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */
    337 	  timer0count.hi++;
    338 
    339 	*pcount = timer0count;
    340 }
    341 
    342 static int
    343 clockintr(arg)
    344 	void *arg;
    345 {
    346 	struct clockframe *frame = arg;		/* not strictly necessary */
    347 	extern void isa_specific_eoi(int irq);
    348 #ifdef TESTHAT
    349 	static int ticks = 0;
    350 #endif
    351 #ifdef SHARK
    352 	static int hatUnwedgeCtr = 0;
    353 #endif
    354 
    355 	gettimer0count(&timer0_at_last_clockintr);
    356 
    357 	mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */
    358 
    359 #ifdef SHARK
    360 	/* check to see if the high-availability timer needs to be unwedged */
    361 	if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) {
    362 	  hatUnwedgeCtr = 0;
    363 	  hatUnwedge();
    364 	}
    365 #endif
    366 
    367 #ifdef TESTHAT
    368 	++ticks;
    369 
    370 	if (testHatOn && ((ticks & 0x3f) == 0)) {
    371 	  if (testHatOn == 1) {
    372 	    hatClkAdjust(hatCount2);
    373 	    testHatOn = 2;
    374 	  } else {
    375 	    testHatOn = 0;
    376 	    hatClkOff();
    377 	    printf("hat off status: %d %d %x\n", nHats, nHatWedges, fiqReason);
    378 	  }
    379 	} else if (!testHatOn && (ticks & 0x1ff) == 0) {
    380 	  printf("hat on status: %d %d %x\n", nHats, nHatWedges, fiqReason);
    381 	  testHatOn = 1;
    382 	  nHats = 0;
    383 	  fiqReason = 0;
    384 	  hatClkOn(hatCount, hatTest, 0xfeedface,
    385 		   hatStack + HATSTACKSIZE - sizeof(unsigned),
    386 		   hatWedge);
    387 	}
    388 #endif
    389 	hardclock(frame);
    390 	return(0);
    391 }
    392 
    393 static int
    394 gettick()
    395 {
    396 	u_char lo, hi;
    397 	u_int savedints;
    398 
    399 	/* Don't want someone screwing with the counter while we're here. */
    400 	savedints = disable_interrupts(I32_bit);
    401 	/* Select counter 0 and latch it. */
    402 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
    403 	lo = inb(IO_TIMER1 + TIMER_CNTR0);
    404 	hi = inb(IO_TIMER1 + TIMER_CNTR0);
    405 	restore_interrupts(savedints);
    406 	return ((hi << 8) | lo);
    407 }
    408 
    409 /* modifications from i386 to shark isa version:
    410    - removed hardcoded "n -=" values that approximated the time to
    411      calculate delay ticks
    412    - made the time to calculate delay ticks almost negligable. 4 multiplies
    413      = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts;
    414      as opposed to 4 multiplies plus a bunch of divides.
    415    - removed i386 assembly language hack
    416    - put code in findcpuspeed that works even if FIRST_GUESS is orders
    417      of magnitude low
    418    - put code in delay() to use delayloop() for short delays
    419    - microtime no longer in assembly language
    420 */
    421 
    422 /*
    423  * Wait "n" microseconds.
    424  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
    425  * Note: timer had better have been programmed before this is first used!
    426  * (Note that we use `rate generator' mode, which counts at 1:1; `square
    427  * wave' mode counts at 2:1).
    428  */
    429 void
    430 delay(n)
    431 	unsigned n;
    432 {
    433 	int tick, otick;
    434 	int nticks;
    435 
    436 	if (n < 100) {
    437 	  /* it can take a long time (1 usec or longer) just for 1 ISA read,
    438 	     so it's best not to use the timer for short delays */
    439 	  delayloop((n * count1024usec) >> 10);
    440 	  return;
    441 	}
    442 
    443 	/*
    444 	 * Read the counter first, so that the rest of the setup overhead is
    445 	 * counted.
    446 	 */
    447 	otick = gettick();
    448 
    449 	/*
    450 	 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
    451 	 * without any avoidable overflows.
    452 	 */
    453 	{
    454 	        /* a Musec = 2^20 usec */
    455 		int Musec = n >> 20,
    456 		    usec = n & ((1 << 20) - 1);
    457 		nticks
    458 		  = (Musec * TIMER_MUSECFREQ) +
    459 		    (usec * (TIMER_MUSECFREQ >> 20)) +
    460 		    ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) +
    461 		    ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20);
    462 	}
    463 
    464 	while (nticks > 0) {
    465 		tick = gettick();
    466 		if (tick > otick)
    467 			nticks -= TIMER0_ROLLOVER - (tick - otick);
    468 		else
    469 			nticks -= otick - tick;
    470 		otick = tick;
    471 	}
    472 
    473 }
    474 
    475 void
    476 sysbeepstop(arg)
    477 	void *arg;
    478 {
    479 }
    480 
    481 void
    482 sysbeep(pitch, period)
    483 	int pitch, period;
    484 {
    485 }
    486 
    487 #define FIRST_GUESS   0x2000
    488 
    489 static void
    490 findcpuspeed()
    491 {
    492 	int ticks;
    493 	unsigned int guess = FIRST_GUESS;
    494 
    495 	while (1) { /* loop until accurate enough */
    496 	  /* Put counter in count down mode */
    497 	  outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
    498 	  outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    499 	  outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    500 	  delayloop(guess);
    501 
    502 	  /* Read the value left in the counter */
    503 	  /*
    504 	   * Formula for delaycount is:
    505 	   *  (loopcount * timer clock speed) / (counter ticks * 1000)
    506 	   */
    507 	  ticks = 0xFFFF - gettick();
    508 	  if (ticks == 0) ticks = 1; /* just in case */
    509 	  if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */
    510 	    guess *= max(2, (TIMER_MUSECDIV(1024) / ticks));
    511 	    continue;
    512 	  }
    513 	  count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks;
    514 	  return;
    515 	}
    516 }
    517 
    518 static void
    519 delayloop(counts)
    520 {
    521   while (counts--);
    522 }
    523 
    524 void
    525 cpu_initclocks()
    526 {
    527         unsigned hzval;
    528 
    529 	printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
    530 
    531 	/* install RTC interrupt handler */
    532 	(void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK,
    533 				 clockintr, 0);
    534 
    535 	/* code for values of hz that don't divide 1000000 exactly */
    536         tickfix = 1000000 - (hz * tick);
    537         if (tickfix) {
    538                 int ftp;
    539 
    540                 ftp = min(ffs(tickfix), ffs(hz));
    541                 tickfix >>= (ftp - 1);
    542                 tickfixinterval = hz >> (ftp - 1);
    543         }
    544 
    545 	/* set  up periodic interrupt @ hz
    546 	   this is the subset of hz values in kern_clock.c that are
    547 	   supported by the ISA RTC */
    548 	switch (hz) {
    549 	case 64:
    550 		hzval = MC_RATE_64_Hz;
    551 		break;
    552 	case 128:
    553 		hzval = MC_RATE_128_Hz;
    554 		break;
    555 	case 256:
    556 		hzval = MC_RATE_256_Hz;
    557 		break;
    558 	case 1024:
    559 		hzval = MC_RATE_1024_Hz;
    560 		break;
    561 	default:
    562 		panic("cannot configure hz = %d", hz);
    563         }
    564 
    565 	rtcinit(); /* make sure basics are done by now */
    566 
    567 	/* blast values to set up clock interrupt */
    568 	mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval);
    569 	/* enable periodic interrupt */
    570 	mc146818_write(NULL, MC_REGB,
    571 		       mc146818_read(NULL, MC_REGB) | MC_REGB_PIE);
    572 }
    573 
    574 void
    575 rtcinit()
    576 {
    577 	static int first_rtcopen_ever = 1;
    578 
    579 	if (!first_rtcopen_ever)
    580 		return;
    581 	first_rtcopen_ever = 0;
    582 
    583 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
    584 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
    585 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
    586 }
    587 
    588 void
    589 setstatclockrate(arg)
    590 	int arg;
    591 {
    592 }
    593 
    594 /*
    595  * void microtime(struct timeval *tvp)
    596  *
    597  * Fill in the specified timeval struct with the current time
    598  * accurate to the microsecond.
    599  */
    600 
    601 void
    602 microtime(tvp)
    603 	struct timeval *tvp;
    604 {
    605         int s;
    606 	unsigned lsb, msb;
    607 	int tm;
    608 	static struct timeval oldtv;
    609 	struct count64 timer0current;
    610 	int ticks;
    611 
    612 	s = splstatclock();
    613 
    614 	gettimer0count(&timer0current);
    615 
    616 	tm = time.tv_usec;
    617 
    618 	/* unsigned arithmetic should take care of overflow */
    619 	/* with a >= 32 Hz clock, ticks will always be < 0x7FFF */
    620 	ticks = (int)((unsigned)
    621 		      (timer0current.lo - timer0_at_last_clockintr.lo));
    622 
    623 #ifdef DIAGNOSTIC
    624 	if ((ticks < 0) || (ticks > 0xffff))
    625 	  printf("microtime bug: ticks = %x\n", ticks);
    626 #endif
    627 
    628 	while (ticks > 0) {
    629 
    630 	  if (ticks < 0xffff) {
    631 	    msb = (ticks >> 8) & 0xFF;
    632 	    lsb = ticks & 0xFF;
    633 	  } else {
    634 	    msb = 0xff;
    635 	    lsb = 0xff;
    636 	  }
    637 
    638 	  /* see comments above */
    639 	  tm  += isa_timer_msb_table[msb] + isa_timer_lsb_table[lsb];
    640 
    641 	  /* for a 64 Hz RTC, ticks will never overflow table */
    642 	  /* microtime will be less accurate if the RTC is < 36 Hz */
    643 	  ticks -= 0xffff;
    644 	}
    645 
    646 	tvp->tv_sec = time.tv_sec;
    647 	if (tm >= 1000000) {
    648 	  tvp->tv_sec += 1;
    649 	  tm -= 1000000;
    650 	}
    651 
    652 	tvp->tv_usec = tm;
    653 
    654 	/* Make sure the time has advanced. */
    655 
    656 	if (tvp->tv_sec == oldtv.tv_sec &&
    657 	    tvp->tv_usec <= oldtv.tv_usec) {
    658 		tvp->tv_usec = oldtv.tv_usec + 1;
    659 		if (tvp->tv_usec >= 1000000) {
    660 			tvp->tv_usec -= 1000000;
    661 			++tvp->tv_sec;
    662 		}
    663 	}
    664 
    665 	oldtv = *tvp;
    666 	(void)splx(s);
    667 }
    668 
    669 /* End of clock.c */
    670