OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [kernel/] [v2_0/] [src/] [common/] [clock.cxx] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      common/clock.cxx
4
//
5
//      Clock class implementations
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
// Copyright (C) 2002 Jonathan Larmour
13
//
14
// eCos is free software; you can redistribute it and/or modify it under
15
// the terms of the GNU General Public License as published by the Free
16
// Software Foundation; either version 2 or (at your option) any later version.
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21
// for more details.
22
//
23
// You should have received a copy of the GNU General Public License along
24
// with eCos; if not, write to the Free Software Foundation, Inc.,
25
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26
//
27
// As a special exception, if other files instantiate templates or use macros
28
// or inline functions from this file, or you compile this file and link it
29
// with other works to produce a work based on this file, this file does not
30
// by itself cause the resulting work to be covered by the GNU General Public
31
// License. However the source code for this file must still be made available
32
// in accordance with section (3) of the GNU General Public License.
33
//
34
// This exception does not invalidate any other reasons why a work based on
35
// this file might be covered by the GNU General Public License.
36
//
37
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38
// at http://sources.redhat.com/ecos/ecos-license/
39
// -------------------------------------------
40
//####ECOSGPLCOPYRIGHTEND####
41
//==========================================================================
42
//#####DESCRIPTIONBEGIN####
43
//
44
// Author(s):   nickg
45
// Contributors:        nickg
46
// Date:        1997-09-15
47
// Purpose:     Clock class implementation
48
// Description: This file contains the definitions of the counter,
49
//              clock and alarm class member functions that are common
50
//              to all clock implementations.
51
//
52
//####DESCRIPTIONEND####
53
//
54
//==========================================================================
55
 
56
#include <pkgconf/kernel.h>
57
 
58
#include <cyg/kernel/ktypes.h>         // base kernel types
59
#include <cyg/infra/cyg_trac.h>        // tracing macros
60
#include <cyg/infra/cyg_ass.h>         // assertion macros
61
 
62
#include <cyg/kernel/clock.hxx>        // our header
63
 
64
#include <cyg/kernel/sched.hxx>        // scheduler definitions
65
#include <cyg/kernel/thread.hxx>       // thread definitions
66
#include <cyg/kernel/intr.hxx>         // interrupt definitions
67
 
68
#include <cyg/kernel/sched.inl>        // scheduler inlines
69
#include <cyg/kernel/clock.inl>        // Clock inlines
70
 
71
// -------------------------------------------------------------------------
72
// Static variables
73
 
74
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
75
 
76
Cyg_Clock *Cyg_Clock::real_time_clock = NULL;   // System real time clock
77
 
78
#endif
79
 
80
//==========================================================================
81
// Constructor for counter object
82
 
83
Cyg_Counter::Cyg_Counter(
84
    cyg_uint32      incr
85
    )
86
{
87
    CYG_REPORT_FUNCTION();
88
 
89
    counter = 0;
90
    increment = incr;
91
 
92
}
93
 
94
// -------------------------------------------------------------------------
95
// Destructor for Counter object
96
 
97
Cyg_Counter::~Cyg_Counter()
98
{
99
    CYG_REPORT_FUNCTION();
100
 
101
 
102
}
103
 
104
// -------------------------------------------------------------------------
105
// 
106
 
107
#ifdef CYGDBG_USE_ASSERTS
108
 
109
cyg_bool Cyg_Counter::check_this( cyg_assert_class_zeal zeal) const
110
{
111
    // check that we have a non-NULL pointer first
112
    if( this == NULL ) return false;
113
 
114
    switch( zeal )
115
    {
116
    case cyg_system_test:
117
    case cyg_extreme:
118
    case cyg_thorough:
119
    case cyg_quick:
120
    case cyg_trivial:
121
    case cyg_none:
122
    default:
123
        break;
124
    };
125
 
126
    return true;
127
}
128
 
129
#endif
130
 
131
// -------------------------------------------------------------------------
132
// Counter tick function
133
 
134
void Cyg_Counter::tick( cyg_uint32 ticks )
135
{
136
//    CYG_REPORT_FUNCTION();
137
 
138
    CYG_ASSERTCLASS( this, "Bad counter object" );
139
 
140
    // Increment the counter in a loop so we process
141
    // each tick separately. This is easier than trying
142
    // to cope with a range of increments.
143
 
144
    while( ticks-- )
145
    {
146
        Cyg_Scheduler::lock();
147
 
148
        // increment the counter, note that it is
149
        // allowed to wrap.
150
        counter += increment;
151
 
152
        // now check for any expired alarms
153
 
154
        Cyg_Alarm_List *alarm_list_ptr;     // pointer to list
155
 
156
#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)
157
 
158
        alarm_list_ptr = &alarm_list;
159
 
160
#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
161
 
162
        // With multiple lists, each one contains only the alarms
163
        // that will expire at a given tick modulo the list number.
164
        // So we only have a fraction of the alarms to check here.
165
 
166
        alarm_list_ptr = &(alarm_list[
167
            (counter/increment) % CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
168
 
169
#else
170
#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
171
#endif
172
 
173
        // Now that we have the list pointer, we can use common code for
174
        // both list oragnizations.
175
 
176
#ifdef CYGIMP_KERNEL_COUNTERS_SORT_LIST
177
 
178
        // With a sorted alarm list, we can simply pick alarms off the
179
        // front of the list until we find one that is in the future.
180
 
181
        while( !alarm_list_ptr->empty() )
182
        {
183
            Cyg_Alarm *alarm = alarm_list_ptr->get_head();
184
 
185
            CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" );
186
 
187
            if( alarm->trigger <= counter )
188
            {
189
                // remove alarm from list
190
                alarm_list_ptr->rem_head();
191
 
192
                if( alarm->interval != 0 )
193
                {
194
                    // The alarm has a retrigger interval.
195
                    // Reset the trigger time and requeue
196
                    // the alarm.
197
                    alarm->trigger += alarm->interval;
198
                    add_alarm( alarm );
199
                }
200
                else alarm->enabled = false;
201
 
202
                CYG_INSTRUMENT_ALARM( CALL, this, alarm );
203
 
204
                // call alarm function
205
                alarm->alarm(alarm, alarm->data);
206
 
207
                // all done, loop
208
            }
209
            else break;
210
 
211
        }
212
#else
213
 
214
        // With an unsorted list, we must scan the whole list for
215
        // candidates. We move the whole list to a temporary location
216
        // before doing this so that we are not disturbed by new
217
        // alarms being added to the list. As we consider and
218
        // eliminate alarms we put them onto the done_list and at the
219
        // end we then move it back to where it belongs.
220
 
221
        Cyg_Alarm_List done_list;
222
 
223
        Cyg_Alarm_List alarm_list;
224
 
225
        alarm_list.merge( *alarm_list_ptr );
226
 
227
        while( !alarm_list.empty() )
228
        {
229
            Cyg_Alarm *alarm = alarm_list.rem_head();
230
 
231
            CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" );
232
 
233
            if( alarm->trigger <= counter )
234
            {
235
                if( alarm->interval != 0 )
236
                {
237
                    // The alarm has a retrigger interval.
238
                    // Reset the trigger time and requeue
239
                    // the alarm.
240
                    alarm->trigger += alarm->interval;
241
                    add_alarm( alarm );
242
                }
243
                else alarm->enabled = false;
244
 
245
                CYG_INSTRUMENT_ALARM( CALL, this, alarm );
246
 
247
                // call alarm function
248
                alarm->alarm(alarm, alarm->data);
249
 
250
                // all done, loop
251
            }
252
            else
253
            {
254
                // add unused alarm to done list.
255
                done_list.add_tail(alarm);
256
            }
257
        }
258
 
259
        // Return done list to real list. If any alarms have been
260
        // added to the alarm list while we have been scanning then
261
        // the done list will be added behind them.
262
 
263
        alarm_list_ptr->merge( done_list );
264
 
265
#endif        
266
        Cyg_Scheduler::unlock();
267
 
268
    }
269
 
270
}
271
 
272
// -------------------------------------------------------------------------
273
// Add an alarm to this counter
274
 
275
void Cyg_Counter::add_alarm( Cyg_Alarm *alarm )
276
{
277
    CYG_REPORT_FUNCTION();
278
 
279
    CYG_ASSERTCLASS( this, "Bad counter object" );
280
    CYG_ASSERTCLASS( alarm, "Bad alarm passed" );
281
 
282
    Cyg_Scheduler::lock();
283
 
284
    // set this now to allow an immediate handler call to manipulate
285
    // this alarm sensibly.
286
    alarm->enabled = true;
287
 
288
    // Check here for an alarm that triggers now or in the past and
289
    // call its alarm function immediately. 
290
    if( alarm->trigger <= counter )
291
    {
292
        CYG_INSTRUMENT_ALARM( CALL, this, alarm );
293
 
294
        // call alarm function. Note that this is being
295
        // called here before the add_alarm has returned.
296
        // Note that this function may disable the alarm.
297
 
298
        alarm->alarm(alarm, alarm->data);
299
 
300
        // Note that this extra check on alarm->enabled is in case the
301
        // handler function disables this alarm!
302
        if( alarm->interval != 0 && alarm->enabled )
303
        {
304
            // The alarm has a retrigger interval.
305
            // Reset the trigger interval and drop
306
            // through to queue it.
307
            alarm->trigger += alarm->interval;
308
            // ensure the next alarm time is in our future, and in phase
309
            // with the original time requested.
310
            alarm->synchronize();
311
        }
312
        else
313
        {
314
            // The alarm is all done with, disable it
315
            // unlock and return.
316
            alarm->enabled = false;
317
            Cyg_Scheduler::unlock();
318
            return;
319
        }
320
    }
321
 
322
    CYG_INSTRUMENT_ALARM( ADD, this, alarm );
323
 
324
    // Find the pointer to the relevant list _after_ a retrigger
325
    // alarm has been given its new trigger time.
326
 
327
    Cyg_Alarm_List *alarm_list_ptr;     // pointer to list
328
 
329
#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)
330
 
331
    alarm_list_ptr = &alarm_list;
332
 
333
#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
334
 
335
    // Each alarm must go into the list that covers the tick that is
336
    // going to happen _after_ the trigger time (or at it if trigger
337
    // happens to fall on a tick.
338
 
339
    alarm_list_ptr = &(alarm_list[
340
        ((alarm->trigger+increment-1)/increment) %
341
        CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
342
 
343
#else
344
#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
345
#endif
346
 
347
#ifdef CYGIMP_KERNEL_COUNTERS_SORT_LIST
348
 
349
    // Now that we have the list pointer, we can use common code for
350
    // both list organizations.
351
 
352
    Cyg_Alarm *list_alarm = alarm_list_ptr->get_head();
353
 
354
    if( list_alarm != NULL )
355
    {
356
        do
357
        {
358
            CYG_ASSERTCLASS(list_alarm, "Bad alarm in counter list" );
359
 
360
            // The alarms are in ascending trigger order. If we
361
            // find an alarm that triggers later than us, we go
362
            // in front of it.
363
 
364
            if( list_alarm->trigger > alarm->trigger )
365
            {
366
                alarm_list_ptr->insert( list_alarm, alarm );
367
                goto add_alarm_unlock_return;
368
            }
369
 
370
            list_alarm = list_alarm->get_next();
371
 
372
        } while( list_alarm != alarm_list_ptr->get_head() );
373
        // a lower or equal alarm time was not found, so drop through
374
        // so it is added to the list tail
375
    }
376
    alarm_list_ptr->add_tail( alarm );
377
 
378
 add_alarm_unlock_return:
379
#else    
380
 
381
    alarm_list_ptr->add_tail( alarm );
382
 
383
#endif
384
 
385
    Cyg_Scheduler::unlock();
386
}
387
 
388
// -------------------------------------------------------------------------
389
// Remove an alarm from this counter
390
 
391
void Cyg_Counter::rem_alarm( Cyg_Alarm *alarm )
392
{
393
    CYG_REPORT_FUNCTION();
394
 
395
    CYG_ASSERTCLASS( this, "Bad counter object" );
396
    CYG_ASSERTCLASS( alarm, "Bad alarm passed" );
397
 
398
    Cyg_Alarm_List *alarm_list_ptr;     // pointer to list
399
 
400
#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)
401
 
402
    alarm_list_ptr = &alarm_list;
403
 
404
#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
405
 
406
    alarm_list_ptr = &(alarm_list[
407
        ((alarm->trigger+increment-1)/increment) %
408
                              CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
409
 
410
#else
411
#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
412
#endif
413
 
414
    // Now that we have the list pointer, we can use common code for
415
    // both list organizations.
416
 
417
    Cyg_Scheduler::lock();
418
 
419
    CYG_INSTRUMENT_ALARM( REM, this, alarm );
420
 
421
    alarm_list_ptr->remove( alarm );
422
 
423
    alarm->enabled = false;
424
 
425
    Cyg_Scheduler::unlock();
426
}
427
 
428
//==========================================================================
429
// Constructor for clock object
430
 
431
Cyg_Clock::Cyg_Clock(
432
    cyg_resolution      res
433
    )
434
{
435
    CYG_REPORT_FUNCTION();
436
 
437
    resolution = res;
438
}
439
 
440
// -------------------------------------------------------------------------
441
// Destructor for Clock objects
442
 
443
Cyg_Clock::~Cyg_Clock()
444
{
445
    CYG_REPORT_FUNCTION();
446
 
447
}
448
 
449
// -------------------------------------------------------------------------
450
// 
451
 
452
#ifdef CYGDBG_USE_ASSERTS
453
 
454
cyg_bool Cyg_Clock::check_this( cyg_assert_class_zeal zeal) const
455
{
456
    // check that we have a non-NULL pointer first
457
    if( this == NULL ) return false;
458
 
459
    switch( zeal )
460
    {
461
    case cyg_system_test:
462
    case cyg_extreme:
463
    case cyg_thorough:
464
    case cyg_quick:
465
    case cyg_trivial:
466
    case cyg_none:
467
    default:
468
        break;
469
    };
470
 
471
    return true;
472
}
473
 
474
#endif
475
 
476
// -------------------------------------------------------------------------
477
// 
478
// Clock Converters: split a rational into 4 factors to try to prevent
479
// overflow whilst retaining reasonable accuracy.
480
// 
481
// typically we get numbers like 1,000,000 for ns_per and
482
// 100 and 1,000,000,000 for the dividend and divisor.
483
// So we want answers like 1/10 and 10/1 out of these routines.
484
 
485
static void construct_converter( Cyg_Clock::converter *pcc,
486
                                        cyg_uint64 m1, cyg_uint64 d1,
487
                                        cyg_uint64 m2, cyg_uint64 d2 )
488
{
489
    cyg_uint64 upper, lower;
490
    unsigned int i;
491
    static cyg_uint16 primes[] = {
492
        3,5,7,11,13,17,19,23,29,31,37,41,43,47,
493
        53,59,61,67,71,73,79,83,89,97,
494
        101,103,107,109,113,127,131,137,139,149,
495
        151,157,163,167,173,179,181,191,193,197,199,
496
        239,                            // for 1,111,111
497
        541,                            // for 10,101,011
498
        1667,                           // for 8,333,333
499
    };
500
 
501
    int rounding = 0;
502
 
503
    // Here we assume that our workings will fit in a 64; the point is to
504
    // allow calculations with a number of ticks that may be large.
505
    upper = m1 * m2;
506
    lower = d1 * d2;
507
#ifdef CYGDBG_USE_ASSERTS
508
    cyg_uint64 save_upper = upper;
509
    cyg_uint64 save_lower = lower;
510
#endif
511
 
512
 retry_rounding:
513
    // First strip out common powers of 2
514
    while ( (0 == (1 & upper)) && ( 0 == (1 & lower)) ) {
515
        upper >>= 1;
516
        lower >>= 1;
517
    }
518
 
519
    // then common factors - use lazy table above
520
    for ( i = 0 ; i < (sizeof( primes )/sizeof( primes[0] )); i++ ) {
521
        cyg_uint64 j, k, p = (cyg_uint64)(primes[i]);
522
        j = upper / p;
523
        while ( j * p == upper ) {
524
            k = lower / p;
525
            if ( k * p != lower )
526
                break;
527
            upper = j;
528
            lower = k;
529
            j = upper / p;
530
        }
531
    }
532
 
533
    m1 = upper;
534
    d1 = lower;
535
    m2 = 1;
536
    d2 = 1;
537
 
538
    if ( m1 > 0x10000 ) {
539
        // only bother if there are more than 16 bits consumed here
540
 
541
        // now move powers of 2 from d1 to d2
542
        // keeping them the same order of magnitude
543
        while ( (0 == (1 & d1)) && (d2 < d1) ) {
544
            d1 >>= 1;
545
            d2 <<= 1;
546
        }
547
 
548
        // and factors from the table - go too far, if anything
549
        int cont = (d2 < d1);
550
        for ( i = 0 ; cont && (i < (sizeof( primes )/sizeof( primes[0] ))); i++ ) {
551
            cyg_uint64 k, p = (cyg_uint64)(primes[i]);
552
            k = d1 / p;
553
            while ( cont && ((k * p) == d1) ) {
554
                // we can extract a prime
555
                d1 = k;
556
                d2 *= p;
557
                k = d1 / p;
558
                cont = (d2 < d1);
559
            }
560
        }
561
 
562
        // move powers of 2 from m1 to m2 so long as we do not go less than d1
563
        while ( (0 == (1 & m1)) && (m2 < m1) && (m1 > (d1 << 5)) ) {
564
            m1 >>= 1;
565
            m2 <<= 1;
566
            if ( m1 < 0x10000 )
567
                break;
568
        }
569
 
570
        // and factors from the table - ensure m1 stays well larger than d1
571
        cont = ((m2 < m1) && (m1 > (d1 << 4)) && (m1 > 0x10000));
572
        for ( i = 0 ; cont && (i < (sizeof( primes )/sizeof( primes[0] ))); i++ ) {
573
            cyg_uint64 k, p = (cyg_uint64)(primes[i]);
574
            k = m1 / p;
575
            cont = cont && (k > (d1 << 4) && (k > 0x10000));
576
            while ( cont && ((k * p) == m1) ) {
577
                // we can extract a prime
578
                m1 = k;
579
                m2 *= p;
580
                k = m1 / p; // examine k for getting too small
581
                cont = ((m2 < m1) && (k > (d1 << 4)) && (k > 0x10000));
582
            }
583
        }
584
 
585
        // if, after all that, m1 odd and unchanged, and too large,
586
        // decrement it just the once and try again: then try it
587
        // incremented once.
588
        if ( (m1 & 1) && (m1 == upper) && (m1 > 0x10000) && (rounding < 2) ) {
589
            CYG_ASSERT( 1 == m2, "m2 should be 1 to try rounding" );
590
            m1--;
591
            upper = m1;
592
            rounding++;
593
            goto retry_rounding;
594
        }
595
        // likewise for d1 - each of the pair can be odd only once each
596
        if ( (d1 & 1) && (d1 == lower) && (d1 > 0x10000) && (rounding < 2) ) {
597
            CYG_ASSERT( 1 == d2, "d2 should be 1 to try rounding" );
598
            d1--;
599
            lower = d1;
600
            rounding++;
601
            goto retry_rounding;
602
        }
603
    }
604
 
605
    CYG_ASSERT( 0 != m1, "m1 zero" );
606
    CYG_ASSERT( 0 != m2, "m2 zero" );
607
    CYG_ASSERT( 0 != d1, "d1 zero" );
608
    CYG_ASSERT( 0 != d2, "d2 zero" );
609
    CYG_ASSERT( rounding || save_upper/save_lower == (m1 * m2)/(d1 * d2),
610
                "Unequal in forwards direction" );
611
    CYG_ASSERT( rounding || save_lower/save_upper == (d1 * d2)/(m1 * m2),
612
                "Unequal in reverse direction" );
613
 
614
    pcc->mul1 = m1;
615
    pcc->div1 = d1;
616
    pcc->mul2 = m2;
617
    pcc->div2 = d2;
618
}
619
 
620
// other to clocks is (other * ns_per * dividend / divisor)
621
void Cyg_Clock::get_other_to_clock_converter(
622
    cyg_uint64 ns_per_other_tick,
623
    struct converter *pcc )
624
{
625
    construct_converter( pcc,
626
                         ns_per_other_tick, 1,
627
                         resolution.divisor, resolution.dividend );
628
}
629
 
630
// clocks to other is (ticks * divisor / dividend / ns_per)
631
void Cyg_Clock::get_clock_to_other_converter(
632
    cyg_uint64 ns_per_other_tick,
633
    struct converter *pcc )
634
{
635
    construct_converter( pcc,
636
                         1, ns_per_other_tick,
637
                         resolution.dividend, resolution.divisor );
638
}
639
 
640
 
641
//==========================================================================
642
// Constructor for alarm object
643
 
644
Cyg_Alarm::Cyg_Alarm(
645
        Cyg_Counter     *c,             // Attached to this counter
646
        cyg_alarm_fn    *a,             // Call-back function
647
        CYG_ADDRWORD    d               // Call-back data
648
        )
649
{
650
    CYG_REPORT_FUNCTION();
651
 
652
    counter     = c;
653
    alarm       = a;
654
    data        = d;
655
    trigger     = 0;
656
    interval    = 0;
657
    enabled     = false;
658
 
659
}
660
 
661
Cyg_Alarm::Cyg_Alarm(){}
662
 
663
// -------------------------------------------------------------------------
664
// Destructor
665
 
666
Cyg_Alarm::~Cyg_Alarm()
667
{
668
    CYG_REPORT_FUNCTION();
669
 
670
    disable();
671
}
672
 
673
// -------------------------------------------------------------------------
674
// 
675
 
676
#ifdef CYGDBG_USE_ASSERTS
677
 
678
cyg_bool Cyg_Alarm::check_this( cyg_assert_class_zeal zeal) const
679
{
680
    // check that we have a non-NULL pointer first
681
    if( this == NULL ) return false;
682
 
683
    switch( zeal )
684
    {
685
    case cyg_system_test:
686
    case cyg_extreme:
687
    case cyg_thorough:
688
        if( trigger != 0 && !enabled ) return false;
689
    case cyg_quick:
690
    case cyg_trivial:
691
    case cyg_none:
692
    default:
693
        break;
694
    };
695
 
696
    return true;
697
}
698
 
699
#endif
700
 
701
// -------------------------------------------------------------------------
702
// Initialize Alarm and enable
703
 
704
void Cyg_Alarm::initialize(
705
    cyg_tick_count    t,                // Absolute trigger time
706
    cyg_tick_count    i                 // Relative retrigger interval
707
    )
708
{
709
    CYG_REPORT_FUNCTION();
710
 
711
    // If already enabled, remove from counter
712
 
713
    if( enabled ) counter->rem_alarm(this);
714
 
715
    CYG_INSTRUMENT_ALARM( INIT,     this, 0 );
716
    CYG_INSTRUMENT_ALARM( TRIGGER,
717
                          ((cyg_uint32 *)&t)[0],
718
                          ((cyg_uint32 *)&t)[1] );
719
    CYG_INSTRUMENT_ALARM( INTERVAL,
720
                          ((cyg_uint32 *)&i)[0],
721
                          ((cyg_uint32 *)&i)[1] );
722
 
723
    trigger = t;
724
    interval = i;
725
 
726
    counter->add_alarm(this);
727
}
728
 
729
// -------------------------------------------------------------------------
730
// Synchronize with a past alarm stream that had been disabled,
731
// bring past times into synch, and the like.
732
 
733
void
734
Cyg_Alarm::synchronize( void )
735
{
736
    if( interval != 0 ) {
737
        // This expression sets the trigger to the next whole interval
738
        // at or after the current time. This means that alarms will
739
        // continue at the same intervals as if they had never been
740
        // disabled. The alternative would be to just set trigger to
741
        // (counter->counter + interval), but this is less satisfying
742
        // than preserving the original intervals. That behaviour can
743
        // always be obtained by using initialize() rather than
744
        // enable(), while the current behaviour would be more
745
        // difficult to achieve that way.
746
        cyg_tick_count d;
747
        d = counter->current_value() + interval - trigger;
748
        if ( d > interval ) {
749
            // then trigger was in the past, so resynchronize
750
            trigger += interval * ((d - 1) / interval );
751
        }
752
        // otherwise, we were just set up, so no worries.
753
    }
754
}
755
 
756
// -------------------------------------------------------------------------
757
// Ensure alarm enabled
758
 
759
void Cyg_Alarm::enable()
760
{
761
    if( !enabled )
762
    {
763
        // ensure the alarm time is in our future:
764
        synchronize();
765
        enabled = true;
766
        counter->add_alarm(this);
767
    }
768
}
769
 
770
// -------------------------------------------------------------------------
771
// Get the current time values from the alarm
772
 
773
void Cyg_Alarm::get_times(
774
        cyg_tick_count  *t,      // Next trigger time
775
        cyg_tick_count  *i       // Current interval
776
        )
777
{
778
    // Lock the scheduler while we do this to avoid
779
    // race conditions.
780
    Cyg_Scheduler::lock();
781
 
782
    if( t != NULL ) *t = trigger;
783
    if( i != NULL ) *i = interval;
784
 
785
    Cyg_Scheduler::unlock();
786
}
787
 
788
//==========================================================================
789
// System clock object
790
 
791
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
792
 
793
class Cyg_RealTimeClock
794
    : public Cyg_Clock
795
{
796
    Cyg_Interrupt       interrupt;
797
 
798
    static cyg_uint32 isr(cyg_vector vector, CYG_ADDRWORD data);
799
 
800
    static void dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data);
801
 
802
    Cyg_RealTimeClock();
803
 
804
    static Cyg_RealTimeClock rtc;
805
};
806
 
807
Cyg_Clock::cyg_resolution rtc_resolution = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
808
 
809
//Cyg_RealTimeClock Cyg_RealTimeClock::rtc __attribute__((init_priority (1)));
810
 
811
Cyg_RealTimeClock Cyg_RealTimeClock::rtc CYG_INIT_PRIORITY( CLOCK );
812
 
813
// -------------------------------------------------------------------------
814
 
815
Cyg_RealTimeClock::Cyg_RealTimeClock()
816
    : Cyg_Clock(rtc_resolution),
817
      interrupt(CYGNUM_HAL_INTERRUPT_RTC, 1, (CYG_ADDRWORD)this, isr, dsr)
818
{
819
    CYG_REPORT_FUNCTION();
820
 
821
    HAL_CLOCK_INITIALIZE( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD );
822
 
823
    interrupt.attach();
824
 
825
    interrupt.unmask_interrupt(CYGNUM_HAL_INTERRUPT_RTC);
826
 
827
    Cyg_Clock::real_time_clock = this;
828
}
829
 
830
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
831
cyg_tick_count total_clock_latency, total_clock_interrupts;
832
cyg_int32 min_clock_latency = 0x7FFFFFFF;
833
cyg_int32 max_clock_latency = 0;
834
bool measure_clock_latency = false;
835
#endif
836
 
837
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
838
cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls;
839
cyg_int32 min_clock_dsr_latency = 0x7FFFFFFF;
840
cyg_int32 max_clock_dsr_latency = 0;
841
cyg_uint32 clock_dsr_start = 0;
842
#endif
843
 
844
// -------------------------------------------------------------------------
845
 
846
cyg_uint32 Cyg_RealTimeClock::isr(cyg_vector vector, CYG_ADDRWORD data)
847
{
848
//    CYG_REPORT_FUNCTION();
849
 
850
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
851
    if (measure_clock_latency) {
852
        cyg_int32 delta;
853
        HAL_CLOCK_LATENCY(&delta);
854
        // Note: Ignore a latency of 0 when finding min_clock_latency.
855
        if (delta > 0) {
856
            // Valid delta measured
857
            total_clock_latency += delta;
858
            total_clock_interrupts++;
859
            if (min_clock_latency > delta) min_clock_latency = delta;
860
            if (max_clock_latency < delta) max_clock_latency = delta;
861
        }
862
    }
863
#endif
864
 
865
    CYG_INSTRUMENT_CLOCK( ISR, 0, 0);
866
 
867
    HAL_CLOCK_RESET( CYGNUM_HAL_INTERRUPT_RTC, CYGNUM_KERNEL_COUNTERS_RTC_PERIOD );
868
 
869
    Cyg_Interrupt::acknowledge_interrupt(CYGNUM_HAL_INTERRUPT_RTC);
870
 
871
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
872
    HAL_CLOCK_READ(&clock_dsr_start);
873
#endif    
874
    return Cyg_Interrupt::CALL_DSR|Cyg_Interrupt::HANDLED;
875
}
876
 
877
// -------------------------------------------------------------------------
878
 
879
void Cyg_RealTimeClock::dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data)
880
{
881
//    CYG_REPORT_FUNCTION();
882
 
883
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY)
884
    if (measure_clock_latency) {
885
        cyg_int32 delta;
886
        HAL_CLOCK_READ((cyg_uint32 *)&delta);
887
        delta -= clock_dsr_start;
888
        // Note: Ignore a latency of <= 0 when finding min_clock_latency.
889
        if (delta > 0 ) {
890
            // Valid delta measured
891
            total_clock_dsr_latency += delta;
892
            total_clock_dsr_calls++;
893
            if (min_clock_dsr_latency > delta) min_clock_dsr_latency = delta;
894
            if (max_clock_dsr_latency < delta) max_clock_dsr_latency = delta;
895
        }
896
    }
897
#endif    
898
 
899
    Cyg_RealTimeClock *rtc = (Cyg_RealTimeClock *)data;
900
 
901
    CYG_INSTRUMENT_CLOCK( TICK_START,
902
                          rtc->current_value_lo(),
903
                          rtc->current_value_hi());
904
 
905
    rtc->tick( count );
906
 
907
#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
908
#if    0 == CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES
909
 
910
    // If timeslicing is enabled, call the scheduler to
911
    // handle it. But not if we have unique priorities.
912
 
913
    Cyg_Scheduler::scheduler.timeslice();
914
 
915
#endif
916
#endif
917
 
918
    CYG_INSTRUMENT_CLOCK( TICK_END,
919
                          rtc->current_value_lo(),
920
                          rtc->current_value_hi());
921
 
922
}
923
 
924
#endif
925
 
926
// -------------------------------------------------------------------------
927
// EOF common/clock.cxx

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.