comparison packages/kernel/current/src/common/clock.cxx @ 64:c38311975d4f ecos-sw-2000-01-28

Merge from eCos master repository on 2000-01-28-04:28:11-GMT
author jlarmour
date Fri, 28 Jan 2000 04:59:39 +0000
parents 29bc183297e1
children bf00f99aec69
comparison
equal deleted inserted replaced
63:119e6e57c342 64:c38311975d4f
4 // 4 //
5 // Clock class implementations 5 // Clock class implementations
6 // 6 //
7 //========================================================================== 7 //==========================================================================
8 //####COPYRIGHTBEGIN#### 8 //####COPYRIGHTBEGIN####
9 // 9 //
10 // ------------------------------------------- 10 // -------------------------------------------
11 // The contents of this file are subject to the Cygnus eCos Public License 11 // The contents of this file are subject to the Red Hat eCos Public License
12 // Version 1.0 (the "License"); you may not use this file except in 12 // Version 1.0 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at 13 // compliance with the License. You may obtain a copy of the License at
14 // http://sourceware.cygnus.com/ecos 14 // http://sourceware.cygnus.com/ecos
15 // 15 //
16 // Software distributed under the License is distributed on an "AS IS" 16 // Software distributed under the License is distributed on an
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under 18 // License for the specific language governing rights and limitations under
19 // the License. 19 // the License.
20 // 20 //
21 // The Original Code is eCos - Embedded Cygnus Operating System, released 21 // The Original Code is eCos - Embedded Configurable Operating System,
22 // September 30, 1998. 22 // released September 30, 1998.
23 // 23 //
24 // The Initial Developer of the Original Code is Cygnus. Portions created 24 // The Initial Developer of the Original Code is Red Hat.
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. 25 // Portions created by Red Hat are
26 // ------------------------------------------- 26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
27 // 27 // All Rights Reserved.
28 // -------------------------------------------
29 //
28 //####COPYRIGHTEND#### 30 //####COPYRIGHTEND####
29 //========================================================================== 31 //==========================================================================
30 //#####DESCRIPTIONBEGIN#### 32 //#####DESCRIPTIONBEGIN####
31 // 33 //
32 // Author(s): nickg 34 // Author(s): nickg
483 return true; 485 return true;
484 } 486 }
485 487
486 #endif 488 #endif
487 489
490 // -------------------------------------------------------------------------
491 //
492 // Clock Converters: split a rational into 4 factors to try to prevent
493 // overflow whilst retaining reasonable accuracy.
494 //
495 // typically we get numbers like 1,000,000 for ns_per and
496 // 100 and 1,000,000,000 for the dividend and divisor.
497 // So we want answers like 1/10 and 10/1 out of these routines.
498
499 static void construct_converter( Cyg_Clock::converter *pcc,
500 cyg_uint64 m1, cyg_uint64 d1,
501 cyg_uint64 m2, cyg_uint64 d2 )
502 {
503 cyg_uint64 upper, lower;
504 unsigned int i;
505 static cyg_uint16 primes[] = {
506 3,5,7,11,13,17,19,23,29,31,37,41,43,47,
507 53,59,61,67,71,73,79,83,89,97,
508 101,103,107,109,113,127,131,137,139,149,
509 151,157,163,167,173,179,181,191,193,197,199,
510 239, // for 1,111,111
511 541, // for 10,101,011
512 1667, // for 8,333,333
513 };
514
515 int rounding = 0;
516
517 // Here we assume that our workings will fit in a 64; the point is to
518 // allow calculations with a number of ticks that may be large.
519 upper = m1 * m2;
520 lower = d1 * d2;
521 #ifdef CYGDBG_USE_ASSERTS
522 cyg_uint64 save_upper = upper;
523 cyg_uint64 save_lower = lower;
524 #endif
525
526 retry_rounding:
527 // First strip out common powers of 2
528 while ( (0 == (1 & upper)) && ( 0 == (1 & lower)) ) {
529 upper >>= 1;
530 lower >>= 1;
531 }
532
533 // then common factors - use lazy table above
534 for ( i = 0 ; i < (sizeof( primes )/sizeof( primes[0] )); i++ ) {
535 cyg_uint64 j, k, p = (cyg_uint64)(primes[i]);
536 j = upper / p;
537 while ( j * p == upper ) {
538 k = lower / p;
539 if ( k * p != lower )
540 break;
541 upper = j;
542 lower = k;
543 j = upper / p;
544 }
545 }
546
547 m1 = upper;
548 d1 = lower;
549 m2 = 1;
550 d2 = 1;
551
552 if ( m1 > 0x10000 ) {
553 // only bother if there are more than 16 bits consumed here
554
555 // now move powers of 2 from d1 to d2
556 // keeping them the same order of magnitude
557 while ( (0 == (1 & d1)) && (d2 < d1) ) {
558 d1 >>= 1;
559 d2 <<= 1;
560 }
561
562 // and factors from the table - go too far, if anything
563 int cont = (d2 < d1);
564 for ( i = 0 ; cont && (i < (sizeof( primes )/sizeof( primes[0] ))); i++ ) {
565 cyg_uint64 k, p = (cyg_uint64)(primes[i]);
566 k = d1 / p;
567 while ( cont && ((k * p) == d1) ) {
568 // we can extract a prime
569 d1 = k;
570 d2 *= p;
571 k = d1 / p;
572 cont = (d2 < d1);
573 }
574 }
575
576 // move powers of 2 from m1 to m2 so long as we do not go less than d1
577 while ( (0 == (1 & m1)) && (m2 < m1) && (m1 > (d1 << 5)) ) {
578 m1 >>= 1;
579 m2 <<= 1;
580 if ( m1 < 0x10000 )
581 break;
582 }
583
584 // and factors from the table - ensure m1 stays well larger than d1
585 cont = ((m2 < m1) && (m1 > (d1 << 4)) && (m1 > 0x10000));
586 for ( i = 0 ; cont && (i < (sizeof( primes )/sizeof( primes[0] ))); i++ ) {
587 cyg_uint64 k, p = (cyg_uint64)(primes[i]);
588 k = m1 / p;
589 cont = cont && (k > (d1 << 4) && (k > 0x10000));
590 while ( cont && ((k * p) == m1) ) {
591 // we can extract a prime
592 m1 = k;
593 m2 *= p;
594 k = m1 / p; // examine k for getting too small
595 cont = ((m2 < m1) && (k > (d1 << 4)) && (k > 0x10000));
596 }
597 }
598
599 // if, after all that, m1 odd and unchanged, and too large,
600 // decrement it just the once and try again: then try it
601 // incremented once.
602 if ( (m1 & 1) && (m1 == upper) && (m1 > 0x10000) && (rounding < 2) ) {
603 CYG_ASSERT( 1 == m2, "m2 should be 1 to try rounding" );
604 m1--;
605 upper = m1;
606 rounding++;
607 goto retry_rounding;
608 }
609 // likewise for d1 - each of the pair can be odd only once each
610 if ( (d1 & 1) && (d1 == lower) && (d1 > 0x10000) && (rounding < 2) ) {
611 CYG_ASSERT( 1 == d2, "d2 should be 1 to try rounding" );
612 d1--;
613 lower = d1;
614 rounding++;
615 goto retry_rounding;
616 }
617 }
618
619 CYG_ASSERT( 0 != m1, "m1 zero" );
620 CYG_ASSERT( 0 != m2, "m2 zero" );
621 CYG_ASSERT( 0 != d1, "d1 zero" );
622 CYG_ASSERT( 0 != d2, "d2 zero" );
623 CYG_ASSERT( rounding || save_upper/save_lower == (m1 * m2)/(d1 * d2),
624 "Unequal in forwards direction" );
625 CYG_ASSERT( rounding || save_lower/save_upper == (d1 * d2)/(m1 * m2),
626 "Unequal in reverse direction" );
627
628 pcc->mul1 = m1;
629 pcc->div1 = d1;
630 pcc->mul2 = m2;
631 pcc->div2 = d2;
632 }
633
634 // other to clocks is (other * ns_per * dividend / divisor)
635 void Cyg_Clock::get_other_to_clock_converter(
636 cyg_uint64 ns_per_other_tick,
637 struct converter *pcc )
638 {
639 construct_converter( pcc,
640 ns_per_other_tick, 1,
641 resolution.divisor, resolution.dividend );
642 }
643
644 // clocks to other is (ticks * divisor / dividend / ns_per)
645 void Cyg_Clock::get_clock_to_other_converter(
646 cyg_uint64 ns_per_other_tick,
647 struct converter *pcc )
648 {
649 construct_converter( pcc,
650 1, ns_per_other_tick,
651 resolution.dividend, resolution.divisor );
652 }
653
654
488 //========================================================================== 655 //==========================================================================
489 // Constructor for alarm object 656 // Constructor for alarm object
490 657
491 Cyg_Alarm::Cyg_Alarm( 658 Cyg_Alarm::Cyg_Alarm(
492 Cyg_Counter *c, // Attached to this counter 659 Cyg_Counter *c, // Attached to this counter