newlib-cygwin/newlib/libc/machine/powerpc/setjmp.S

388 lines
10 KiB
ArmAsm

/* This is a simple version of setjmp and longjmp for the PowerPC.
Ian Lance Taylor, Cygnus Support, 9 Feb 1994.
Modified by Jeff Johnston, Red Hat Inc. 2 Oct 2001.
Modified by Sebastian Huber, embedded brains GmbH. 22 Sep 2022. */
#include "ppc-asm.h"
FUNC_START(setjmp)
#ifdef __ALTIVEC__
addi 3,3,15 # align Altivec to 16 byte boundary
#if __powerpc64__
clrrdi 3,3,4
#else
rlwinm 3,3,0,0,27
#endif
#else
addi 3,3,7 # align to 8 byte boundary
#if __powerpc64__
clrrdi 3,3,3
#else
rlwinm 3,3,0,0,28
#endif
#endif
#if __SPE__
/* If we are E500, then save 64-bit registers. */
evstdd 1,0(3) # offset 0
evstdd 2,8(3) # offset 8
evstdd 13,16(3) # offset 16
evstdd 14,24(3) # offset 24
evstdd 15,32(3) # offset 32
evstdd 16,40(3) # offset 40
evstdd 17,48(3) # offset 48
evstdd 18,56(3) # offset 56
evstdd 19,64(3) # offset 64
evstdd 20,72(3) # offset 72
evstdd 21,80(3) # offset 80
evstdd 22,88(3) # offset 88
evstdd 23,96(3) # offset 96
evstdd 24,104(3) # offset 104
evstdd 25,112(3) # offset 112
evstdd 26,120(3) # offset 120
evstdd 27,128(3) # offset 128
evstdd 28,136(3) # offset 136
evstdd 29,144(3) # offset 144
evstdd 30,152(3) # offset 152
evstdd 31,160(3) # offset 160
/* Add 164 to r3 to account for the amount of data we just
stored. Note that we are not adding 168 because the next
store instruction uses an offset of 4. */
addi 3,3,164
#elif __powerpc64__
/* In the first store, add 8 to r3 so that the subsequent floating
point stores are aligned on an 8 byte boundary and the Altivec
stores are aligned on a 16 byte boundary. */
stdu 1,8(3) # offset 8
stdu 2,8(3) # offset 16
stdu 13,8(3) # offset 24
stdu 14,8(3) # offset 32
stdu 15,8(3) # offset 40
stdu 16,8(3) # offset 48
stdu 17,8(3) # offset 56
stdu 18,8(3) # offset 64
stdu 19,8(3) # offset 72
stdu 20,8(3) # offset 80
stdu 21,8(3) # offset 88
stdu 22,8(3) # offset 96
stdu 23,8(3) # offset 104
stdu 24,8(3) # offset 112
stdu 25,8(3) # offset 120
stdu 26,8(3) # offset 128
stdu 27,8(3) # offset 136
stdu 28,8(3) # offset 144
stdu 29,8(3) # offset 152
stdu 30,8(3) # offset 160
stdu 31,8(3) # offset 168
mflr 4
stdu 4,8(3) # offset 176
mfcr 4
stwu 4,8(3) # offset 184
#else
stw 1,0(3) # offset 0
stwu 2,4(3) # offset 4
stwu 13,4(3) # offset 8
stwu 14,4(3) # offset 12
stwu 15,4(3) # offset 16
stwu 16,4(3) # offset 20
stwu 17,4(3) # offset 24
stwu 18,4(3) # offset 28
stwu 19,4(3) # offset 32
stwu 20,4(3) # offset 36
stwu 21,4(3) # offset 40
stwu 22,4(3) # offset 44
stwu 23,4(3) # offset 48
stwu 24,4(3) # offset 52
stwu 25,4(3) # offset 56
stwu 26,4(3) # offset 60
stwu 27,4(3) # offset 64
stwu 28,4(3) # offset 68
stwu 29,4(3) # offset 72
stwu 30,4(3) # offset 76
stwu 31,4(3) # offset 80
#endif
#if !__powerpc64__
/* If __SPE__, then add 84 to the offset shown from this point on until
the end of this function. This difference comes from the fact that
we save 21 64-bit registers instead of 21 32-bit registers above. */
mflr 4
stwu 4,4(3) # offset 84
mfcr 4
stwu 4,4(3) # offset 88
# one word pad to get floating point aligned on 8 byte boundary
#endif
/* Check whether we need to save FPRs. Checking __NO_FPRS__
on its own would be enough for GCC 4.1 and above, but older
compilers only define _SOFT_FLOAT, so check both. */
#if !defined (__NO_FPRS__) && !defined (_SOFT_FLOAT)
#if defined (__rtems__) && !defined (__PPC_CPU_E6500__)
/* For some RTEMS multilibs, the FPU and Altivec units are disabled
during interrupt handling. Do not save and restore the
corresponding registers in this case. */
mfmsr 5
andi. 5,5,0x2000
beq 1f
#endif
/* If __powerpc64__, then add 96 to the offset shown from this point on until
the end of this function. This difference comes from the fact that
we save 23 64-bit registers instead of 23 32-bit registers above and
we take alignement requirements of floating point and Altivec stores
into account. */
stfdu 14,8(3) # offset 96
stfdu 15,8(3) # offset 104
stfdu 16,8(3) # offset 112
stfdu 17,8(3) # offset 120
stfdu 18,8(3) # offset 128
stfdu 19,8(3) # offset 136
stfdu 20,8(3) # offset 144
stfdu 21,8(3) # offset 152
stfdu 22,8(3) # offset 160
stfdu 23,8(3) # offset 168
stfdu 24,8(3) # offset 176
stfdu 25,8(3) # offset 184
stfdu 26,8(3) # offset 192
stfdu 27,8(3) # offset 200
stfdu 28,8(3) # offset 208
stfdu 29,8(3) # offset 216
stfdu 30,8(3) # offset 224
stfdu 31,8(3) # offset 232
1:
#endif
/* This requires a total of 21 * 4 + 18 * 8 + 4 + 4 + 4
bytes == 60 * 4 bytes == 240 bytes. */
#ifdef __ALTIVEC__
#if defined (__rtems__) && !defined (__PPC_CPU_E6500__)
mfmsr 5
andis. 5,5,0x200
beq 1f
#endif
/* save Altivec vrsave and vr20-vr31 registers */
mfspr 4,256 # vrsave register
stwu 4,16(3) # offset 248
addi 3,3,8
stvx 20,0,3 # offset 256
addi 3,3,16
stvx 21,0,3 # offset 272
addi 3,3,16
stvx 22,0,3 # offset 288
addi 3,3,16
stvx 23,0,3 # offset 304
addi 3,3,16
stvx 24,0,3 # offset 320
addi 3,3,16
stvx 25,0,3 # offset 336
addi 3,3,16
stvx 26,0,3 # offset 352
addi 3,3,16
stvx 27,0,3 # offset 368
addi 3,3,16
stvx 28,0,3 # offset 384
addi 3,3,16
stvx 29,0,3 # offset 400
addi 3,3,16
stvx 30,0,3 # offset 416
addi 3,3,16
stvx 31,0,3 # offset 432
1:
/* This requires a total of 240 + 8 + 8 + 12 * 16 == 448 bytes. */
#endif
li 3,0
blr
FUNC_END(setjmp)
FUNC_START(longjmp)
#ifdef __ALTIVEC__
addi 3,3,15 # align Altivec to 16 byte boundary
#if __powerpc64__
clrrdi 3,3,4
#else
rlwinm 3,3,0,0,27
#endif
#else
addi 3,3,7 # align to 8 byte boundary
#if __powerpc64__
clrrdi 3,3,3
#else
rlwinm 3,3,0,0,28
#endif
#endif
#if __SPE__
/* If we are E500, then restore 64-bit registers. */
evldd 1,0(3) # offset 0
evldd 2,8(3) # offset 8
evldd 13,16(3) # offset 16
evldd 14,24(3) # offset 24
evldd 15,32(3) # offset 32
evldd 16,40(3) # offset 40
evldd 17,48(3) # offset 48
evldd 18,56(3) # offset 56
evldd 19,64(3) # offset 64
evldd 20,72(3) # offset 72
evldd 21,80(3) # offset 80
evldd 22,88(3) # offset 88
evldd 23,96(3) # offset 96
evldd 24,104(3) # offset 104
evldd 25,112(3) # offset 112
evldd 26,120(3) # offset 120
evldd 27,128(3) # offset 128
evldd 28,136(3) # offset 136
evldd 29,144(3) # offset 144
evldd 30,152(3) # offset 152
evldd 31,160(3) # offset 160
/* Add 164 to r3 to account for the amount of data we just
loaded. Note that we are not adding 168 because the next
load instruction uses an offset of 4. */
addi 3,3,164
#elif __powerpc64__
/* In the first load, add 8 to r3 so that the subsequent floating
point loades are aligned on an 8 byte boundary and the Altivec
loads are aligned on a 16 byte boundary. */
ldu 1,8(3) # offset 8
ldu 2,8(3) # offset 16
ldu 13,8(3) # offset 24
ldu 14,8(3) # offset 32
ldu 15,8(3) # offset 40
ldu 16,8(3) # offset 48
ldu 17,8(3) # offset 56
ldu 18,8(3) # offset 64
ldu 19,8(3) # offset 72
ldu 20,8(3) # offset 80
ldu 21,8(3) # offset 88
ldu 22,8(3) # offset 96
ldu 23,8(3) # offset 104
ldu 24,8(3) # offset 112
ldu 25,8(3) # offset 120
ldu 26,8(3) # offset 128
ldu 27,8(3) # offset 136
ldu 28,8(3) # offset 144
ldu 29,8(3) # offset 152
ldu 30,8(3) # offset 160
ldu 31,8(3) # offset 168
ldu 5,8(3) # offset 176
mtlr 5
lwzu 5,8(3) # offset 184
mtcrf 255,5
#else
lwz 1,0(3) # offset 0
lwzu 2,4(3) # offset 4
lwzu 13,4(3) # offset 8
lwzu 14,4(3) # offset 12
lwzu 15,4(3) # offset 16
lwzu 16,4(3) # offset 20
lwzu 17,4(3) # offset 24
lwzu 18,4(3) # offset 28
lwzu 19,4(3) # offset 32
lwzu 20,4(3) # offset 36
lwzu 21,4(3) # offset 40
lwzu 22,4(3) # offset 44
lwzu 23,4(3) # offset 48
lwzu 24,4(3) # offset 52
lwzu 25,4(3) # offset 56
lwzu 26,4(3) # offset 60
lwzu 27,4(3) # offset 64
lwzu 28,4(3) # offset 68
lwzu 29,4(3) # offset 72
lwzu 30,4(3) # offset 76
lwzu 31,4(3) # offset 80
#endif
/* If __SPE__, then add 84 to the offset shown from this point on until
the end of this function. This difference comes from the fact that
we restore 22 64-bit registers instead of 22 32-bit registers above. */
#if !__powerpc64__
lwzu 5,4(3) # offset 84
mtlr 5
lwzu 5,4(3) # offset 88
mtcrf 255,5
# one word pad to get floating point aligned on 8 byte boundary
#endif
/* Check whether we need to restore FPRs. Checking
__NO_FPRS__ on its own would be enough for GCC 4.1 and
above, but older compilers only define _SOFT_FLOAT, so
check both. */
#if !defined (__NO_FPRS__) && !defined (_SOFT_FLOAT)
#if defined (__rtems__) && !defined (__PPC_CPU_E6500__)
mfmsr 5
andi. 5,5,0x2000
beq 1f
#endif
/* If __powerpc64__, then add 96 to the offset shown from this point on until
the end of this function. This difference comes from the fact that
we restore 23 64-bit registers instead of 23 32-bit registers above and
we take alignement requirements of floating point and Altivec loads
into account. */
lfdu 14,8(3) # offset 96
lfdu 15,8(3) # offset 104
lfdu 16,8(3) # offset 112
lfdu 17,8(3) # offset 120
lfdu 18,8(3) # offset 128
lfdu 19,8(3) # offset 136
lfdu 20,8(3) # offset 144
lfdu 21,8(3) # offset 152
lfdu 22,8(3) # offset 160
lfdu 23,8(3) # offset 168
lfdu 24,8(3) # offset 176
lfdu 25,8(3) # offset 184
lfdu 26,8(3) # offset 192
lfdu 27,8(3) # offset 200
lfdu 28,8(3) # offset 208
lfdu 29,8(3) # offset 216
lfdu 30,8(3) # offset 224
lfdu 31,8(3) # offset 232
1:
#endif
#ifdef __ALTIVEC__
#if defined (__rtems__) && !defined (__PPC_CPU_E6500__)
mfmsr 5
andis. 5,5,0x200
beq 1f
#endif
/* restore Altivec vrsave and v20-v31 registers */
lwzu 5,16(3) # offset 248
mtspr 256,5 # vrsave
addi 3,3,8
lvx 20,0,3 # offset 256
addi 3,3,16
lvx 21,0,3 # offset 272
addi 3,3,16
lvx 22,0,3 # offset 288
addi 3,3,16
lvx 23,0,3 # offset 304
addi 3,3,16
lvx 24,0,3 # offset 320
addi 3,3,16
lvx 25,0,3 # offset 336
addi 3,3,16
lvx 26,0,3 # offset 352
addi 3,3,16
lvx 27,0,3 # offset 368
addi 3,3,16
lvx 28,0,3 # offset 384
addi 3,3,16
lvx 29,0,3 # offset 400
addi 3,3,16
lvx 30,0,3 # offset 416
addi 3,3,16
lvx 31,0,3 # offset 432
1:
#endif
mr. 3,4
bclr+ 4,2
li 3,1
blr
FUNC_END(longjmp)