📄 clock.cxx
字号:
#ifdef CYGDBG_USE_ASSERTSbool Cyg_Clock::check_this( cyg_assert_class_zeal zeal) const{ // check that we have a non-NULL pointer first if( this == NULL ) return false; switch( zeal ) { case cyg_system_test: case cyg_extreme: case cyg_thorough: case cyg_quick: case cyg_trivial: case cyg_none: default: break; }; return true;}#endif// -------------------------------------------------------------------------// // Clock Converters: split a rational into 4 factors to try to prevent// overflow whilst retaining reasonable accuracy.// // typically we get numbers like 1,000,000 for ns_per and// 100 and 1,000,000,000 for the dividend and divisor.// So we want answers like 1/10 and 10/1 out of these routines.static void construct_converter( Cyg_Clock::converter *pcc, cyg_uint64 m1, cyg_uint64 d1, cyg_uint64 m2, cyg_uint64 d2 ){ cyg_uint64 upper, lower; unsigned int i; static cyg_uint16 primes[] = { 3,5,7,11,13,17,19,23,29,31,37,41,43,47, 53,59,61,67,71,73,79,83,89,97, 101,103,107,109,113,127,131,137,139,149, 151,157,163,167,173,179,181,191,193,197,199, 239, // for 1,111,111 541, // for 10,101,011 1667, // for 8,333,333 }; int rounding = 0; // Here we assume that our workings will fit in a 64; the point is to // allow calculations with a number of ticks that may be large. upper = m1 * m2; lower = d1 * d2;#ifdef CYGDBG_USE_ASSERTS cyg_uint64 save_upper = upper; cyg_uint64 save_lower = lower;#endif retry_rounding: // First strip out common powers of 2 while ( (0 == (1 & upper)) && ( 0 == (1 & lower)) ) { upper >>= 1; lower >>= 1; } // then common factors - use lazy table above for ( i = 0 ; i < (sizeof( primes )/sizeof( primes[0] )); i++ ) { cyg_uint64 j, k, p = (cyg_uint64)(primes[i]); j = upper / p; while ( j * p == upper ) { k = lower / p; if ( k * p != lower ) break; upper = j; lower = k; j = upper / p; } } m1 = upper; d1 = lower; m2 = 1; d2 = 1; if ( m1 > 0x10000 ) { // only bother if there are more than 16 bits consumed here // now move powers of 2 from d1 to d2 // keeping them the same order of magnitude while ( (0 == (1 & d1)) && (d2 < d1) ) { d1 >>= 1; d2 <<= 1; } // and factors from the table - go too far, if anything int cont = (d2 < d1); for ( i = 0 ; cont && (i < (sizeof( primes )/sizeof( primes[0] ))); i++ ) { cyg_uint64 k, p = (cyg_uint64)(primes[i]); k = d1 / p; while ( cont && ((k * p) == d1) ) { // we can extract a prime d1 = k; d2 *= p; k = d1 / p; cont = (d2 < d1); } } // move powers of 2 from m1 to m2 so long as we do not go less than d1 while ( (0 == (1 & m1)) && (m2 < m1) && (m1 > (d1 << 5)) ) { m1 >>= 1; m2 <<= 1; if ( m1 < 0x10000 ) break; } // and factors from the table - ensure m1 stays well larger than d1 cont = ((m2 < m1) && (m1 > (d1 << 4)) && (m1 > 0x10000)); for ( i = 0 ; cont && (i < (sizeof( primes )/sizeof( primes[0] ))); i++ ) { cyg_uint64 k, p = (cyg_uint64)(primes[i]); k = m1 / p; cont = cont && (k > (d1 << 4) && (k > 0x10000)); while ( cont && ((k * p) == m1) ) { // we can extract a prime m1 = k; m2 *= p; k = m1 / p; // examine k for getting too small cont = ((m2 < m1) && (k > (d1 << 4)) && (k > 0x10000)); } } // if, after all that, m1 odd and unchanged, and too large, // decrement it just the once and try again: then try it // incremented once. if ( (m1 & 1) && (m1 == upper) && (m1 > 0x10000) && (rounding < 2) ) { CYG_ASSERT( 1 == m2, "m2 should be 1 to try rounding" ); m1--; upper = m1; rounding++; goto retry_rounding; } // likewise for d1 - each of the pair can be odd only once each if ( (d1 & 1) && (d1 == lower) && (d1 > 0x10000) && (rounding < 2) ) { CYG_ASSERT( 1 == d2, "d2 should be 1 to try rounding" ); d1--; lower = d1; rounding++; goto retry_rounding; } } CYG_ASSERT( 0 != m1, "m1 zero" ); CYG_ASSERT( 0 != m2, "m2 zero" ); CYG_ASSERT( 0 != d1, "d1 zero" ); CYG_ASSERT( 0 != d2, "d2 zero" ); CYG_ASSERT( rounding || save_upper/save_lower == (m1 * m2)/(d1 * d2), "Unequal in forwards direction" ); CYG_ASSERT( rounding || save_lower/save_upper == (d1 * d2)/(m1 * m2), "Unequal in reverse direction" ); pcc->mul1 = m1; pcc->div1 = d1; pcc->mul2 = m2; pcc->div2 = d2;}// other to clocks is (other * ns_per * dividend / divisor)void Cyg_Clock::get_other_to_clock_converter( cyg_uint64 ns_per_other_tick, struct converter *pcc ){ construct_converter( pcc, ns_per_other_tick, 1, resolution.divisor, resolution.dividend );}// clocks to other is (ticks * divisor / dividend / ns_per)void Cyg_Clock::get_clock_to_other_converter( cyg_uint64 ns_per_other_tick, struct converter *pcc ){ construct_converter( pcc, 1, ns_per_other_tick, resolution.dividend, resolution.divisor );}//==========================================================================// Constructor for alarm objectCyg_Alarm::Cyg_Alarm( Cyg_Counter *c, // Attached to this counter cyg_alarm_fn *a, // Call-back function CYG_ADDRWORD d // Call-back data ){ CYG_REPORT_FUNCTION(); counter = c; alarm = a; data = d; trigger = 0; interval = 0; enabled = false;#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST) || defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST) next = NULL;#endif }Cyg_Alarm::Cyg_Alarm(){}// -------------------------------------------------------------------------// DestructorCyg_Alarm::~Cyg_Alarm(){ CYG_REPORT_FUNCTION(); disable();}// -------------------------------------------------------------------------// #ifdef CYGDBG_USE_ASSERTSbool Cyg_Alarm::check_this( cyg_assert_class_zeal zeal) const{ // check that we have a non-NULL pointer first if( this == NULL ) return false; switch( zeal ) { case cyg_system_test: case cyg_extreme: case cyg_thorough: if( trigger != 0 && !enabled ) return false; case cyg_quick: case cyg_trivial: case cyg_none: default: break; }; return true;}#endif// -------------------------------------------------------------------------// Initialize Alarm and enablevoid Cyg_Alarm::initialize( cyg_tick_count t, // Absolute trigger time cyg_tick_count i // Relative retrigger interval ){ CYG_REPORT_FUNCTION(); // If already enabled, remove from counter if( enabled ) counter->rem_alarm(this); CYG_INSTRUMENT_ALARM( INIT, this, 0 ); CYG_INSTRUMENT_ALARM( TRIGGER, ((cyg_uint32 *)&t)[0], ((cyg_uint32 *)&t)[1] ); CYG_INSTRUMENT_ALARM( INTERVAL, ((cyg_uint32 *)&i)[0], ((cyg_uint32 *)&i)[1] ); trigger = t; interval = i; counter->add_alarm(this);}// -------------------------------------------------------------------------// Synchronize with a past alarm stream that had been disabled,// bring past times into synch, and the like.voidCyg_Alarm::synchronize( void ){ if( interval != 0 ) { // This expression sets the trigger to the next whole interval // at or after the current time. This means that alarms will // continue at the same intervals as if they had never been // disabled. The alternative would be to just set trigger to // (counter->counter + interval), but this is less satisfying // than preserving the original intervals. That behaviour can // always be obtained by using initialize() rather than // enable(), while the current behaviour would be more // difficult to achieve that way. cyg_tick_count d; d = counter->current_value() + interval - trigger; if ( d > interval ) { // then trigger was in the past, so resynchronize trigger += interval * ((d - 1) / interval ); } // otherwise, we were just set up, so no worries. }}// -------------------------------------------------------------------------// Ensure alarm enabledvoid Cyg_Alarm::enable(){ if( !enabled ) { // ensure the alarm time is in our future: synchronize(); enabled = true; counter->add_alarm(this); }}//==========================================================================// System clock object#ifdef CYGVAR_KERNEL_COUNTERS_CLOCKclass Cyg_RealTimeClock : public Cyg_Clock{ Cyg_Interrupt interrupt; static cyg_uint32 isr(cyg_vector vector, CYG_ADDRWORD data); static void dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data); Cyg_RealTimeClock(); static Cyg_RealTimeClock rtc;};Cyg_Clock::cyg_resolution rtc_resolution = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;//Cyg_RealTimeClock Cyg_RealTimeClock::rtc __attribute__((init_priority (1)));Cyg_RealTimeClock Cyg_RealTimeClock::rtc CYG_INIT_PRIORITY( CLOCK );// -------------------------------------------------------------------------Cyg_RealTimeClock::Cyg_RealTimeClock() : Cyg_Clock(rtc_resolution), interrupt(CYGNUM_HAL_INTERRUPT_RTC, 1, (CYG_ADDRWORD)this, isr, dsr){ CYG_REPORT_FUNCTION(); HAL_CLOCK_INITIALIZE( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD ); interrupt.attach(); interrupt.unmask_interrupt(CYGNUM_HAL_INTERRUPT_RTC); Cyg_Clock::real_time_clock = this;}#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)cyg_tick_count total_clock_latency, total_clock_interrupts;cyg_int32 min_clock_latency = 0x7FFFFFFF;cyg_int32 max_clock_latency = 0;bool measure_clock_latency = false;#endif#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls;cyg_int32 min_clock_dsr_latency = 0x7FFFFFFF;cyg_int32 max_clock_dsr_latency = 0;cyg_uint32 clock_dsr_start = 0;#endif// -------------------------------------------------------------------------cyg_uint32 Cyg_RealTimeClock::isr(cyg_vector vector, CYG_ADDRWORD data){// CYG_REPORT_FUNCTION();#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) if (measure_clock_latency) { cyg_int32 delta; HAL_CLOCK_LATENCY(&delta); // Note: Ignore a latency of 0 when finding min_clock_latency. if (delta > 0) { // Valid delta measured total_clock_latency += delta; total_clock_interrupts++; if (min_clock_latency > delta) min_clock_latency = delta; if (max_clock_latency < delta) max_clock_latency = delta; } }#endif CYG_INSTRUMENT_CLOCK( ISR, 0, 0); HAL_CLOCK_RESET( CYGNUM_HAL_INTERRUPT_RTC, CYGNUM_KERNEL_COUNTERS_RTC_PERIOD ); Cyg_Interrupt::acknowledge_interrupt(CYGNUM_HAL_INTERRUPT_RTC);#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) HAL_CLOCK_READ(&clock_dsr_start);#endif return Cyg_Interrupt::CALL_DSR|Cyg_Interrupt::HANDLED;}// -------------------------------------------------------------------------void Cyg_RealTimeClock::dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data){// CYG_REPORT_FUNCTION();#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) if (measure_clock_latency) { cyg_uint32 delta; HAL_CLOCK_READ(&delta); delta -= clock_dsr_start; // Note: Ignore a latency of <= 0 when finding min_clock_latency. if (delta > 0 ) { // Valid delta measured total_clock_dsr_latency += delta; total_clock_dsr_calls++; if (min_clock_dsr_latency > delta) min_clock_dsr_latency = delta; if (max_clock_dsr_latency < delta) max_clock_dsr_latency = delta; } }#endif Cyg_RealTimeClock *rtc = (Cyg_RealTimeClock *)data; CYG_INSTRUMENT_CLOCK( TICK_START, rtc->current_value_lo(), rtc->current_value_hi()); rtc->tick( count );#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE#if 0 == CYG_SCHED_UNIQUE_PRIORITIES // If timeslicing is enabled, call the scheduler to // handle it. But not if we have unique priorities. Cyg_Scheduler::scheduler.timeslice();#endif#endif CYG_INSTRUMENT_CLOCK( TICK_END, rtc->current_value_lo(), rtc->current_value_hi()); }#endif// -------------------------------------------------------------------------// EOF common/clock.cxx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -