source: rtems/cpukit/score/cpu/sparc/cpu.c @ 9700578

4.104.114.84.95
Last change on this file since 9700578 was 9700578, checked in by Joel Sherrill <joel.sherrill@…>, on 10/30/95 at 21:54:45

SPARC port passes all tests

  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 *  SPARC Dependent Source
3 *
4 *  $Id$
5 */
6
7#include <rtems/system.h>
8#include <rtems/score/isr.h>
9
10#if defined(erc32)
11#include <erc32.h>
12#endif
13
14/*
15 *  This initializes the set of opcodes placed in each trap
16 *  table entry.  The routine which installs a handler is responsible
17 *  for filling in the fields for the _handler address and the _vector
18 *  trap type.
19 *
20 *  The constants following this structure are masks for the fields which
21 *  must be filled in when the handler is installed.
22 */
23
24const CPU_Trap_table_entry _CPU_Trap_slot_template = {
25  0xa1480000,      /* mov   %psr, %l0           */
26  0x29000000,      /* sethi %hi(_handler), %l4  */
27  0x81c52000,      /* jmp   %l4 + %lo(_handler) */
28  0xa6102000       /* mov   _vector, %l3        */
29};
30
31/*PAGE
32 *
33 *  _CPU_Initialize
34 *
35 *  This routine performs processor dependent initialization.
36 *
37 *  Input Parameters:
38 *    cpu_table       - CPU table to initialize
39 *    thread_dispatch - address of disptaching routine
40 *
41 *  Output Parameters: NONE
42 *
43 *  NOTE: There is no need to save the pointer to the thread dispatch routine.
44 *        The SPARC's assembly code can reference it directly with no problems.
45 */
46
47void _CPU_Initialize(
48  rtems_cpu_table  *cpu_table,
49  void            (*thread_dispatch)      /* ignored on this CPU */
50)
51{
52  void                  *pointer;
53  unsigned32             trap_table_start;
54  unsigned32             tbr_value;
55  CPU_Trap_table_entry  *old_tbr;
56  CPU_Trap_table_entry  *trap_table;
57
58  /*
59   *  Install the executive's trap table.  All entries from the original
60   *  trap table are copied into the executive's trap table.  This is essential
61   *  since this preserves critical trap handlers such as the window underflow
62   *  and overflow handlers.  It is the responsibility of the BSP to provide
63   *  install these in the initial trap table.
64   */
65 
66  trap_table_start = (unsigned32) &_CPU_Trap_Table_area;
67  if (trap_table_start & (SPARC_TRAP_TABLE_ALIGNMENT-1))
68    trap_table_start = (trap_table_start + SPARC_TRAP_TABLE_ALIGNMENT) &
69                       ~(SPARC_TRAP_TABLE_ALIGNMENT-1);
70
71  trap_table = (CPU_Trap_table_entry *) trap_table_start;
72
73  sparc_get_tbr( tbr_value );
74
75  old_tbr = (CPU_Trap_table_entry *) (tbr_value & 0xfffff000);
76
77  memcpy( trap_table, (void *) old_tbr, 256 * sizeof( CPU_Trap_table_entry ) );
78
79  sparc_set_tbr( trap_table_start );
80
81  /*
82   *  This seems to be the most appropriate way to obtain an initial
83   *  FP context on the SPARC.  The NULL fp context is copied it to
84   *  the task's FP context during Context_Initialize.
85   */
86
87  pointer = &_CPU_Null_fp_context;
88  _CPU_Context_save_fp( &pointer );
89
90  /*
91   *  Grab our own copy of the user's CPU table.
92   */
93
94  _CPU_Table = *cpu_table;
95
96#if defined(erc32)
97
98  /*
99   *  ERC32 specific initialization
100   */
101
102  _ERC32_MEC_Timer_Control_Mirror = 0;
103  ERC32_MEC.Timer_Control = 0;
104
105  ERC32_MEC.Control |= ERC32_CONFIGURATION_POWER_DOWN_ALLOWED;
106
107#endif
108
109}
110
111/*PAGE
112 *
113 *  _CPU_ISR_Get_level
114 *
115 *  Input Parameters: NONE
116 *
117 *  Output Parameters:
118 *    returns the current interrupt level (PIL field of the PSR)
119 */
120 
121unsigned32 _CPU_ISR_Get_level( void )
122{
123  unsigned32 level;
124 
125  sparc_get_interrupt_level( level );
126 
127  return level;
128}
129
130/*PAGE
131 *
132 *  _CPU_ISR_install_raw_handler
133 *
134 *  This routine installs the specified handler as a "raw" non-executive
135 *  supported trap handler (a.k.a. interrupt service routine).
136 *
137 *  Input Parameters:
138 *    vector      - trap table entry number plus synchronous
139 *                    vs. asynchronous information
140 *    new_handler - address of the handler to be installed
141 *    old_handler - pointer to an address of the handler previously installed
142 *
143 *  Output Parameters: NONE
144 *    *new_handler - address of the handler previously installed
145 *
146 *  NOTE:
147 *
148 *  On the SPARC, there are really only 256 vectors.  However, the executive
149 *  has no easy, fast, reliable way to determine which traps are synchronous
150 *  and which are asynchronous.  By default, synchronous traps return to the
151 *  instruction which caused the interrupt.  So if you install a software
152 *  trap handler as an executive interrupt handler (which is desirable since
153 *  RTEMS takes care of window and register issues), then the executive needs
154 *  to know that the return address is to the trap rather than the instruction
155 *  following the trap.
156 *
157 *  So vectors 0 through 255 are treated as regular asynchronous traps which
158 *  provide the "correct" return address.  Vectors 256 through 512 are assumed
159 *  by the executive to be synchronous and to require that the return address
160 *  be fudged.
161 *
162 *  If you use this mechanism to install a trap handler which must reexecute
163 *  the instruction which caused the trap, then it should be installed as
164 *  an asynchronous trap.  This will avoid the executive changing the return
165 *  address.
166 */
167 
168void _CPU_ISR_install_raw_handler(
169  unsigned32  vector,
170  proc_ptr    new_handler,
171  proc_ptr   *old_handler
172)
173{
174  unsigned32             real_vector;
175  CPU_Trap_table_entry  *tbr;
176  CPU_Trap_table_entry  *slot;
177  unsigned32             u32_tbr;
178  unsigned32             u32_handler;
179
180  /*
181   *  Get the "real" trap number for this vector ignoring the synchronous
182   *  versus asynchronous indicator included with our vector numbers.
183   */
184
185  real_vector = SPARC_REAL_TRAP_NUMBER( vector );
186
187  /*
188   *  Get the current base address of the trap table and calculate a pointer
189   *  to the slot we are interested in.
190   */
191
192  sparc_get_tbr( u32_tbr );
193
194  u32_tbr &= 0xfffff000;
195
196  tbr = (CPU_Trap_table_entry *) u32_tbr;
197
198  slot = &tbr[ real_vector ];
199
200  /*
201   *  Get the address of the old_handler from the trap table.
202   *
203   *  NOTE: The old_handler returned will be bogus if it does not follow
204   *        the RTEMS model.
205   */
206
207#define HIGH_BITS_MASK   0xFFFFFC00
208#define HIGH_BITS_SHIFT  10
209#define LOW_BITS_MASK    0x000003FF
210
211  if ( slot->mov_psr_l0 == _CPU_Trap_slot_template.mov_psr_l0 ) {
212    u32_handler =
213      ((slot->sethi_of_handler_to_l4 & HIGH_BITS_MASK) << HIGH_BITS_SHIFT) |
214      (slot->jmp_to_low_of_handler_plus_l4 & LOW_BITS_MASK);
215    *old_handler = (proc_ptr) u32_handler;
216  } else
217    *old_handler = 0;
218
219  /*
220   *  Copy the template to the slot and then fix it.
221   */
222
223  *slot = _CPU_Trap_slot_template;
224
225  u32_handler = (unsigned32) new_handler;
226
227  slot->mov_vector_l3 |= vector;
228  slot->sethi_of_handler_to_l4 |=
229    (u32_handler & HIGH_BITS_MASK) >> HIGH_BITS_SHIFT;
230  slot->jmp_to_low_of_handler_plus_l4 |= (u32_handler & LOW_BITS_MASK);
231}
232
233/*PAGE
234 *
235 *  _CPU_ISR_install_vector
236 *
237 *  This kernel routine installs the RTEMS handler for the
238 *  specified vector.
239 *
240 *  Input parameters:
241 *    vector       - interrupt vector number
242 *    new_handler  - replacement ISR for this vector number
243 *    old_handler  - pointer to former ISR for this vector number
244 *
245 *  Output parameters:
246 *    *old_handler - former ISR for this vector number
247 *
248 */
249
250void _CPU_ISR_install_vector(
251  unsigned32  vector,
252  proc_ptr    new_handler,
253  proc_ptr   *old_handler
254)
255{
256   unsigned32 real_vector;
257   proc_ptr   ignored;
258
259  /*
260   *  Get the "real" trap number for this vector ignoring the synchronous
261   *  versus asynchronous indicator included with our vector numbers.
262   */
263
264   real_vector = SPARC_REAL_TRAP_NUMBER( vector );
265
266   /*
267    *  Return the previous ISR handler.
268    */
269
270   *old_handler = _ISR_Vector_table[ real_vector ];
271
272   /*
273    *  Install the wrapper so this ISR can be invoked properly.
274    */
275
276   _CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
277
278   /*
279    *  We put the actual user ISR address in '_ISR_vector_table'.  This will
280    *  be used by the _ISR_Handler so the user gets control.
281    */
282
283    _ISR_Vector_table[ real_vector ] = new_handler;
284}
285
286/*PAGE
287 *
288 *  _CPU_Context_Initialize
289 *
290 *  This kernel routine initializes the basic non-FP context area associated
291 *  with each thread.
292 *
293 *  Input parameters:
294 *    the_context  - pointer to the context area
295 *    stack_base   - address of memory for the SPARC
296 *    size         - size in bytes of the stack area
297 *    new_level    - interrupt level for this context area
298 *    entry_point  - the starting execution point for this this context
299 *    is_fp        - TRUE if this context is associated with an FP thread
300 *
301 *  Output parameters: NONE
302 */
303
304void _CPU_Context_Initialize(
305  Context_Control  *the_context,
306  unsigned32       *stack_base,
307  unsigned32        size,
308  unsigned32        new_level,
309  void             *entry_point,
310  boolean           is_fp
311)
312{
313    unsigned32   stack_high;  /* highest "stack aligned" address */
314    unsigned32   the_size;
315    unsigned32   tmp_psr;
316 
317    /*
318     *  On CPUs with stacks which grow down (i.e. SPARC), we build the stack
319     *  based on the stack_high address. 
320     */
321 
322    stack_high = ((unsigned32)(stack_base) + size);
323    stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
324 
325    the_size = size & ~(CPU_STACK_ALIGNMENT - 1);
326 
327    /*
328     *  See the README in this directory for a diagram of the stack.
329     */
330 
331    the_context->o7    = ((unsigned32) entry_point) - 8;
332    the_context->o6_sp = stack_high - CPU_MINIMUM_STACK_FRAME_SIZE;
333    the_context->i6_fp = stack_high;
334
335    /*
336     *  Build the PSR for the task.  Most everything can be 0 and the
337     *  CWP is corrected during the context switch.
338     *
339     *  The EF bit determines if the floating point unit is available.
340     *  The FPU is ONLY enabled if the context is associated with an FP task
341     *  and this SPARC model has an FPU.
342     */
343
344    sparc_get_psr( tmp_psr );
345    tmp_psr &= ~SPARC_PSR_PIL_MASK;
346    tmp_psr |= (new_level << 8) & SPARC_PSR_PIL_MASK;
347    tmp_psr &= ~SPARC_PSR_EF_MASK;      /* disabled by default */
348   
349#if (SPARC_HAS_FPU == 1)
350    /*
351     *  If this bit is not set, then a task gets a fault when it accesses
352     *  a floating point register.  This is a nice way to detect floating
353     *  point tasks which are not currently declared as such.
354     */
355
356    if ( is_fp )
357      tmp_psr |= SPARC_PSR_EF_MASK;
358#endif
359    the_context->psr = tmp_psr;
360}
361
362/*PAGE
363 *
364 *  _CPU_Internal_threads_Idle_thread_body
365 *
366 *  Some SPARC implementations have low power, sleep, or idle modes.  This
367 *  tries to take advantage of those models. 
368 */
369 
370#if (CPU_PROVIDES_IDLE_THREAD_BODY == TRUE)
371
372/*
373 *  This is the implementation for the erc32.
374 *
375 *  NOTE: Low power mode was enabled at initialization time.
376 */
377
378#if defined(erc32)
379
380void _CPU_Internal_threads_Idle_thread_body( void )
381{
382  while (1) {
383    ERC32_MEC.Power_Down = 0;   /* value is irrelevant */
384  }
385}
386
387#endif
388
389#endif /* CPU_PROVIDES_IDLE_THREAD_BODY */
Note: See TracBrowser for help on using the repository browser.