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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [i386/] [pc386/] [timer/] [timer.c] - Blame information for rev 173

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*-------------------------------------------------------------------------+
2
| timer.c v1.1 - PC386 BSP - 1997/08/07
3
+--------------------------------------------------------------------------+
4
| This file contains the PC386 timer package.
5
+--------------------------------------------------------------------------+
6
| NOTE: It is important that the timer start/stop overhead be determined
7
|       when porting or modifying this code.
8
+--------------------------------------------------------------------------+
9
| (C) Copyright 1997 -
10
| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
11
|
12
| http://pandora.ist.utl.pt
13
|
14
| Instituto Superior Tecnico * Lisboa * PORTUGAL
15
+--------------------------------------------------------------------------+
16
| Disclaimer:
17
|
18
| This file is provided "AS IS" without warranty of any kind, either
19
| expressed or implied.
20
+--------------------------------------------------------------------------+
21
| This code is base on:
22
|   timer.c,v 1.7 1995/12/19 20:07:43 joel Exp - go32 BSP
23
|
24
| Rosimildo daSilva -ConnectTel, Inc - Fixed infinite loop in the Calibration
25
| routine. I've seen this problems with faster machines ( pentiums ). Sometimes
26
| RTEMS just hangs at startup.
27
|
28
| With the following copyright notice:
29
| **************************************************************************
30
| *  COPYRIGHT (c) 1989-1999.
31
| *  On-Line Applications Research Corporation (OAR).
32
| *
33
| *  The license and distribution terms for this file may be
34
| *  found in found in the file LICENSE in this distribution or at
35
| *  http://www.OARcorp.com/rtems/license.html.
36
| **************************************************************************
37
|
38
|  $Id: timer.c,v 1.2 2001-09-27 11:59:48 chris Exp $
39
+--------------------------------------------------------------------------*/
40
 
41
 
42
#include <stdlib.h>
43
 
44
#include <bsp.h>
45
#include <irq.h>
46
 
47
/*-------------------------------------------------------------------------+
48
| Constants
49
+--------------------------------------------------------------------------*/
50
#define AVG_OVERHEAD  0              /* 0.1 microseconds to start/stop timer. */
51
#define LEAST_VALID   1              /* Don't trust a value lower than this.  */
52
#define SLOW_DOWN_IO  0x80      /* io which does nothing */
53
 
54
#define TWO_MS  (rtems_unsigned32)(2000)     /* TWO_MS = 2000us (sic!) */
55
 
56
#define MSK_NULL_COUNT 0x40     /* bit counter available for reading */
57
 
58
#define CMD_READ_BACK_STATUS 0xE2   /* command read back status */
59
/*-------------------------------------------------------------------------+
60
| Global Variables
61
+--------------------------------------------------------------------------*/
62
volatile rtems_unsigned32 Ttimer_val;
63
         rtems_boolean    Timer_driver_Find_average_overhead = TRUE;
64
         unsigned int     loop1ms;
65
 
66
/*-------------------------------------------------------------------------+
67
| External Prototypes
68
+--------------------------------------------------------------------------*/
69
extern void timerisr(void);
70
       /* timer (int 08h) Interrupt Service Routine (defined in 'timerisr.s') */
71
 
72
/*-------------------------------------------------------------------------+
73
| Pentium optimized timer handling.
74
+--------------------------------------------------------------------------*/
75
#if defined(pentium)
76
 
77
/*-------------------------------------------------------------------------+
78
|         Function: rdtsc
79
|      Description: Read the value of PENTIUM on-chip cycle counter.
80
| Global Variables: None.
81
|        Arguments: None.
82
|          Returns: Value of PENTIUM on-chip cycle counter.
83
+--------------------------------------------------------------------------*/
84
static inline unsigned long long
85
rdtsc(void)
86
{
87
  /* Return the value of the on-chip cycle counter. */
88
  unsigned long long result;
89
  asm volatile(".byte 0x0F, 0x31" : "=A" (result));
90
  return result;
91
} /* rdtsc */
92
 
93
 
94
/*-------------------------------------------------------------------------+
95
|         Function: Timer_exit
96
|      Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
97
|                   not really necessary, since there will be a reset at exit.
98
| Global Variables: None.
99
|        Arguments: None.
100
|          Returns: Nothing.
101
+--------------------------------------------------------------------------*/
102
void
103
Timer_exit(void)
104
{
105
} /* Timer_exit */
106
 
107
 
108
/*-------------------------------------------------------------------------+
109
|         Function: Timer_initialize
110
|      Description: Timer initialization routine.
111
| Global Variables: Ttimer_val.
112
|        Arguments: None.
113
|          Returns: Nothing.
114
+--------------------------------------------------------------------------*/
115
void
116
Timer_initialize(void)
117
{
118
  static rtems_boolean First = TRUE;
119
 
120
  if (First)
121
  {
122
    First = FALSE;
123
 
124
    atexit(Timer_exit); /* Try not to hose the system at exit. */
125
  }
126
  Ttimer_val = rdtsc(); /* read starting time */
127
} /* Timer_initialize */
128
 
129
 
130
/*-------------------------------------------------------------------------+
131
|         Function: Read_timer
132
|      Description: Read hardware timer value.
133
| Global Variables: Ttimer_val, Timer_driver_Find_average_overhead.
134
|        Arguments: None.
135
|          Returns: Nothing.
136
+--------------------------------------------------------------------------*/
137
rtems_unsigned32
138
Read_timer(void)
139
{
140
  register rtems_unsigned32 total;
141
 
142
  total =  (rtems_unsigned32)(rdtsc() - Ttimer_val);
143
 
144
  if (Timer_driver_Find_average_overhead)
145
    return total;
146
  else if (total < LEAST_VALID)
147
    return 0; /* below timer resolution */
148
  else
149
    return (total - AVG_OVERHEAD);
150
} /* Read_timer */
151
 
152
#else /* pentium */
153
 
154
/*-------------------------------------------------------------------------+
155
| Non-Pentium timer handling.
156
+--------------------------------------------------------------------------*/
157
#define US_PER_ISR   250  /* Number of micro-seconds per timer interruption */
158
 
159
 
160
/*-------------------------------------------------------------------------+
161
|         Function: Timer_exit
162
|      Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
163
|                   not really necessary, since there will be a reset at exit.
164
| Global Variables: None.
165
|        Arguments: None.
166
|          Returns: Nothing.
167
+--------------------------------------------------------------------------*/
168
static void
169
timerOff(const rtems_raw_irq_connect_data* used)
170
{
171
    /*
172
     * disable interrrupt at i8259 level
173
     */
174
     BSP_irq_disable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);
175
     /* reset timer mode to standard (DOS) value */
176
     outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
177
     outport_byte(TIMER_CNTR0, 0);
178
     outport_byte(TIMER_CNTR0, 0);
179
} /* Timer_exit */
180
 
181
 
182
static void
183
timerOn(const rtems_raw_irq_connect_data* used)
184
{
185
     /* load timer for US_PER_ISR microsecond period */
186
     outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
187
     outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff);
188
     outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff);
189
    /*
190
     * enable interrrupt at i8259 level
191
     */
192
     BSP_irq_enable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);
193
}
194
 
195
static int
196
timerIsOn(const rtems_raw_irq_connect_data *used)
197
{
198
     return BSP_irq_enabled_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);}
199
 
200
static rtems_raw_irq_connect_data timer_raw_irq_data = {
201
  BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE,
202
  timerisr,
203
  timerOn,
204
  timerOff,
205
  timerIsOn
206
};
207
 
208
/*-------------------------------------------------------------------------+
209
|         Function: Timer_exit
210
|      Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
211
|                   not really necessary, since there will be a reset at exit.
212
| Global Variables: None.
213
|        Arguments: None.
214
|          Returns: Nothing.
215
+--------------------------------------------------------------------------*/
216
void
217
Timer_exit(void)
218
{
219
  i386_delete_idt_entry (&timer_raw_irq_data);
220
} /* Timer_exit */
221
 
222
/*-------------------------------------------------------------------------+
223
|         Function: Timer_initialize
224
|      Description: Timer initialization routine.
225
| Global Variables: Ttimer_val.
226
|        Arguments: None.
227
|          Returns: Nothing.
228
+--------------------------------------------------------------------------*/
229
void
230
Timer_initialize(void)
231
{
232
  static rtems_boolean First = TRUE;
233
 
234
  if (First)
235
  {
236
    First = FALSE;
237
 
238
    atexit(Timer_exit); /* Try not to hose the system at exit. */
239
    if (!i386_set_idt_entry (&timer_raw_irq_data)) {
240
      printk("raw handler connexion failed\n");
241
      rtems_fatal_error_occurred(1);
242
    }
243
  }
244
  /* wait for ISR to be called at least once */
245
  Ttimer_val = 0;
246
  while (Ttimer_val == 0)
247
    continue;
248
  Ttimer_val = 0;
249
} /* Timer_initialize */
250
 
251
 
252
/*-------------------------------------------------------------------------+
253
|         Function: Read_timer
254
|      Description: Read hardware timer value.
255
| Global Variables: Ttimer_val, Timer_driver_Find_average_overhead.
256
|        Arguments: None.
257
|          Returns: Nothing.
258
+--------------------------------------------------------------------------*/
259
rtems_unsigned32
260
Read_timer(void)
261
{
262
  register rtems_unsigned32 total, clicks;
263
  register rtems_unsigned8  lsb, msb;
264
 
265
  outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
266
  inport_byte(TIMER_CNTR0, lsb);
267
  inport_byte(TIMER_CNTR0, msb);
268
  clicks = (msb << 8) | lsb;
269
  total  = (Ttimer_val * US_PER_ISR) + (US_PER_ISR - TICK_TO_US(clicks));
270
 
271
  if (Timer_driver_Find_average_overhead)
272
    return total;
273
  else if (total < LEAST_VALID)
274
    return 0; /* below timer resolution */
275
  else
276
    return (total - AVG_OVERHEAD);
277
}
278
 
279
#endif /* pentium */
280
 
281
 
282
/*-------------------------------------------------------------------------+
283
|         Function: Empty_function
284
|      Description: Empty function used in time tests.
285
| Global Variables: None.
286
|        Arguments: None.
287
|          Returns: Nothing.
288
+--------------------------------------------------------------------------*/
289
rtems_status_code Empty_function(void)
290
{
291
  return RTEMS_SUCCESSFUL;
292
} /* Empty function */
293
 
294
 
295
/*-------------------------------------------------------------------------+
296
|         Function: Set_find_average_overhead
297
|      Description: Set internal Timer_driver_Find_average_overhead flag value.
298
| Global Variables: Timer_driver_Find_average_overhead.
299
|        Arguments: find_flag - new value of the flag.
300
|          Returns: Nothing.
301
+--------------------------------------------------------------------------*/
302
void
303
Set_find_average_overhead(rtems_boolean find_flag)
304
{
305
  Timer_driver_Find_average_overhead = find_flag;
306
} /* Set_find_average_overhead */
307
 
308
 
309
 
310
/*-------------------------------------------------------------------------+
311
| Description: Loads timer 0 with value passed as arguemnt.
312
| Returns: Nothing.
313
+--------------------------------------------------------------------------*/
314
inline void loadTimerValue( unsigned short loadedValue )
315
{
316
  outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
317
  outport_byte(TIMER_CNTR0, loadedValue >> 0 & 0xff);
318
  outport_byte(TIMER_CNTR0, loadedValue >> 8 & 0xff);
319
}
320
 
321
 
322
/*-------------------------------------------------------------------------+
323
| Description: Waits until the counter on timer 0 reaches 0.
324
| Returns: Nothing.
325
+--------------------------------------------------------------------------*/
326
inline void waitTimerStatus( void )
327
{
328
  unsigned char status;
329
  outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS); /* read Status counter 0 */
330
  inport_byte(TIMER_CNTR0, status);
331
  while (status & MSK_NULL_COUNT){      /* wait for counter ready */
332
    outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS);
333
    inport_byte(TIMER_CNTR0, status);
334
  }
335
}
336
 
337
 
338
/*-------------------------------------------------------------------------+
339
| Description: Reads the current value of the timer, and converts the
340
|                          number of ticks to micro-seconds.
341
| Returns: current number of microseconds since last value loaded..
342
+--------------------------------------------------------------------------*/
343
inline unsigned short readCurrentTimer()
344
{
345
  unsigned short lsb, msb;
346
  outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
347
  inport_byte(TIMER_CNTR0, lsb);
348
  inport_byte(TIMER_CNTR0, msb);
349
  return TICK_TO_US( ( msb << 8 ) | lsb );
350
}
351
 
352
 
353
/*-------------------------------------------------------------------------+
354
 * clockbits - Read low order bits of timer 0 (the TOD clock)
355
 * This works only for the 8254 chips used in ATs and 386s.
356
 *
357
 * The timer runs in mode 3 (square wave mode), counting down
358
 * by twos, twice for each cycle. So it is necessary to read back the
359
 * OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT
360
 * pin forms the most significant bit of the count. Unfortunately,
361
 * the 8253 in the PC/XT lacks a command to read the OUTPUT pin...
362
 *
363
 * The PC's clock design is soooo brain damaged...
364
 *
365
 * Rosimildo - I've got this routine from the KA9Q32 distribution and
366
 *                         have updated it for the RTEMS environment.
367
 +--------------------------------------------------------------------------*/
368
unsigned int clockbits(void)
369
{
370
        unsigned int stat,count1, count;
371
 
372
        do
373
        {
374
          outport_byte( 0x43, 0xc2 );    /* latch timer 0 count and status for reading */
375
          inport_byte( 0x40, stat );     /* get status of timer 0 */
376
          inport_byte( 0x40, count1 ); /* lsb of count */
377
          inport_byte( 0x40, count ); /* msb of count */
378
          count = count1 | ( count << 8 );
379
        } while(stat & 0x40);            /* reread if NULL COUNT bit set */
380
        stat = (stat & 0x80) << 8;       /* Shift OUTPUT to msb of 16-bit word */
381
        if(count == 0)
382
                return stat ^ 0x8000;   /* return complement of OUTPUT bit */
383
        else
384
                return count | stat;    /* Combine OUTPUT with counter */
385
}
386
 
387
 
388
/*-------------------------------------------------------------------------+
389
|         Function: Calibrate_loop_1ms
390
|      Description: Set loop variable to calibrate a 1ms loop
391
| Global Variables: loop1ms
392
|        Arguments: none
393
|          Returns: Nothing.
394
+--------------------------------------------------------------------------*/
395
void
396
Calibrate_loop_1ms(void)
397
{
398
  unsigned int i;
399
  unsigned short loadedValue, offset;
400
  unsigned int timerValue, t1_ref, t2_ref=0;
401
  rtems_interrupt_level  level;
402
 
403
 
404
  printk( "Calibrate_loop_1ms is starting,  please wait ( but not too loooong. )\n" );
405
 
406
  loop1ms = 200;
407
  timerValue = 0;
408
 
409
  /* Let's load the timer with 2ms, initially */
410
  loadedValue = US_TO_TICK( 2000 );
411
 
412
  rtems_interrupt_disable(level);
413
  /*
414
   * Compute the offset to apply due to read counter register
415
   */
416
  offset = 0;
417
  loadTimerValue( loadedValue + offset );
418
  waitTimerStatus();
419
  t1_ref = clockbits();
420
  offset = loadedValue - readCurrentTimer();
421
  while( timerValue < 1000 )
422
  {
423
    loop1ms++;
424
    loadTimerValue( loadedValue + offset );
425
    waitTimerStatus();
426
    t1_ref = clockbits();
427
    for( i=0; i < loop1ms; i++ )
428
       outport_byte( SLOW_DOWN_IO, 0 );  /* write is # 1us */
429
    t2_ref = clockbits();
430
    timerValue = TICK_TO_US( t1_ref - t2_ref );  /* timer0 is decrementing number of ticks  */
431
  }
432
  printk( "Calibrate_loop_1ms timerValue=%d, loop1ms=%d, t1_ref=%x, clockbits=%x, delta=%d\n",
433
                   timerValue, loop1ms, t1_ref, t2_ref, t1_ref - t2_ref );
434
  rtems_interrupt_enable(level);
435
}
436
 
437
 
438
 
439
/*-------------------------------------------------------------------------+
440
|         Function: Wait_X_1ms
441
|      Description: loop which waits at least timeToWait ms
442
| Global Variables: loop1ms
443
|        Arguments: timeToWait
444
|          Returns: Nothing.
445
+--------------------------------------------------------------------------*/
446
void
447
Wait_X_ms( unsigned int timeToWait){
448
 
449
  unsigned int i, j;
450
 
451
  for (j=0; j<timeToWait ; j++)
452
    for (i=0; i<loop1ms; i++)
453
      outport_byte(SLOW_DOWN_IO, 0);     /* write is # 1us */
454
}
455
 
456
 
457
 
458
 
459
 
460
 

powered by: WebSVN 2.1.0

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