Implement a clkread() function for microtime() using a multu/mfhi

sequence using the reciprocal of the delay divisor to perform the
division.
Set the cp0 compare register so that it doesn't trigger interrupts and
reset the cp0 count register in the hardclock interrupt handler.
This commit is contained in:
simonb 2002-03-06 07:47:57 +00:00
parent 86cb239e4f
commit 2bf916e97d
2 changed files with 53 additions and 6 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: sbtimer.c,v 1.2 2002/03/06 03:25:09 simonb Exp $ */
/* $NetBSD: sbtimer.c,v 1.3 2002/03/06 07:47:57 simonb Exp $ */
/*
* Copyright 2000, 2001
@ -178,6 +178,9 @@ sbtimer_clockintr(void *arg, uint32_t status, uint32_t pc)
cf.pc = pc;
cf.sr = status;
/* reset the CPU count register (used by microtime) */
mips3_cp0_count_write(0);
hardclock(&cf);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: systemsw.c,v 1.2 2002/03/06 03:29:16 simonb Exp $ */
/* $NetBSD: systemsw.c,v 1.3 2002/03/06 07:47:57 simonb Exp $ */
/*
* Copyright 2000, 2001
@ -42,12 +42,13 @@
#include <machine/systemsw.h>
/* trivial functions for function switch */
static void microtime_triv(struct timeval *);
static void delay_triv(u_long);
static void clock_init_triv(void *);
static uint32_t clkread_triv(void);
static void cpu_intr_triv(uint32_t, uint32_t, uint32_t, uint32_t);
static void cpu_setsoftintr_triv(void);
static void clock_init_triv(void *);
static void delay_triv(u_long);
static void inittodr_triv(void *, time_t);
static void microtime_triv(struct timeval *);
static void resettodr_triv(void *);
#define XXXNULL NULL
@ -57,6 +58,7 @@ struct systemsw systemsw = {
cpu_intr_triv,
cpu_setsoftintr_triv,
microtime_triv,
clkread_triv,
delay_triv,
NULL, /* clock intr arg */
@ -85,12 +87,45 @@ system_set_clockfns(void *arg, void (*init)(void *))
static void
microtime_triv(struct timeval *tvp)
{
int s = splclock();
int s;
static struct timeval lasttime;
s = splclock();
*tvp = time;
if (systemsw.s_clkread)
tvp->tv_usec += systemsw.s_clkread();
if (tvp->tv_usec >= 1000000) {
tvp->tv_usec -= 1000000;
tvp->tv_sec++;
}
if (tvp->tv_sec == lasttime.tv_sec &&
tvp->tv_usec <= lasttime.tv_usec &&
(tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
tvp->tv_sec++;
tvp->tv_usec -= 1000000;
}
lasttime = *tvp;
splx(s);
}
static uint32_t
clkread_triv(void)
{
uint32_t res, count;
count = mips3_cp0_count_read();
asm volatile("multu %1,%2 ; mfhi %0"
: "=r"(res) : "r"(count), "r"(curcpu()->ci_divisor_recip));
return (res);
}
/* trivial delay() implementation */
static void
delay_triv(u_long n)
@ -109,6 +144,7 @@ cpu_intr_triv(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
panic("cpu_intr_triv");
}
void
cpu_setsoftintr_triv(void)
{
@ -157,6 +193,14 @@ cpu_initclocks(void)
if (systemsw.s_statclock_init != NULL)
(*systemsw.s_statclock_init)(XXXNULL);
/*
* ``Disable'' the compare interrupt by setting it to it's largest
* value. The counter will be reset to 0 every hz. This is used
* for microtime.
*/
mips3_cp0_compare_write(~(uint32_t)0);
mips3_cp0_count_write(0);
}
void