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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [kernel/] [current/] [src/] [common/] [clock.cxx] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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