Changeset 9700578 in rtems for cpukit/score/cpu/sparc/cpu.c


Ignore:
Timestamp:
Oct 30, 1995, 9:54:45 PM (25 years ago)
Author:
Joel Sherrill <joel.sherrill@…>
Branches:
4.10, 4.11, 4.8, 4.9, 5, master
Children:
c4808ca
Parents:
ea74482
Message:

SPARC port passes all tests

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpukit/score/cpu/sparc/cpu.c

    rea74482 r9700578  
    88#include <rtems/score/isr.h>
    99
    10 /*  _CPU_Initialize
     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
    1134 *
    1235 *  This routine performs processor dependent initialization.
    1336 *
    14  *  INPUT PARAMETERS:
     37 *  Input Parameters:
    1538 *    cpu_table       - CPU table to initialize
    1639 *    thread_dispatch - address of disptaching routine
    17  */
    18 
     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 */
    1946
    2047void _CPU_Initialize(
    2148  rtems_cpu_table  *cpu_table,
    22   void      (*thread_dispatch)      /* ignored on this CPU */
     49  void            (*thread_dispatch)      /* ignored on this CPU */
    2350)
    2451{
    25   void *pointer;
    26 
    27   /*
    28    *  The thread_dispatch argument is the address of the entry point
    29    *  for the routine called at the end of an ISR once it has been
    30    *  decided a context switch is necessary.  On some compilation
    31    *  systems it is difficult to call a high-level language routine
    32    *  from assembly.  This allows us to trick these systems.
    33    *
    34    *  If you encounter this problem save the entry point in a CPU
    35    *  dependent variable.
    36    */
    37 
    38   _CPU_Thread_dispatch_pointer = thread_dispatch;
    39 
    40   /*
    41    *  If there is not an easy way to initialize the FP context
    42    *  during Context_Initialize, then it is usually easier to
    43    *  save an "uninitialized" FP context here and copy it to
    44    *  the task's during Context_Initialize.
     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.
    4585   */
    4686
     
    4888  _CPU_Context_save_fp( &pointer );
    4989
     90  /*
     91   *  Grab our own copy of the user's CPU table.
     92   */
     93
    5094  _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
    51109}
    52110
     
    54112 *
    55113 *  _CPU_ISR_Get_level
     114 *
     115 *  Input Parameters: NONE
     116 *
     117 *  Output Parameters:
     118 *    returns the current interrupt level (PIL field of the PSR)
    56119 */
    57120 
     
    65128}
    66129
    67 /*  _CPU_ISR_install_vector
     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
    68236 *
    69237 *  This kernel routine installs the RTEMS handler for the
     
    71239 *
    72240 *  Input parameters:
    73  *    vector      - interrupt vector number
    74  *    old_handler - former ISR for this vector number
    75  *    new_handler - replacement ISR for this vector number
    76  *
    77  *  Output parameters:  NONE
    78  *
    79  */
    80 
     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 */
    81249
    82250void _CPU_ISR_install_vector(
     
    86254)
    87255{
    88    *old_handler = _ISR_Vector_table[ vector ];
     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 );
    89265
    90266   /*
    91     *  If the interrupt vector table is a table of pointer to isr entry
    92     *  points, then we need to install the appropriate RTEMS interrupt
    93     *  handler for this vector number.
     267    *  Return the previous ISR handler.
    94268    */
     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 );
    95277
    96278   /*
     
    99281    */
    100282
    101     _ISR_Vector_table[ vector ] = new_handler;
    102 }
    103 
    104 /*PAGE
    105  *
    106  *  _CPU_Install_interrupt_stack
    107  */
    108 
    109 void _CPU_Install_interrupt_stack( void )
    110 {
     283    _ISR_Vector_table[ real_vector ] = new_handler;
    111284}
    112285
     
    114287 *
    115288 *  _CPU_Context_Initialize
    116  */
    117 
    118 /*
    119  *  The following constants assist in building a thread's initial context.
    120  */
    121 
    122 #define CPU_FRAME_SIZE  (112)   /* based on disassembled test code */
    123 #define ADDR_ADJ_OFFSET  -8
     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 */
    124303
    125304void _CPU_Context_Initialize(
    126   Context_Control  *_the_context,
    127   unsigned32       *_stack_base,
    128   unsigned32        _size,
    129   unsigned32        _new_level,
    130   void             *_entry_point
     305  Context_Control  *the_context,
     306  unsigned32       *stack_base,
     307  unsigned32        size,
     308  unsigned32        new_level,
     309  void             *entry_point,
     310  boolean           is_fp
    131311)
    132312{
    133     unsigned32   jmp_addr;
    134     unsigned32   _stack_high;  /* highest "stack aligned" address */
    135     unsigned32   _the_size;
     313    unsigned32   stack_high;  /* highest "stack aligned" address */
     314    unsigned32   the_size;
    136315    unsigned32   tmp_psr;
    137  
    138     jmp_addr = (unsigned32) _entry_point;
    139316 
    140317    /*
    141318     *  On CPUs with stacks which grow down (i.e. SPARC), we build the stack
    142      *  based on the _stack_high address. 
     319     *  based on the stack_high address. 
    143320     */
    144321 
    145     _stack_high = ((unsigned32)(_stack_base) + _size);
    146     _stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
    147  
    148     _the_size = _size & ~(CPU_STACK_ALIGNMENT - 1);
    149  
    150 /* XXX following code is based on unix port */
     322    stack_high = ((unsigned32)(stack_base) + size);
     323    stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
     324 
     325    the_size = size & ~(CPU_STACK_ALIGNMENT - 1);
     326 
    151327    /*
    152      *  XXX SPARC port needs a diagram like this one...
    153      *  See /usr/include/sys/stack.h in Solaris 2.3 for a nice
    154      *  diagram of the stack.
     328     *  See the README in this directory for a diagram of the stack.
    155329     */
    156330 
    157     _the_context->o7 = jmp_addr + ADDR_ADJ_OFFSET;
    158     _the_context->o6 = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
    159     _the_context->i6 = (unsigned32)(_stack_high);
    160 #if 0
    161     _the_context->rp = jmp_addr + ADDR_ADJ_OFFSET;
    162     _the_context->sp = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
    163     _the_context->fp = (unsigned32)(_stack_high);
     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;
    164358#endif
    165 
    166     _the_context->wim = 0x01;
    167 
    168     sparc_get_psr( tmp_psr );
    169     tmp_psr &= ~SPARC_PIL_MASK;
    170     tmp_psr |= (((_new_level) << 8) & SPARC_PIL_MASK);
    171     tmp_psr  = (tmp_psr & ~0x07) | 0x07;  /* XXX should use num windows */
    172     _the_context->psr = tmp_psr;
     359    the_context->psr = tmp_psr;
    173360}
    174361
     
    177364 *  _CPU_Internal_threads_Idle_thread_body
    178365 *
    179  *  NOTES:
    180  *
    181  *  1. This is the same as the regular CPU independent algorithm.
    182  *
    183  *  2. If you implement this using a "halt", "idle", or "shutdown"
    184  *     instruction, then don't forget to put it in an infinite loop.
    185  *
    186  *  3. Be warned. Some processors with onboard DMA have been known
    187  *     to stop the DMA if the CPU were put in IDLE mode.  This might
    188  *     also be a problem with other on-chip peripherals.  So use this
    189  *     hook with caution.
    190  */
     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)
    191379
    192380void _CPU_Internal_threads_Idle_thread_body( void )
    193381{
    194 
    195   for( ; ; )
    196     /* insert your "halt" instruction here */ ;
    197 }
     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 TracChangeset for help on using the changeset viewer.