summaryrefslogblamecommitdiffstats
path: root/c/src/exec/score/cpu/sparc/cpu_asm.s
blob: d1e275ca3f71ea5747882d373044a27169473598 (plain) (tree)







































































































































































































































































































































                                                                             
/*  cpu_asm.s
 *
 *  This file contains the basic algorithms for all assembly code used
 *  in an specific CPU port of RTEMS.  These algorithms must be implemented
 *  in assembly language
 *
 *  $Id$
 */

#include <asm.h>
#include <rtems/score/cpu.h>

/*
 *  _CPU_Context_save_fp
 *
 *  This routine is responsible for saving the FP context
 *  at *fp_context_ptr.  If the point to load the FP context
 *  from is changed then the pointer is modified by this routine.
 *
 *  Sometimes a macro implementation of this is in cpu.h which dereferences
 *  the ** and a similarly named routine in this file is passed something
 *  like a (Context_Control_fp *).  The general rule on making this decision
 *  is to avoid writing assembly language.
 *  
 *  void _CPU_Context_save_fp(
 *    void **fp_context_ptr
 *  )
 *  {
 *  }
 */

        .align 4
        PUBLIC(_CPU_Context_save_fp)
SYM(_CPU_Context_save_fp):
        save    %sp,-104,%sp
        ld      [%i0],%l0
        std     %f0,[%l0+FO_F1_OFFSET]
        std     %f2,[%l0+F2_F3_OFFSET]
        std     %f4,[%l0+F4_F5_OFFSET]
        std     %f6,[%l0+F6_F7_OFFSET]
        std     %f8,[%l0+F8_F9_OFFSET]
        std     %f10,[%l0+F1O_F11_OFFSET]
        std     %f12,[%l0+F12_F13_OFFSET]
        std     %f14,[%l0+F14_F15_OFFSET]
        std     %f16,[%l0+F16_F17_OFFSET]
        std     %f18,[%l0+F18_F19_OFFSET]
        std     %f20,[%l0+F2O_F21_OFFSET]
        std     %f22,[%l0+F22_F23_OFFSET]
        std     %f24,[%l0+F24_F25_OFFSET]
        std     %f26,[%l0+F26_F27_OFFSET]
        std     %f28,[%l0+F28_F29_OFFSET]
        std     %f30,[%l0+F3O_F31_OFFSET]
        st      %fsr,[%l0+FSR_OFFSET]
        ret
        restore

/*
 *  _CPU_Context_restore_fp
 *
 *  This routine is responsible for restoring the FP context
 *  at *fp_context_ptr.  If the point to load the FP context
 *  from is changed then the pointer is modified by this routine.
 *
 *  Sometimes a macro implementation of this is in cpu.h which dereferences
 *  the ** and a similarly named routine in this file is passed something
 *  like a (Context_Control_fp *).  The general rule on making this decision
 *  is to avoid writing assembly language.
 *  
 *  void _CPU_Context_restore_fp(
 *    void **fp_context_ptr
 *  )
 *  {
 *  }
 */

        .align 4
        PUBLIC(_CPU_Context_restore_fp)
SYM(_CPU_Context_restore_fp):
        save    %sp,-104,%sp
        ld      [%o0],%l0
        ldd     [%l0+FO_F1_OFFSET],%f0
        ldd     [%l0+F2_F3_OFFSET],%f2
        ldd     [%l0+F4_F5_OFFSET],%f4
        ldd     [%l0+F6_F7_OFFSET],%f6
        ldd     [%l0+F8_F9_OFFSET],%f8
        ldd     [%l0+F1O_F11_OFFSET],%f10
        ldd     [%l0+F12_F13_OFFSET],%f12
        ldd     [%l0+F14_F15_OFFSET],%f14
        ldd     [%l0+F16_F17_OFFSET],%f16
        ldd     [%l0+F18_F19_OFFSET],%f18
        ldd     [%l0+F2O_F21_OFFSET],%f20
        ldd     [%l0+F22_F23_OFFSET],%f22
        ldd     [%l0+F24_F25_OFFSET],%f24
        ldd     [%l0+F26_F27_OFFSET],%f26
        ldd     [%l0+F28_F29_OFFSET],%f28
        ldd     [%l0+F3O_F31_OFFSET],%f30
        ld      [%l0+FSR_OFFSET],%fsr
        ret
        restore

/*  _CPU_Context_switch
 *
 *  This routine performs a normal non-FP context switch.
 *  
 *  void _CPU_Context_switch(
 *    Context_Control  *run,
 *    Context_Control  *heir
 *  )
 *  {
 *  }
 */

/* from gcc-2.7.0/config/sparc/sparc.h on register usage */

/* 1 for registers that have pervasive standard uses
   and are not available for the register allocator.
   g0 is used for the condition code and not to represent %g0, which is
   hardwired to 0, so reg 0 is *not* fixed.
   On non-v9 systems:
   g1 is free to use as temporary.
   g2-g4 are reserved for applications.  Gcc normally uses them as
   temporaries, but this can be disabled via the -mno-app-regs option.
   g5 through g7 are reserved for the operating system.
   On v9 systems:
   g1 and g5 are free to use as temporaries.
   g2-g4 are reserved for applications (the compiler will not normally use
   them, but they can be used as temporaries with -mapp-regs).
   g6-g7 are reserved for the operating system.
   ??? Register 1 is used as a temporary by the 64 bit sethi pattern, so must
   currently be a fixed register until this pattern is rewritten.
   Register 1 is also used when restoring call-preserved registers in large
   stack frames.  */


        .align 4
        PUBLIC(_CPU_Context_switch)
SYM(_CPU_Context_switch):
        ta      0x03                       /* flush registers */

        /* skip g0 */
        st      %g1,[%o0+G1_OFFSET]        /* globals */
        st      %g2,[%o0+G2_OFFSET]
        st      %g3,[%o0+G3_OFFSET]
        st      %g4,[%o0+G4_OFFSET]
        st      %g5,[%o0+G5_OFFSET]
        st      %g6,[%o0+G6_OFFSET]
        st      %g7,[%o0+G7_OFFSET]

        st      %l0,[%o0+L0_OFFSET]
        st      %l1,[%o0+L1_OFFSET]
        st      %l2,[%o0+L2_OFFSET]
        st      %l3,[%o0+L3_OFFSET]
        st      %l4,[%o0+L4_OFFSET]
        st      %l5,[%o0+L5_OFFSET]
        st      %l6,[%o0+L6_OFFSET]
        st      %l7,[%o0+L7_OFFSET]

        st      %i0,[%o0+I0_OFFSET]
        st      %i1,[%o0+I1_OFFSET]
        st      %i2,[%o0+I2_OFFSET]
        st      %i3,[%o0+I3_OFFSET]
        st      %i4,[%o0+I4_OFFSET]
        st      %i5,[%o0+I5_OFFSET]
        st      %i6,[%o0+I6_OFFSET]
        st      %i7,[%o0+I7_OFFSET]

        st      %o0,[%o0+O0_OFFSET]
        st      %o1,[%o0+O1_OFFSET]
        st      %o2,[%o0+O2_OFFSET]
        st      %o3,[%o0+O3_OFFSET]
        st      %o4,[%o0+O4_OFFSET]
        st      %o5,[%o0+O5_OFFSET]
        st      %o6,[%o0+O6_OFFSET]
        st      %o7,[%o0+O7_OFFSET]

        rd      %psr,%o2
        st      %o2,[%o0+PSR_OFFSET]        /* save status register */

        /* enter here with o1 = context to restore */
        /*                 o2 = psr */
restore:

        ld      [%o1+PSR_OFFSET],%o0
        and     %o2,31,%o2               /* g1 = cwp */
        and     %o0,-32,%o0                /* o0 = psr w/o cwp */
        or      %o0,%o2,%o2                /* o2 = new psr */
        wr      %o2,0,%psr                 /* restore status register */

        /* skip g0 */
        ld      [%o1+G1_OFFSET],%g1
        ld      [%o1+G2_OFFSET],%g2
        ld      [%o1+G3_OFFSET],%g3
        ld      [%o1+G4_OFFSET],%g4
        ld      [%o1+G5_OFFSET],%g5
        ld      [%o1+G6_OFFSET],%g6
        ld      [%o1+G7_OFFSET],%g7

        ld      [%o1+L0_OFFSET],%l0
        ld      [%o1+L1_OFFSET],%l1
        ld      [%o1+L2_OFFSET],%l2
        ld      [%o1+L3_OFFSET],%l3
        ld      [%o1+L4_OFFSET],%l4
        ld      [%o1+L5_OFFSET],%l5
        ld      [%o1+L6_OFFSET],%l6
        ld      [%o1+L7_OFFSET],%l7

        ld      [%o1+I0_OFFSET],%i0
        ld      [%o1+I1_OFFSET],%i1
        ld      [%o1+I2_OFFSET],%i2
        ld      [%o1+I3_OFFSET],%i3
        ld      [%o1+I4_OFFSET],%i4
        ld      [%o1+I5_OFFSET],%i5
        ld      [%o1+I6_OFFSET],%i6
        ld      [%o1+I7_OFFSET],%i7

        ld      [%o1+O0_OFFSET],%o0
        /* do o1 last to avoid destroying heir context pointer */
        ld      [%o1+O2_OFFSET],%o2
        ld      [%o1+O3_OFFSET],%o3
        ld      [%o1+O4_OFFSET],%o4
        ld      [%o1+O5_OFFSET],%o5
        ld      [%o1+O6_OFFSET],%o6
        ld      [%o1+O7_OFFSET],%o7

        ld      [%o1+O1_OFFSET],%o1   /* overwrite heir pointer */

        jmp     %o7 + 8                     /* return */
        nop                                 /* delay slot */
        

/*
 *  _CPU_Context_restore
 *
 *  This routine is generallu used only to restart self in an
 *  efficient manner.  It may simply be a label in _CPU_Context_switch.
 *
 *  NOTE: May be unnecessary to reload some registers.
 *  
 *  void _CPU_Context_restore(
 *    Context_Control *new_context
 *  )
 *  {
 *  }
 */

        .align 4
        PUBLIC(_CPU_Context_restore)
SYM(_CPU_Context_restore):
        save    %sp, -104, %sp              /* save a stack frame */
        ta      0x03                       /* flush registers */
        rd      %psr,%o2
        ba      restore 
        mov     %i0,%o1                    /* in the delay slot */

/*  void _ISR_Handler()
 *
 *  This routine provides the RTEMS interrupt management.
 *
 *  void _ISR_Handler()
 *  {
 *  }
 */

        .align 4
        PUBLIC(_ISR_Handler)
SYM(_ISR_Handler):
        ret

  /*
   *  This discussion ignores a lot of the ugly details in a real
   *  implementation such as saving enough registers/state to be
   *  able to do something real.  Keep in mind that the goal is
   *  to invoke a user's ISR handler which is written in C and
   *  uses a certain set of registers.
   *
   *  Also note that the exact order is to a large extent flexible.
   *  Hardware will dictate a sequence for a certain subset of
   *  _ISR_Handler while requirements for setting
   */

 /*
  *  At entry to "common" _ISR_Handler, the vector number must be
  *  available.  On some CPUs the hardware puts either the vector
  *  number or the offset into the vector table for this ISR in a
  *  known place.  If the hardware does not give us this information,
  *  then the assembly portion of RTEMS for this port will contain
  *  a set of distinct interrupt entry points which somehow place
  *  the vector number in a known place (which is safe if another
  *  interrupt nests this one) and branches to _ISR_Handler.
  *
  *  save some or all context on stack
  *  may need to save some special interrupt information for exit
  *
  *  #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
  *    if ( _ISR_Nest_level == 0 )
  *      switch to software interrupt stack
  *  #endif
  *
  *  _ISR_Nest_level++;
  *
  *  _Thread_Dispatch_disable_level++;
  *
  *  (*_ISR_Vector_table[ vector ])( vector );
  *
  *  --_ISR_Nest_level;
  *
  *  if ( _ISR_Nest_level )
  *    goto the label "exit interrupt (simple case)"
  *
  *  #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
  *    restore stack
  *  #endif
  *  
  *  if ( !_Context_Switch_necessary )
  *    goto the label "exit interrupt (simple case)"
  *  
  *  if ( !_ISR_Signals_to_thread_executing )
  *    goto the label "exit interrupt (simple case)"
  *
  *  call _Thread_Dispatch() or prepare to return to _ISR_Dispatch
  *
  *  prepare to get out of interrupt
  *  return from interrupt  (maybe to _ISR_Dispatch)
  *
  *  LABEL "exit interrupt (simple case):
  *  prepare to get out of interrupt
  *  return from interrupt
  */