Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:25

0001 /*
0002  *  window.s
0003  *
0004  *  This file contains the register window management routines for the
0005  *  SPARC architecture.  Trap handlers for the following capabilities
0006  *  are included in this file:
0007  *
0008  *    + Window Overflow
0009  *    + Window Underflow
0010  *    + Flushing All Windows
0011  *
0012  *  COPYRIGHT:
0013  *
0014  *  This file includes the window overflow and underflow handlers from
0015  *  the file srt0.s provided with the binary distribution of the SPARC
0016  *  Instruction Simulator (SIS) found at
0017  *  ftp://ftp.estec.esa.nl/pub/ws/wsd/erc32.
0018  *
0019  *  COPYRIGHT (c) 1995. European Space Agency.
0020  *
0021  *  This terms of the RTEMS license apply to this file.
0022  */
0023 
0024 #include <rtems/asm.h>
0025 #include <libcpu/grlib-tn-0018.h>
0026 
0027         .section    ".text"
0028         /*
0029          *  Window overflow trap handler.
0030          *
0031          *  On entry:
0032          *
0033          *    prev regwin l1 = pc
0034          *    prev regwin l2 = npc
0035          */
0036 
0037         PUBLIC(window_overflow_trap_handler)
0038 
0039 SYM(window_overflow_trap_handler):
0040 
0041         /*
0042          *  Calculate new WIM by "rotating" the valid bits in the WIM right
0043          *  by one position.  The following shows how the bits move for a SPARC
0044          *  cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
0045          *
0046          *    OLD WIM = 76543210
0047          *    NEW WIM = 07654321
0048          *
0049          *  NOTE: New WIM must be stored in a global register since the
0050          *        "save" instruction just prior to the load of the wim
0051          *        register will result in the local register set changing.
0052          */
0053 
0054         std  %l0, [%sp + 0x00]           ! save local register set
0055         SPARC_LEON3FT_B2BST_NOP
0056         std  %l2, [%sp + 0x08]
0057         mov  %wim, %l3
0058         sll  %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l2
0059                                          ! l2  = WIM << (Number Windows - 1)
0060         std  %l4, [%sp + 0x10]
0061         SPARC_LEON3FT_B2BST_NOP
0062         std  %l6, [%sp + 0x18]
0063         srl  %l3, 1, %l3                 ! l3  = WIM >> 1
0064         wr   %l3, %l2, %wim              ! WIM = (WIM >> 1) ^
0065                                          !       (WIM << (Number Windows - 1))
0066                                          ! 3 instruction delay not needed here
0067         std  %i0, [%sp + 0x20]           ! save input register set
0068         SPARC_LEON3FT_B2BST_NOP
0069         std  %i2, [%sp + 0x28]
0070         SPARC_LEON3FT_B2BST_NOP
0071         std  %i4, [%sp + 0x30]
0072         SPARC_LEON3FT_B2BST_NOP
0073         std  %i6, [%sp + 0x38]
0074         restore                          ! Go back to trap window.
0075         jmp  %l1                         ! Re-execute save.
0076          rett %l2
0077 
0078         /*
0079          *  Window underflow trap handler.
0080          *
0081          *  On entry:
0082          *
0083          *    l1 = pc
0084          *    l2 = npc
0085          *    l3 = wim (from trap vector)
0086          *    l4 = wim << 1 (from trap vector)
0087          */
0088 
0089         PUBLIC(window_underflow_trap_handler)
0090 
0091 SYM(window_underflow_trap_handler):
0092 
0093         /*
0094          *  Calculate new WIM by "rotating" the valid bits in the WIM left
0095          *  by one position.  The following shows how the bits move for a SPARC
0096          *  cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
0097          *
0098          *    OLD WIM = 76543210
0099          *    NEW WIM = 07654321
0100          *
0101          *  NOTE: New WIM must be stored in a global register since the
0102          *        "save" instruction just prior to the load of the wim
0103          *        register will result in the local register set changing.
0104          */
0105 
0106         srl  %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1, %l5
0107         or   %l5, %l4, %l5              ! l5 = (WIM << 1) |
0108                                         !      (WIM >> (Number Windows-1))
0109         mov  %l5, %wim                  ! load the new WIM
0110         nop; nop; nop                   ! 3 slot delay
0111         restore                         ! Two restores to get into the
0112         restore                         ! window to restore
0113         ldd  [%sp + 0x00], %l0          ! First the local register set
0114         ldd  [%sp + 0x08], %l2
0115         ldd  [%sp + 0x10], %l4
0116         ldd  [%sp + 0x18], %l6
0117         ldd  [%sp + 0x20], %i0          ! Then the input registers
0118         ldd  [%sp + 0x28], %i2
0119         ldd  [%sp + 0x30], %i4
0120         ldd  [%sp + 0x38], %i6
0121         save                            ! Get back to the trap window.
0122         save
0123         jmp  %l1                        ! Re-execute restore.
0124          rett  %l2
0125 
0126         /*
0127          *  Flush All Windows trap handler.
0128          *
0129          *  Flush all windows with valid contents except the current one
0130          *  and the one we will be returning to.
0131          *
0132          *  In examining the set register windows, one may logically divide
0133          *  the windows into sets (some of which may be empty) based on their
0134          *  current status:
0135          *
0136          *    + current (i.e. in use),
0137          *    + used (i.e. a restore would not trap)
0138          *    + invalid (i.e. 1 in corresponding bit in WIM)
0139          *    + unused
0140          *
0141          *  Either the used or unused set of windows may be empty.
0142          *
0143          *  NOTE: We assume only one bit is set in the WIM at a time.
0144          *
0145          *  Given a CWP of 5 and a WIM of 0x1, the registers are divided
0146          *  into sets as follows:
0147          *
0148          *    + 0   - invalid
0149          *    + 1-4 - unused
0150          *    + 5   - current
0151          *    + 6-7 - used
0152          *
0153          *  In this case, we only would save the used windows which we
0154          *  will not be returning to -- 6.
0155          *
0156          *    Register Usage while saving the windows:
0157          *      g1 = current PSR
0158          *      g2 = current wim
0159          *      g3 = CWP
0160          *      g4 = wim scratch
0161          *      g5 = scratch
0162          *
0163          *  On entry:
0164          *
0165          *    l0 = psr (from trap table)
0166          *    l1 = pc
0167          *    l2 = npc
0168          */
0169 
0170         PUBLIC(window_flush_trap_handler)
0171 
0172 SYM(window_flush_trap_handler):
0173         /*
0174          *  Save the global registers we will be using
0175          */
0176 
0177         mov     %g1, %l3
0178         mov     %g2, %l4
0179         mov     %g3, %l5
0180         mov     %g4, %l6
0181         mov     %g5, %l7
0182 
0183         mov     %l0, %g1                      ! g1 = psr
0184         mov     %wim, %g2                     ! g2 = wim
0185         and     %l0, SPARC_PSR_CWP_MASK, %g3  ! g3 = CWP
0186 
0187         add     %g3, 1, %g5                   ! g5 = CWP + 1
0188         and     %g5, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g5
0189 
0190         mov     1, %g4
0191         sll     %g4, %g5, %g4                 ! g4 = WIM mask for CWP+1 invalid
0192 
0193         restore                               ! go back one register window
0194 
0195 save_frame_loop:
0196         sll     %g4, 1, %g5                   ! rotate the "wim" left 1
0197         srl     %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
0198         or      %g4, %g5, %g4                 ! g4 = wim if we do one restore
0199 
0200         /*
0201          *  If a restore would not underflow, then continue.
0202          */
0203 
0204         andcc   %g4, %g2, %g0                 ! Any windows to flush?
0205         bnz     done_flushing                 ! No, then continue
0206         nop
0207 
0208         restore                               ! back one window
0209 
0210         /*
0211          *  Now save the window just as if we overflowed to it.
0212          */
0213 
0214         std     %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
0215         SPARC_LEON3FT_B2BST_NOP
0216         std     %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
0217         SPARC_LEON3FT_B2BST_NOP
0218         std     %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
0219         SPARC_LEON3FT_B2BST_NOP
0220         std     %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
0221         SPARC_LEON3FT_B2BST_NOP
0222 
0223         std     %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
0224         SPARC_LEON3FT_B2BST_NOP
0225         std     %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
0226         SPARC_LEON3FT_B2BST_NOP
0227         std     %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
0228         SPARC_LEON3FT_B2BST_NOP
0229         std     %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
0230 
0231         ba      save_frame_loop
0232         nop
0233 
0234 done_flushing:
0235 
0236         add     %g3, 2, %g3                   ! calculate desired WIM
0237         and     %g3, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g3
0238         mov     1, %g4
0239         sll     %g4, %g3, %g4                 ! g4 = new WIM
0240         mov     %g4, %wim
0241 
0242         mov     %g1, %psr                     ! restore PSR
0243         nop
0244         nop
0245         nop
0246 
0247         /*
0248          *  Restore the global registers we used
0249          */
0250 
0251         mov     %l4, %g2
0252         mov     %l5, %g3
0253 
0254         TN0018_WAIT_IFLUSH %l4,%l5
0255         TN0018_WRITE_PSR %g1
0256 
0257         mov     %l3, %g1
0258         mov     %l6, %g4
0259         mov     %l7, %g5
0260 
0261         TN0018_FIX %l4,%l5
0262 
0263         jmpl    %l2, %g0
0264         rett    %l2 + 4
0265 
0266 /* end of file */