source: rtems/c/src/lib/libbsp/i386/pc386/timer/timer.c @ 0ebbf66

4.104.114.84.95
Last change on this file since 0ebbf66 was 0ebbf66, checked in by Joel Sherrill <joel.sherrill@…>, on 10/05/98 at 22:36:06

Large patch from Erik Ivanenko <erik.ivanenko@…> which
moves pieces of the pc386 bsp up to a shared level for all i386 BSPs
and modifies the i386ex BSP to use those shared pieces. Serial remote
debugging is included for both targets. Erik's notes:

There are several workarounds in it:

1) #define NEXT_GAS is hardcoded in pc386/start/start.s
2) #define NEXT_GAS is hardcoded in i386ex/start/start.s
3) #define NEW_GAS is hardcoded in pc386/start16.s
4) #undef assert and redeclare _assert hardcoded in console.c for

both pc386 and i386ex due to my egcs1.1b ~ newlib problem. Should have
modified t-rtems.cfg ( no time )

I've tested pc386 with both video and serial consoles and GDB remote.
All work fine, except that GDB acts weird. ( re: other posting)

I hope this will work for you. It took quite some time to locate the
autoconf error. The remainder was just grunt work.
Unfortunately, I think I've unwound the removal of the IBMPCInitVideo
stuff. Sorry. I REALLY can't spend more time... I've been at this
conversion to 4.0 locally and updating the release since Sept. 8th, and
have yet to compile my network driver.... This is as much as I can do
right now.

I look forward to the next patch to really test i368ex. I did make sure
that the sample tests worked for pc386.

  • Property mode set to 100644
File size: 12.9 KB
Line 
1/*-------------------------------------------------------------------------+
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| With the following copyright notice:
24| **************************************************************************
25| *  COPYRIGHT (c) 1989-1998.
26| *  On-Line Applications Research Corporation (OAR).
27| *  Copyright assigned to U.S. Government, 1994.
28| *
29| *  The license and distribution terms for this file may be
30| *  found in found in the file LICENSE in this distribution or at
31| *  http://www.OARcorp.com/rtems/license.html.
32| **************************************************************************
33|
34|  $Id$
35+--------------------------------------------------------------------------*/
36
37
38#include <stdlib.h>
39
40#include <bsp.h>
41#include <irq.h>
42
43/*-------------------------------------------------------------------------+
44| Constants
45+--------------------------------------------------------------------------*/
46#define AVG_OVERHEAD  0              /* 0.1 microseconds to start/stop timer. */
47#define LEAST_VALID   1              /* Don't trust a value lower than this.  */
48#define SLOW_DOWN_IO  0x80      /* io which does nothing */
49
50#define TWO_MS  (rtems_unsigned32)(2000)     /* TWO_MS = 2000us (sic!) */
51
52#define MSK_NULL_COUNT 0x40     /* bit counter available for reading */
53
54#define CMD_READ_BACK_STATUS 0xE2   /* command read back status */
55/*-------------------------------------------------------------------------+
56| Global Variables
57+--------------------------------------------------------------------------*/
58volatile rtems_unsigned32 Ttimer_val;
59         rtems_boolean    Timer_driver_Find_average_overhead = TRUE;
60         unsigned int     loop1ms;
61
62/*-------------------------------------------------------------------------+
63| External Prototypes
64+--------------------------------------------------------------------------*/
65extern void timerisr(void);
66       /* timer (int 08h) Interrupt Service Routine (defined in 'timerisr.s') */
67
68/*-------------------------------------------------------------------------+
69| Pentium optimized timer handling.
70+--------------------------------------------------------------------------*/
71#if defined(pentium)
72
73/*-------------------------------------------------------------------------+
74|         Function: rdtsc
75|      Description: Read the value of PENTIUM on-chip cycle counter.
76| Global Variables: None.
77|        Arguments: None.
78|          Returns: Value of PENTIUM on-chip cycle counter.
79+--------------------------------------------------------------------------*/
80static inline unsigned long long
81rdtsc(void)
82{
83  /* Return the value of the on-chip cycle counter. */
84  unsigned long long result;
85  asm volatile(".byte 0x0F, 0x31" : "=A" (result));
86  return result;
87} /* rdtsc */
88
89
90/*-------------------------------------------------------------------------+
91|         Function: Timer_exit
92|      Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
93|                   not really necessary, since there will be a reset at exit.
94| Global Variables: None.
95|        Arguments: None.
96|          Returns: Nothing.
97+--------------------------------------------------------------------------*/
98void
99Timer_exit(void)
100{
101} /* Timer_exit */
102
103
104/*-------------------------------------------------------------------------+
105|         Function: Timer_initialize
106|      Description: Timer initialization routine.
107| Global Variables: Ttimer_val.
108|        Arguments: None.
109|          Returns: Nothing.
110+--------------------------------------------------------------------------*/
111void
112Timer_initialize(void)
113{
114  static rtems_boolean First = TRUE;
115
116  if (First)
117  {
118    First = FALSE;
119
120    atexit(Timer_exit); /* Try not to hose the system at exit. */
121  }
122  Ttimer_val = rdtsc(); /* read starting time */
123} /* Timer_initialize */
124
125
126/*-------------------------------------------------------------------------+
127|         Function: Read_timer
128|      Description: Read hardware timer value.
129| Global Variables: Ttimer_val, Timer_driver_Find_average_overhead.
130|        Arguments: None.
131|          Returns: Nothing.
132+--------------------------------------------------------------------------*/
133rtems_unsigned32
134Read_timer(void)
135{
136  register rtems_unsigned32 total;
137
138  total =  (rtems_unsigned32)(rdtsc() - Ttimer_val);
139
140  if (Timer_driver_Find_average_overhead)
141    return total;
142  else if (total < LEAST_VALID)
143    return 0; /* below timer resolution */
144  else
145    return (total - AVG_OVERHEAD);
146} /* Read_timer */
147
148#else /* pentium */
149
150/*-------------------------------------------------------------------------+
151| Non-Pentium timer handling.
152+--------------------------------------------------------------------------*/
153#define US_PER_ISR   250  /* Number of micro-seconds per timer interruption */
154
155
156/*-------------------------------------------------------------------------+
157|         Function: Timer_exit
158|      Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
159|                   not really necessary, since there will be a reset at exit.
160| Global Variables: None.
161|        Arguments: None.
162|          Returns: Nothing.
163+--------------------------------------------------------------------------*/
164static void
165timerOff(const rtems_raw_irq_connect_data* used)
166{
167    /*
168     * disable interrrupt at i8259 level
169     */
170     BSP_irq_disable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);
171     /* reset timer mode to standard (DOS) value */
172     outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
173     outport_byte(TIMER_CNTR0, 0);
174     outport_byte(TIMER_CNTR0, 0);
175} /* Timer_exit */
176
177
178static void
179timerOn(const rtems_raw_irq_connect_data* used)
180{
181     /* load timer for US_PER_ISR microsecond period */
182     outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
183     outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff);
184     outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff);
185    /*
186     * enable interrrupt at i8259 level
187     */
188     BSP_irq_enable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);
189}
190
191static int
192timerIsOn(const rtems_raw_irq_connect_data *used)
193{
194     return BSP_irq_enabled_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);}
195
196static rtems_raw_irq_connect_data timer_raw_irq_data = {
197  BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE,
198  timerisr,
199  timerOn,
200  timerOff,
201  timerIsOn
202};
203
204/*-------------------------------------------------------------------------+
205|         Function: Timer_exit
206|      Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
207|                   not really necessary, since there will be a reset at exit.
208| Global Variables: None.
209|        Arguments: None.
210|          Returns: Nothing.
211+--------------------------------------------------------------------------*/
212void
213Timer_exit(void)
214{
215  i386_delete_idt_entry (&timer_raw_irq_data);
216} /* Timer_exit */
217
218/*-------------------------------------------------------------------------+
219|         Function: Timer_initialize
220|      Description: Timer initialization routine.
221| Global Variables: Ttimer_val.
222|        Arguments: None.
223|          Returns: Nothing.
224+--------------------------------------------------------------------------*/
225void
226Timer_initialize(void)
227{
228  static rtems_boolean First = TRUE;
229
230  if (First)
231  {
232    First = FALSE;
233
234    atexit(Timer_exit); /* Try not to hose the system at exit. */
235    if (!i386_set_idt_entry (&timer_raw_irq_data)) {
236      printk("raw handler connexion failed\n");
237      rtems_fatal_error_occurred(1);
238    }
239  }
240  /* wait for ISR to be called at least once */
241  Ttimer_val = 0;
242  while (Ttimer_val == 0)
243    continue;
244  Ttimer_val = 0;
245} /* Timer_initialize */
246
247
248/*-------------------------------------------------------------------------+
249|         Function: Read_timer
250|      Description: Read hardware timer value.
251| Global Variables: Ttimer_val, Timer_driver_Find_average_overhead.
252|        Arguments: None.
253|          Returns: Nothing.
254+--------------------------------------------------------------------------*/
255rtems_unsigned32
256Read_timer(void)
257{
258  register rtems_unsigned32 total, clicks;
259  register rtems_unsigned8  lsb, msb;
260
261  outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
262  inport_byte(TIMER_CNTR0, lsb);
263  inport_byte(TIMER_CNTR0, msb);
264  clicks = (msb << 8) | lsb;
265  total  = (Ttimer_val * US_PER_ISR) + (US_PER_ISR - TICK_TO_US(clicks));
266
267  if (Timer_driver_Find_average_overhead)
268    return total;
269  else if (total < LEAST_VALID)
270    return 0; /* below timer resolution */
271  else
272    return (total - AVG_OVERHEAD);
273}
274
275#endif /* pentium */
276
277
278/*-------------------------------------------------------------------------+
279|         Function: Empty_function
280|      Description: Empty function used in time tests.
281| Global Variables: None.
282|        Arguments: None.
283|          Returns: Nothing.
284+--------------------------------------------------------------------------*/
285rtems_status_code Empty_function(void)
286{
287  return RTEMS_SUCCESSFUL;
288} /* Empty function */
289 
290
291/*-------------------------------------------------------------------------+
292|         Function: Set_find_average_overhead
293|      Description: Set internal Timer_driver_Find_average_overhead flag value.
294| Global Variables: Timer_driver_Find_average_overhead.
295|        Arguments: find_flag - new value of the flag.
296|          Returns: Nothing.
297+--------------------------------------------------------------------------*/
298void
299Set_find_average_overhead(rtems_boolean find_flag)
300{
301  Timer_driver_Find_average_overhead = find_flag;
302} /* Set_find_average_overhead */
303
304/*-------------------------------------------------------------------------+
305|         Function: Calibrate_loop_1ms
306|      Description: Set loop variable to calibrate a 1ms loop
307| Global Variables: loop1ms
308|        Arguments: none
309|          Returns: Nothing.
310+--------------------------------------------------------------------------*/
311void
312Calibrate_loop_1ms(void){
313  unsigned int i;
314  unsigned short loadedValue, offset;
315  unsigned int timerValue;
316  rtems_interrupt_level  level;
317  unsigned short lsb, msb;
318  unsigned char status;
319 
320 
321  loop1ms = 100 ;
322  timerValue = 2000;
323  loadedValue = US_TO_TICK(2000);
324 
325  rtems_interrupt_disable(level);
326
327  /*
328   * Compute the offset to apply due to read counter register
329   */
330  outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
331  outport_byte(TIMER_CNTR0, loadedValue >> 0 & 0xff);
332  outport_byte(TIMER_CNTR0, loadedValue >> 8 & 0xff);
333
334  outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS); /* read Status counter 0 */
335  inport_byte(TIMER_CNTR0, status);
336  while (status & MSK_NULL_COUNT){      /* wait for counter ready */   
337    outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS);
338    inport_byte(TIMER_CNTR0, status);
339  }
340 
341  outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
342  inport_byte(TIMER_CNTR0, lsb);
343  inport_byte(TIMER_CNTR0, msb);
344  offset = loadedValue - (unsigned short)((msb << 8) | lsb);
345
346  while (timerValue > 1000){
347    loop1ms++;
348
349    /* load timer for 2ms+offset period */
350    outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
351    outport_byte(TIMER_CNTR0, (loadedValue+offset) >> 0 & 0xff);
352    outport_byte(TIMER_CNTR0, (loadedValue+offset) >> 8 & 0xff);
353
354    outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS); /* read Status counter 0 */
355    inport_byte(TIMER_CNTR0, status);
356    while (status & MSK_NULL_COUNT) {   /* wait for counter ready */
357      outport_byte(TIMER_MODE, CMD_READ_BACK_STATUS);
358      inport_byte(TIMER_CNTR0, status);
359    }
360   
361    for (i=0; i<loop1ms; i++)
362      outport_byte(SLOW_DOWN_IO, 0);    /* write is # 1us */
363
364    outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
365    inport_byte(TIMER_CNTR0, lsb);
366    inport_byte(TIMER_CNTR0, msb);
367    timerValue = TICK_TO_US((msb << 8) | lsb);
368  }
369
370  rtems_interrupt_enable(level);
371}
372
373/*-------------------------------------------------------------------------+
374|         Function: Wait_X_1ms
375|      Description: loop which waits at least timeToWait ms
376| Global Variables: loop1ms
377|        Arguments: timeToWait
378|          Returns: Nothing.
379+--------------------------------------------------------------------------*/
380void
381Wait_X_ms( unsigned int timeToWait){
382
383  unsigned int i, j;
384
385  for (j=0; j<timeToWait ; j++)
386    for (i=0; i<loop1ms; i++)
387      outport_byte(SLOW_DOWN_IO, 0);    /* write is # 1us */
388}
389
390
391
392
393
394
Note: See TracBrowser for help on using the repository browser.