Deleted Added
full compact
clock.c (15345) clock.c (15508)
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz and Don Ahn.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 20 unchanged lines hidden (view full) ---

29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz and Don Ahn.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 20 unchanged lines hidden (view full) ---

29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
37 * $Id: clock.c,v 1.56 1996/04/05 18:56:10 ache Exp $
37 * $Id: clock.c,v 1.57 1996/04/22 19:40:28 nate Exp $
38 */
39
40/*
41 * inittodr, settodr and support routines written
42 * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
43 *
44 * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94
45 */
46
47/*
48 * Primitive clock interrupt routines.
49 */
50#include "opt_ddb.h"
51
52#include <sys/param.h>
53#include <sys/systm.h>
54#include <sys/time.h>
55#include <sys/kernel.h>
38 */
39
40/*
41 * inittodr, settodr and support routines written
42 * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
43 *
44 * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94
45 */
46
47/*
48 * Primitive clock interrupt routines.
49 */
50#include "opt_ddb.h"
51
52#include <sys/param.h>
53#include <sys/systm.h>
54#include <sys/time.h>
55#include <sys/kernel.h>
56#include <sys/sysctl.h>
57
56#include <machine/clock.h>
58#include <machine/clock.h>
59#ifdef CLK_CALIBRATION_LOOP
60#include <machine/cons.h>
61#endif
62#include <machine/cpu.h>
57#include <machine/frame.h>
63#include <machine/frame.h>
64
58#include <i386/isa/icu.h>
59#include <i386/isa/isa.h>
60#include <i386/isa/isa_device.h>
61#include <i386/isa/rtc.h>
62#include <i386/isa/timerreg.h>
63
64/*
65 * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
66 * can use a simple formula for leap years.
67 */
68#define LEAPYEAR(y) ((u_int)(y) % 4 == 0)
69#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
70
65#include <i386/isa/icu.h>
66#include <i386/isa/isa.h>
67#include <i386/isa/isa_device.h>
68#include <i386/isa/rtc.h>
69#include <i386/isa/timerreg.h>
70
71/*
72 * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
73 * can use a simple formula for leap years.
74 */
75#define LEAPYEAR(y) ((u_int)(y) % 4 == 0)
76#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
77
71/* X-tals being what they are, it's nice to be able to fudge this one... */
72#ifndef TIMER_FREQ
73#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
74#endif
75#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
78#define TIMER_DIV(x) ((timer_freq + (x) / 2) / (x))
76
77/*
78 * Time in timer cycles that it takes for microtime() to disable interrupts
79 * and latch the count. microtime() currently uses "cli; outb ..." so it
80 * normally takes less than 2 timer cycles. Add a few for cache misses.
81 * Add a few more to allow for latency in bogus calls to microtime() with
82 * interrupts already disabled.
83 */

--- 9 unchanged lines hidden (view full) ---

93#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
94
95int adjkerntz; /* local offset from GMT in seconds */
96int disable_rtc_set; /* disable resettodr() if != 0 */
97int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
98
99u_int idelayed;
100#if defined(I586_CPU) || defined(I686_CPU)
79
80/*
81 * Time in timer cycles that it takes for microtime() to disable interrupts
82 * and latch the count. microtime() currently uses "cli; outb ..." so it
83 * normally takes less than 2 timer cycles. Add a few for cache misses.
84 * Add a few more to allow for latency in bogus calls to microtime() with
85 * interrupts already disabled.
86 */

--- 9 unchanged lines hidden (view full) ---

96#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
97
98int adjkerntz; /* local offset from GMT in seconds */
99int disable_rtc_set; /* disable resettodr() if != 0 */
100int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
101
102u_int idelayed;
103#if defined(I586_CPU) || defined(I686_CPU)
104unsigned i586_ctr_freq;
101unsigned i586_ctr_rate;
102long long i586_ctr_bias;
103long long i586_last_tick;
104unsigned long i586_avg_tick;
105#endif
106int statclock_disable;
107u_int stat_imask = SWI_CLOCK_MASK;
108int timer0_max_count;

--- 11 unchanged lines hidden (view full) ---

120 * to switch between clkintr() and a slightly different timerintr().
121 * This will require locking when acquiring and releasing timer0 - the
122 * current (nonexistent) locking doesn't seem to be adequate even now.
123 */
124static void (*new_function) __P((struct clockframe *frame));
125static u_int new_rate;
126static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
127static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR;
105unsigned i586_ctr_rate;
106long long i586_ctr_bias;
107long long i586_last_tick;
108unsigned long i586_avg_tick;
109#endif
110int statclock_disable;
111u_int stat_imask = SWI_CLOCK_MASK;
112int timer0_max_count;

--- 11 unchanged lines hidden (view full) ---

124 * to switch between clkintr() and a slightly different timerintr().
125 * This will require locking when acquiring and releasing timer0 - the
126 * current (nonexistent) locking doesn't seem to be adequate even now.
127 */
128static void (*new_function) __P((struct clockframe *frame));
129static u_int new_rate;
130static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
131static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR;
132#ifdef TIMER_FREQ
133static u_int timer_freq = TIMER_FREQ;
134#else
135static u_int timer_freq = 1193182;
136#endif
128static char timer0_state = 0;
129static char timer2_state = 0;
130static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
131
132#if 0
133void
134clkintr(struct clockframe frame)
135{

--- 146 unchanged lines hidden (view full) ---

282 /* select timer0 and latch counter value */
283 outb(TIMER_MODE, TIMER_SEL0);
284 low = inb(TIMER_CNTR0);
285 high = inb(TIMER_CNTR0);
286 enable_intr();
287 return ((high << 8) | low);
288}
289
137static char timer0_state = 0;
138static char timer2_state = 0;
139static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
140
141#if 0
142void
143clkintr(struct clockframe frame)
144{

--- 146 unchanged lines hidden (view full) ---

291 /* select timer0 and latch counter value */
292 outb(TIMER_MODE, TIMER_SEL0);
293 low = inb(TIMER_CNTR0);
294 high = inb(TIMER_CNTR0);
295 enable_intr();
296 return ((high << 8) | low);
297}
298
290#if defined(I586_CPU) || defined(I686_CPU)
291/*
299/*
292 * Figure out how fast the cyclecounter runs. This must be run with
293 * clock interrupts disabled, but with the timer/counter programmed
294 * and running.
295 */
296void
297calibrate_cyclecounter(void)
298{
299 /*
300 * Don't need volatile; should always use unsigned if 2's
301 * complement arithmetic is desired.
302 */
303 unsigned long long count;
304
305#define howlong 131072UL
306 __asm __volatile(".byte 0x0f, 0x30" : : "A"(0LL), "c" (0x10));
307 DELAY(howlong);
308 __asm __volatile(".byte 0xf,0x31" : "=A" (count));
309
310 i586_ctr_rate = (count << I586_CTR_RATE_SHIFT) / howlong;
311#undef howlong
312}
313#endif
314
315/*
316 * Wait "n" microseconds.
300 * Wait "n" microseconds.
317 * Relies on timer 1 counting down from (TIMER_FREQ / hz)
301 * Relies on timer 1 counting down from (timer_freq / hz)
318 * Note: timer had better have been programmed before this is first used!
319 */
320void
321DELAY(int n)
322{
323 int prev_tick, tick, ticks_left, sec, usec;
324
325#ifdef DELAYDEBUG

--- 15 unchanged lines hidden (view full) ---

341 * counted. Guess the initial overhead is 20 usec (on most systems it
342 * takes about 1.5 usec for each of the i/o's in getit(). The loop
343 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
344 * multiplications and divisions to scale the count take a while).
345 */
346 prev_tick = getit();
347 n -= 20;
348 /*
302 * Note: timer had better have been programmed before this is first used!
303 */
304void
305DELAY(int n)
306{
307 int prev_tick, tick, ticks_left, sec, usec;
308
309#ifdef DELAYDEBUG

--- 15 unchanged lines hidden (view full) ---

325 * counted. Guess the initial overhead is 20 usec (on most systems it
326 * takes about 1.5 usec for each of the i/o's in getit(). The loop
327 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
328 * multiplications and divisions to scale the count take a while).
329 */
330 prev_tick = getit();
331 n -= 20;
332 /*
349 * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
333 * Calculate (n * (timer_freq / 1e6)) without using floating point
350 * and without any avoidable overflows.
351 */
352 sec = n / 1000000;
353 usec = n - sec * 1000000;
334 * and without any avoidable overflows.
335 */
336 sec = n / 1000000;
337 usec = n - sec * 1000000;
354 ticks_left = sec * TIMER_FREQ
355 + usec * (TIMER_FREQ / 1000000)
356 + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
357 + usec * (TIMER_FREQ % 1000) / 1000000;
338 ticks_left = sec * timer_freq
339 + usec * (timer_freq / 1000000)
340 + usec * ((timer_freq % 1000000) / 1000) / 1000
341 + usec * (timer_freq % 1000) / 1000000;
342 if (n < 0)
343 ticks_left = 0; /* XXX timer_freq is unsigned */
358
359 while (ticks_left > 0) {
360 tick = getit();
361#ifdef DELAYDEBUG
362 ++getit_calls;
363#endif
364 if (tick > prev_tick)
365 ticks_left -= prev_tick - (tick - timer0_max_count);

--- 59 unchanged lines hidden (view full) ---

425}
426
427static __inline int
428readrtc(int port)
429{
430 return(bcd2bin(rtcin(port)));
431}
432
344
345 while (ticks_left > 0) {
346 tick = getit();
347#ifdef DELAYDEBUG
348 ++getit_calls;
349#endif
350 if (tick > prev_tick)
351 ticks_left -= prev_tick - (tick - timer0_max_count);

--- 59 unchanged lines hidden (view full) ---

411}
412
413static __inline int
414readrtc(int port)
415{
416 return(bcd2bin(rtcin(port)));
417}
418
419static u_int
420calibrate_clocks(void)
421{
422 u_int count, prev_count, tot_count;
423 int sec, start_sec, timeout;
424
425 printf("Calibrating clock(s) relative to mc146818A clock ... ");
426 if (!(rtcin(RTC_STATUSD) & RTCSD_PWR))
427 goto fail;
428 timeout = 100000000;
429
430 /* Read the mc146818A seconds counter. */
431 for (;;) {
432 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) {
433 sec = rtcin(RTC_SEC);
434 break;
435 }
436 if (--timeout == 0)
437 goto fail;
438 }
439
440 /* Wait for the mC146818A seconds counter to change. */
441 start_sec = sec;
442 for (;;) {
443 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) {
444 sec = rtcin(RTC_SEC);
445 if (sec != start_sec)
446 break;
447 }
448 if (--timeout == 0)
449 goto fail;
450 }
451
452 /* Start keeping track of the i8254 counter. */
453 prev_count = getit();
454 if (prev_count == 0 || prev_count > timer0_max_count)
455 goto fail;
456 tot_count = 0;
457
458#if defined(I586_CPU) || defined(I686_CPU)
459 if (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686)
460 wrmsr(0x10, 0LL); /* XXX 0x10 is the MSR for the TSC */
461#endif
462
463 /*
464 * Wait for the mc146818A seconds counter to change. Read the i8254
465 * counter for each iteration since this is convenient and only
466 * costs a few usec of inaccuracy. The timing of the final reads
467 * of the counters almost matches the timing of the initial reads,
468 * so the main cause of inaccuracy is the varying latency from
469 * inside getit() or rtcin(RTC_STATUSA) to the beginning of the
470 * rtcin(RTC_SEC) that returns a changed seconds count. The
471 * maximum inaccuracy from this cause is < 10 usec on 486's.
472 */
473 start_sec = sec;
474 for (;;) {
475 if (!(rtcin(RTC_STATUSA) & RTCSA_TUP))
476 sec = rtcin(RTC_SEC);
477 count = getit();
478 if (count == 0 || count > timer0_max_count)
479 goto fail;
480 if (count > prev_count)
481 tot_count += prev_count - (count - timer0_max_count);
482 else
483 tot_count += prev_count - count;
484 prev_count = count;
485 if (sec != start_sec)
486 break;
487 if (--timeout == 0)
488 goto fail;
489 }
490
491#if defined(I586_CPU) || defined(I686_CPU)
492 /*
493 * Read the cpu cycle counter. The timing considerations are
494 * similar to those for the i8254 clock.
495 */
496 if (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686) {
497 unsigned long long i586_count;
498
499 i586_count = rdtsc();
500 i586_ctr_freq = i586_count;
501 i586_ctr_rate = (i586_count << I586_CTR_RATE_SHIFT) / 1000000;
502 printf("i586 clock: %u Hz, ", i586_ctr_freq);
503 }
504#endif
505
506 printf("i8254 clock: %u Hz\n", tot_count);
507 return (tot_count);
508
509fail:
510 printf("failed, using default i8254 clock of %u Hz\n", timer_freq);
511 return (timer_freq);
512}
513
514static void
515set_timer_freq(u_int freq, int intr_freq)
516{
517 u_long ef;
518
519 ef = read_eflags();
520 timer_freq = freq;
521 timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq);
522 timer0_overflow_threshold = timer0_max_count - TIMER0_LATCH_COUNT;
523 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
524 outb(TIMER_CNTR0, timer0_max_count & 0xff);
525 outb(TIMER_CNTR0, timer0_max_count >> 8);
526 write_eflags(ef);
527}
528
433/*
434 * Initialize 8253 timer 0 early so that it can be used in DELAY().
435 * XXX initialization of other timers is unintentionally left blank.
436 */
437void
438startrtclock()
439{
529/*
530 * Initialize 8253 timer 0 early so that it can be used in DELAY().
531 * XXX initialization of other timers is unintentionally left blank.
532 */
533void
534startrtclock()
535{
440 timer0_max_count = hardclock_max_count = TIMER_DIV(hz);
441 timer0_overflow_threshold = timer0_max_count - TIMER0_LATCH_COUNT;
442 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
443 outb(TIMER_CNTR0, timer0_max_count & 0xff);
444 outb(TIMER_CNTR0, timer0_max_count >> 8);
536 u_int delta, freq;
537
538 writertc(RTC_STATUSA, rtc_statusa);
539 writertc(RTC_STATUSB, RTCSB_24HR);
540
541 /*
542 * Temporarily calibrate with a high intr_freq to get a low
543 * timer0_max_count to help detect bogus i8254 counts.
544 */
545 set_timer_freq(timer_freq, 20000);
546 freq = calibrate_clocks();
547#ifdef CLK_CALIBRATION_LOOP
548 if (bootverbose) {
549 printf(
550 "Press a key on the console to abort clock calibration\n");
551 while (!cncheckc())
552 calibrate_clocks();
553 }
554#endif
555
556 /*
557 * Use the calibrated i8254 frequency if it seems reasonable.
558 * Otherwise use the default, and don't use the calibrated i586
559 * frequency.
560 */
561 delta = freq > timer_freq ? freq - timer_freq : timer_freq - freq;
562 if (delta < timer_freq / 100) {
563#ifndef CLK_USE_I8254_CALIBRATION
564 printf(
565"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n");
566 freq = timer_freq;
567#endif
568 timer_freq = freq;
569 } else {
570 printf("%d Hz differs from default of %d Hz by more than 1%%\n",
571 freq, timer_freq);
572#if defined(I586_CPU) || defined(I686_CPU)
573 i586_ctr_freq = 0;
574 i586_ctr_rate = 0;
575#endif
576 }
577
578 set_timer_freq(timer_freq, hz);
579
580#if defined(I586_CPU) || defined(I686_CPU)
581#ifndef CLK_USE_I586_CALIBRATION
582 if (i586_ctr_rate != 0) {
583 printf(
584"CLK_USE_I586_CALIBRATION not specified - using old calibration method\n");
585 i586_ctr_freq = 0;
586 i586_ctr_rate = 0;
587 }
588#endif
589 if (i586_ctr_rate == 0 &&
590 (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686)) {
591 /*
592 * Calibration of the i586 clock relative to the mc146818A
593 * clock failed. Do a less accurate calibration relative
594 * to the i8254 clock.
595 */
596 unsigned long long i586_count;
597
598 wrmsr(0x10, 0LL); /* XXX */
599 DELAY(1000000);
600 i586_count = rdtsc();
601 i586_ctr_rate = (i586_count << I586_CTR_RATE_SHIFT) / 1000000;
602 printf("i586 clock: %u Hz\n", i586_ctr_freq);
603 }
604#endif
445}
446
447/*
448 * Initialize the time of day register, based on the time base which is, e.g.
449 * from a filesystem.
450 */
451void
452inittodr(time_t base)

--- 139 unchanged lines hidden (view full) ---

592 /* XXX */ (inthand2_t *)clkintr, &clk_imask,
593 /* unit */ 0);
594 INTREN(IRQ0);
595#if defined(I586_CPU) || defined(I686_CPU)
596 /*
597 * Finish setting up anti-jitter measures.
598 */
599 if (i586_ctr_rate) {
605}
606
607/*
608 * Initialize the time of day register, based on the time base which is, e.g.
609 * from a filesystem.
610 */
611void
612inittodr(time_t base)

--- 139 unchanged lines hidden (view full) ---

752 /* XXX */ (inthand2_t *)clkintr, &clk_imask,
753 /* unit */ 0);
754 INTREN(IRQ0);
755#if defined(I586_CPU) || defined(I686_CPU)
756 /*
757 * Finish setting up anti-jitter measures.
758 */
759 if (i586_ctr_rate) {
600 I586_CYCLECTR(i586_last_tick);
760 i586_last_tick = rdtsc();
601 i586_ctr_bias = i586_last_tick;
602 }
603#endif
604
605 /* Initialize RTC. */
606 writertc(RTC_STATUSA, rtc_statusa);
607 writertc(RTC_STATUSB, RTCSB_24HR);
608

--- 14 unchanged lines hidden (view full) ---

623setstatclockrate(int newhz)
624{
625 if (newhz == RTC_PROFRATE)
626 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF;
627 else
628 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
629 writertc(RTC_STATUSA, rtc_statusa);
630}
761 i586_ctr_bias = i586_last_tick;
762 }
763#endif
764
765 /* Initialize RTC. */
766 writertc(RTC_STATUSA, rtc_statusa);
767 writertc(RTC_STATUSB, RTCSB_24HR);
768

--- 14 unchanged lines hidden (view full) ---

783setstatclockrate(int newhz)
784{
785 if (newhz == RTC_PROFRATE)
786 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF;
787 else
788 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
789 writertc(RTC_STATUSA, rtc_statusa);
790}
791
792static int
793sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS
794{
795 int error;
796 u_int freq;
797
798 /*
799 * Use `i8254' instead of `timer' in external names because `timer'
800 * is is too generic. Should use it everywhere.
801 */
802 freq = timer_freq;
803 error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req);
804 if (error == 0 && freq != timer_freq) {
805 if (timer0_state != 0)
806 return (EBUSY); /* too much trouble to handle */
807 set_timer_freq(freq, hz);
808 }
809 return (error);
810}
811
812SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
813 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", "");
814
815#if defined(I586_CPU) || defined(I686_CPU)
816static int
817sysctl_machdep_i586_freq SYSCTL_HANDLER_ARGS
818{
819 int error;
820 u_int freq;
821
822 if (i586_ctr_rate == 0)
823 return (EOPNOTSUPP);
824 freq = i586_ctr_freq;
825 error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req);
826 if (error == 0 && freq != i586_ctr_freq) {
827 i586_ctr_freq = freq;
828 i586_ctr_rate = ((unsigned long long)freq <<
829 I586_CTR_RATE_SHIFT) / 1000000;
830 }
831 return (error);
832}
833
834SYSCTL_PROC(_machdep, OID_AUTO, i586_freq, CTLTYPE_INT | CTLFLAG_RW,
835 0, sizeof(u_int), sysctl_machdep_i586_freq, "I", "");
836#endif /* defined(I586_CPU) || defined(I686_CPU) */