Date: Sat, 7 Dec 1996 19:23:04 +0900 (JST) From: ohashi@mickey.ai.kyutech.ac.jp (Takeshi Ohashi) To: current@freebsd.org Subject: Re: DELAY() in clock.c Message-ID: <199612071023.TAA06868@mickey.ai.kyutech.ac.jp> In-Reply-To: Your message of Fri, 6 Dec 1996 23:28:29 %2B1100. <199612061228.XAA24120@godzilla.zeta.org.au>
next in thread | previous in thread | raw e-mail | index | archive | help
<199612061228.XAA24120@godzilla.zeta.org.au> bde>>I like this version better. There are still 2 problems: bde>> bde>>1. If the user boots with the turbo button off (possibly to fix problems bde>> caused by DELAY() not being long enough) then the calibration will be bde>> wrong. Fix: recalibrate every now and then, perhaps when DELAY() is bde>> called with a large arg. This won't fixed problems caused by devices bde>> hanging because delays are too short, but can't hurt. bde>> bde>>2. The calibration method has some problems. Thank you for your kindly suggestions. I rewrote the fix patch. Please check it. # When I was debugging it, a if statement did not work right. # Is it a compiler's bug? -- Takeshi OHASHI, Kyushu Inst. of Tech. ohashi@mickey.ai.kyutech.ac.jp --- clock.c.orig Sat Oct 26 09:11:57 1996 +++ clock.c Sat Dec 7 18:39:19 1996 @@ -133,6 +133,8 @@ static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; +static u_int delay_offset = 20; /* It should be calibrated */ + /* Values for timerX_state: */ #define RELEASED 0 #define RELEASE_PENDING 1 @@ -354,6 +356,55 @@ } /* + * calibrate delay_offset for DELAY() + * This is called from calibrate_clock() and DELAY(). + */ +static int +calibrate_delay_offset(void) +{ + int i, start_tick, end_tick, min_ticks; + u_int delta_ticks, delay_offset_old, delay_offset_tmp; + u_long ef; + const int loops = 100; + const int delay = 10; + + delay_offset_old = delay_offset; + delay_offset = 0; + min_ticks = INT_MAX; + for (i = 0; i < loops; i++) { + ef = read_eflags(); + start_tick = getit(); + DELAY(delay); + end_tick = getit(); + write_eflags(ef); + delta_ticks = start_tick - end_tick; + if (min_ticks > delta_ticks) + min_ticks = delta_ticks; + } + if (min_ticks == INT_MAX) { + printf("warning: cannot calibrate delay offset\n"); + delay_offset = delay_offset_tmp = 20; + } else { + delay_offset_tmp = min_ticks * 1000000LL / timer_freq - delay; +/* Why does not it work right? + if (delay_offset_tmp < delay_offset_old) + delay_offset = delay_offset_tmp; +*/ + delay_offset = (delay_offset_tmp < delay_offset_old) ? + delay_offset_tmp : delay_offset_old; +#define DELAYOFFSETDEBUG +#ifdef DELAYOFFSETDEBUG + if (delay_offset != delay_offset_old) { + printf("DELAY offset: %u usec\n", delay_offset); + } +#endif + if (!(0 <= delay_offset || delay_offset <= 20)) + delay_offset = 20; + } + return ((delay_offset_tmp + delay) * loops); +} + +/* * Wait "n" microseconds. * Relies on timer 1 counting down from (timer_freq / hz) * Note: timer had better have been programmed before this is first used! @@ -384,8 +435,11 @@ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The * multiplications and divisions to scale the count take a while). */ + if (n > 10000) { + n -= calibrate_delay_offset(); + } prev_tick = getit(); - n -= 20; + n = (n <= delay_offset) ? 1 : (n - delay_offset); /* * Calculate (n * (timer_freq / 1e6)) without using floating point * and without any avoidable overflows. @@ -564,6 +618,9 @@ #endif printf("i8254 clock: %u Hz\n", tot_count); + + calibrate_delay_offset(); + return (tot_count); fail:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199612071023.TAA06868>