forked from Imagelibrary/rtems
The window underflow trap handler used %i5 which destroyed the %o5 of the calling context. Bug introduced by0d3b5d4742. Go back to the pre0d3b5d4742behaviour and use the two unused instructions in the trap vector to optimize a bit. Update #2651.
248 lines
8.0 KiB
ArmAsm
248 lines
8.0 KiB
ArmAsm
/*
|
|
* window.s
|
|
*
|
|
* This file contains the register window management routines for the
|
|
* SPARC architecture. Trap handlers for the following capabilities
|
|
* are included in this file:
|
|
*
|
|
* + Window Overflow
|
|
* + Window Underflow
|
|
* + Flushing All Windows
|
|
*
|
|
* COPYRIGHT:
|
|
*
|
|
* This file includes the window overflow and underflow handlers from
|
|
* the file srt0.s provided with the binary distribution of the SPARC
|
|
* Instruction Simulator (SIS) found at
|
|
* ftp://ftp.estec.esa.nl/pub/ws/wsd/erc32.
|
|
*
|
|
* COPYRIGHT (c) 1995. European Space Agency.
|
|
*
|
|
* This terms of the RTEMS license apply to this file.
|
|
*/
|
|
|
|
#include <rtems/asm.h>
|
|
|
|
.seg "text"
|
|
/*
|
|
* Window overflow trap handler.
|
|
*
|
|
* On entry:
|
|
*
|
|
* prev regwin l1 = pc
|
|
* prev regwin l2 = npc
|
|
*/
|
|
|
|
PUBLIC(window_overflow_trap_handler)
|
|
|
|
SYM(window_overflow_trap_handler):
|
|
|
|
/*
|
|
* Calculate new WIM by "rotating" the valid bits in the WIM right
|
|
* by one position. The following shows how the bits move for a SPARC
|
|
* cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
|
|
*
|
|
* OLD WIM = 76543210
|
|
* NEW WIM = 07654321
|
|
*
|
|
* NOTE: New WIM must be stored in a global register since the
|
|
* "save" instruction just prior to the load of the wim
|
|
* register will result in the local register set changing.
|
|
*/
|
|
|
|
std %l0, [%sp + 0x00] ! save local register set
|
|
std %l2, [%sp + 0x08]
|
|
mov %wim, %l3
|
|
sll %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l2
|
|
! l2 = WIM << (Number Windows - 1)
|
|
std %l4, [%sp + 0x10]
|
|
std %l6, [%sp + 0x18]
|
|
srl %l3, 1, %l3 ! l3 = WIM >> 1
|
|
wr %l3, %l2, %wim ! WIM = (WIM >> 1) ^
|
|
! (WIM << (Number Windows - 1))
|
|
! 3 instruction delay not needed here
|
|
std %i0, [%sp + 0x20] ! save input register set
|
|
std %i2, [%sp + 0x28]
|
|
std %i4, [%sp + 0x30]
|
|
std %i6, [%sp + 0x38]
|
|
restore ! Go back to trap window.
|
|
jmp %l1 ! Re-execute save.
|
|
rett %l2
|
|
|
|
/*
|
|
* Window underflow trap handler.
|
|
*
|
|
* On entry:
|
|
*
|
|
* l1 = pc
|
|
* l2 = npc
|
|
* l3 = wim (from trap vector)
|
|
* l4 = wim << 1 (from trap vector)
|
|
*/
|
|
|
|
PUBLIC(window_underflow_trap_handler)
|
|
|
|
SYM(window_underflow_trap_handler):
|
|
|
|
/*
|
|
* Calculate new WIM by "rotating" the valid bits in the WIM left
|
|
* by one position. The following shows how the bits move for a SPARC
|
|
* cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
|
|
*
|
|
* OLD WIM = 76543210
|
|
* NEW WIM = 07654321
|
|
*
|
|
* NOTE: New WIM must be stored in a global register since the
|
|
* "save" instruction just prior to the load of the wim
|
|
* register will result in the local register set changing.
|
|
*/
|
|
|
|
srl %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1, %l5
|
|
or %l5, %l4, %l5 ! l5 = (WIM << 1) |
|
|
! (WIM >> (Number Windows-1))
|
|
mov %l5, %wim ! load the new WIM
|
|
nop; nop; nop ! 3 slot delay
|
|
restore ! Two restores to get into the
|
|
restore ! window to restore
|
|
ldd [%sp + 0x00], %l0 ! First the local register set
|
|
ldd [%sp + 0x08], %l2
|
|
ldd [%sp + 0x10], %l4
|
|
ldd [%sp + 0x18], %l6
|
|
ldd [%sp + 0x20], %i0 ! Then the input registers
|
|
ldd [%sp + 0x28], %i2
|
|
ldd [%sp + 0x30], %i4
|
|
ldd [%sp + 0x38], %i6
|
|
save ! Get back to the trap window.
|
|
save
|
|
jmp %l1 ! Re-execute restore.
|
|
rett %l2
|
|
|
|
/*
|
|
* Flush All Windows trap handler.
|
|
*
|
|
* Flush all windows with valid contents except the current one
|
|
* and the one we will be returning to.
|
|
*
|
|
* In examining the set register windows, one may logically divide
|
|
* the windows into sets (some of which may be empty) based on their
|
|
* current status:
|
|
*
|
|
* + current (i.e. in use),
|
|
* + used (i.e. a restore would not trap)
|
|
* + invalid (i.e. 1 in corresponding bit in WIM)
|
|
* + unused
|
|
*
|
|
* Either the used or unused set of windows may be empty.
|
|
*
|
|
* NOTE: We assume only one bit is set in the WIM at a time.
|
|
*
|
|
* Given a CWP of 5 and a WIM of 0x1, the registers are divided
|
|
* into sets as follows:
|
|
*
|
|
* + 0 - invalid
|
|
* + 1-4 - unused
|
|
* + 5 - current
|
|
* + 6-7 - used
|
|
*
|
|
* In this case, we only would save the used windows which we
|
|
* will not be returning to -- 6.
|
|
*
|
|
* Register Usage while saving the windows:
|
|
* g1 = current PSR
|
|
* g2 = current wim
|
|
* g3 = CWP
|
|
* g4 = wim scratch
|
|
* g5 = scratch
|
|
*
|
|
* On entry:
|
|
*
|
|
* l0 = psr (from trap table)
|
|
* l1 = pc
|
|
* l2 = npc
|
|
*/
|
|
|
|
PUBLIC(window_flush_trap_handler)
|
|
|
|
SYM(window_flush_trap_handler):
|
|
/*
|
|
* Save the global registers we will be using
|
|
*/
|
|
|
|
mov %g1, %l3
|
|
mov %g2, %l4
|
|
mov %g3, %l5
|
|
mov %g4, %l6
|
|
mov %g5, %l7
|
|
|
|
mov %l0, %g1 ! g1 = psr
|
|
mov %wim, %g2 ! g2 = wim
|
|
and %l0, SPARC_PSR_CWP_MASK, %g3 ! g3 = CWP
|
|
|
|
add %g3, 1, %g5 ! g5 = CWP + 1
|
|
and %g5, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g5
|
|
|
|
mov 1, %g4
|
|
sll %g4, %g5, %g4 ! g4 = WIM mask for CWP+1 invalid
|
|
|
|
restore ! go back one register window
|
|
|
|
save_frame_loop:
|
|
sll %g4, 1, %g5 ! rotate the "wim" left 1
|
|
srl %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
|
|
or %g4, %g5, %g4 ! g4 = wim if we do one restore
|
|
|
|
/*
|
|
* If a restore would not underflow, then continue.
|
|
*/
|
|
|
|
andcc %g4, %g2, %g0 ! Any windows to flush?
|
|
bnz done_flushing ! No, then continue
|
|
nop
|
|
|
|
restore ! back one window
|
|
|
|
/*
|
|
* Now save the window just as if we overflowed to it.
|
|
*/
|
|
|
|
std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
|
|
std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
|
|
std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
|
|
std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
|
|
|
|
std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
|
|
std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
|
|
std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
|
|
std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
|
|
|
|
ba save_frame_loop
|
|
nop
|
|
|
|
done_flushing:
|
|
|
|
add %g3, 2, %g3 ! calculate desired WIM
|
|
and %g3, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g3
|
|
mov 1, %g4
|
|
sll %g4, %g3, %g4 ! g4 = new WIM
|
|
mov %g4, %wim
|
|
|
|
mov %g1, %psr ! restore PSR
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
/*
|
|
* Restore the global registers we used
|
|
*/
|
|
|
|
mov %l3, %g1
|
|
mov %l4, %g2
|
|
mov %l5, %g3
|
|
mov %l6, %g4
|
|
mov %l7, %g5
|
|
|
|
jmpl %l2, %g0
|
|
rett %l2 + 4
|
|
|
|
/* end of file */
|