source: rtems/c/src/lib/libcpu/hppa1.1/clock/clock.c @ ac7d5ef0

4.104.114.84.95
Last change on this file since ac7d5ef0 was ac7d5ef0, checked in by Joel Sherrill <joel.sherrill@…>, on May 11, 1995 at 5:39:37 PM

Initial revision

  • Property mode set to 100644
File size: 5.4 KB
Line 
1/*  Clock
2 *
3 *  This routine initializes the interval timer on the
4 *  PA-RISC CPU.  The tick frequency is specified by the bsp.
5 *
6 *  COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
7 *  On-Line Applications Research Corporation (OAR).
8 *  All rights assigned to U.S. Government, 1994.
9 *
10 *  This material may be reproduced by or for the U.S. Government pursuant
11 *  to the copyright license under the clause at DFARS 252.227-7013.  This
12 *  notice must appear in all copies of this file and its derivatives.
13 *
14 *  $Id$
15 */
16
17#include <bsp.h>
18#include <clockdrv.h>
19
20#include <stdlib.h>                     /* for atexit() */
21
22extern rtems_cpu_table           Cpu_table;             /* owned by BSP */
23
24typedef unsigned long long hppa_click_count_t;
25
26/*
27 * CPU_HPPA_CLICKS_PER_TICK is either a #define or an rtems_unsigned32
28 *   allocated and set by bsp_start()
29 */
30
31#ifndef CPU_HPPA_CLICKS_PER_TICK
32extern rtems_unsigned32 CPU_HPPA_CLICKS_PER_TICK;
33#endif
34
35volatile rtems_unsigned32 Clock_driver_ticks;
36rtems_unsigned32 Clock_isrs;              /* ISRs until next tick */
37
38rtems_unsigned32   most_recent_itimer_value;
39
40rtems_unsigned64   Clock_clicks;        /* running total of cycles */
41
42rtems_unsigned32   Clock_clicks_interrupt;
43
44rtems_device_driver Clock_initialize(
45  rtems_device_major_number major,
46  rtems_device_minor_number minor,
47  void *pargp,
48  rtems_id tid,
49  rtems_unsigned32 *rval
50)
51{
52    Install_clock(Clock_isr);
53}
54
55void
56ReInstall_clock(rtems_isr_entry new_clock_isr)
57{
58    rtems_unsigned32 isrlevel = 0;
59
60    rtems_interrupt_disable(isrlevel);
61    (void) set_vector(
62      new_clock_isr,
63      HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER,
64      1
65    );
66    rtems_interrupt_enable(isrlevel);
67}
68
69/*
70 * read itimer and update Clock_clicks as appropriate
71 */
72
73rtems_unsigned32
74Clock_read_itimer()
75{
76    rtems_unsigned32 isrlevel;
77    rtems_unsigned32 itimer_value;
78    rtems_unsigned32 wrap_count;
79    rtems_unsigned32 recent_count;
80
81    rtems_interrupt_disable(isrlevel);
82
83    wrap_count = (Clock_clicks & 0xFFFFFFFF00000000ULL) >> 32;
84    recent_count = (rtems_unsigned32) Clock_clicks;
85
86    itimer_value = get_itimer();
87
88    if (itimer_value < recent_count)
89        wrap_count++;
90    Clock_clicks = (((rtems_unsigned64) wrap_count) << 32) + itimer_value;
91
92    rtems_interrupt_enable(isrlevel);
93
94    return itimer_value;
95}
96
97
98void Install_clock(rtems_isr_entry clock_isr)
99{
100    Clock_driver_ticks = 0;
101    Clock_clicks_interrupt = 0;
102    Clock_clicks = 0;
103
104    Clock_isrs = BSP_Configuration.microseconds_per_tick / 1000;
105
106    if (BSP_Configuration.ticks_per_timeslice)
107    {
108        /*
109         * initialize the interval here
110         * First tick is set to right amount of time in the future
111         * Future ticks will be incremented over last value set
112         * in order to provide consistent clicks in the face of
113         * interrupt overhead
114         */
115
116        Clock_clicks_interrupt = Clock_read_itimer() + CPU_HPPA_CLICKS_PER_TICK;
117        set_itimer((rtems_unsigned32) Clock_clicks_interrupt);
118
119        (void) set_vector(clock_isr, HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, 1);
120    }
121    atexit(Clock_exit);
122}
123
124rtems_isr
125Clock_isr(rtems_vector_number vector)
126{
127    rtems_unsigned32 clicks_til_next_interrupt;
128    rtems_unsigned32 itimer_value;
129
130    /*
131     * setup for next interrupt; making sure the new value is reasonably
132     * in the future.... in case we lost out on an interrupt somehow
133     */
134
135    itimer_value = Clock_read_itimer();
136    Clock_clicks_interrupt += CPU_HPPA_CLICKS_PER_TICK;
137
138    /*
139     * how far away is next interrupt *really*
140     * It may be a long time; this subtraction works even if
141     * Clock_clicks_interrupt < Clock_clicks_low_order via
142     * the miracle of unsigned math.
143     */
144    clicks_til_next_interrupt = Clock_clicks_interrupt - itimer_value;
145
146    /*
147     * If it is too soon then bump it up.
148     * This should only happen if CPU_HPPA_CLICKS_PER_TICK is too small.
149     * But setting it low is useful for debug, so...
150     */
151
152    if (clicks_til_next_interrupt < 400)
153    {
154        Clock_clicks_interrupt = itimer_value + 1000;
155        /* XXX: count these! this should be rare */
156    }
157
158    /*
159     * If it is too late, that means we missed the interrupt somehow.
160     * Rather than wait 35-50s for a wrap, we just fudge it here.
161     */
162
163    if (clicks_til_next_interrupt > CPU_HPPA_CLICKS_PER_TICK)
164    {
165        Clock_clicks_interrupt = itimer_value + 1000;
166        /* XXX: count these! this should never happen :-) */
167    }
168
169    set_itimer((rtems_unsigned32) Clock_clicks_interrupt);
170
171    Clock_driver_ticks++;
172
173    if (Clock_isrs == 1)
174    {
175        rtems_clock_tick();
176        Clock_isrs = BSP_Configuration.microseconds_per_tick / 10000;
177        if (Clock_isrs == 0)
178            Clock_isrs = 1;
179    }
180    else
181        Clock_isrs--;
182}
183
184/*
185 * Called via atexit()
186 * Remove the clock interrupt handler by setting handler to NULL
187 */
188
189void
190Clock_exit(void)
191{
192    if ( BSP_Configuration.ticks_per_timeslice )
193    {
194        (void) set_vector(0, HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, 1);
195    }
196}
197
198/*
199 * spin delay for specified number of microseconds
200 * used by RTEMS delay macro
201 */
202
203void
204Clock_delay(rtems_unsigned32 microseconds)
205{
206    rtems_unsigned64 future_time;
207
208    (void) Clock_read_itimer();
209    future_time = Clock_clicks +
210      ((rtems_unsigned64) microseconds) *
211        Cpu_table.itimer_clicks_per_microsecond;
212
213    for (;;)
214    {
215        (void) Clock_read_itimer();
216        if (future_time <= Clock_clicks)
217            break;
218    }
219}
220
Note: See TracBrowser for help on using the repository browser.