1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-or-later */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * Floating-point, VMX/Altivec and VSX loads and stores 4*4882a593Smuzhiyun * for use in instruction emulation. 5*4882a593Smuzhiyun * 6*4882a593Smuzhiyun * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com> 7*4882a593Smuzhiyun */ 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun#include <asm/processor.h> 10*4882a593Smuzhiyun#include <asm/ppc_asm.h> 11*4882a593Smuzhiyun#include <asm/ppc-opcode.h> 12*4882a593Smuzhiyun#include <asm/reg.h> 13*4882a593Smuzhiyun#include <asm/asm-offsets.h> 14*4882a593Smuzhiyun#include <asm/asm-compat.h> 15*4882a593Smuzhiyun#include <linux/errno.h> 16*4882a593Smuzhiyun 17*4882a593Smuzhiyun#define STKFRM (PPC_MIN_STKFRM + 16) 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun/* Get the contents of frN into *p; N is in r3 and p is in r4. */ 20*4882a593Smuzhiyun_GLOBAL(get_fpr) 21*4882a593Smuzhiyun mflr r0 22*4882a593Smuzhiyun mfmsr r6 23*4882a593Smuzhiyun ori r7, r6, MSR_FP 24*4882a593Smuzhiyun MTMSRD(r7) 25*4882a593Smuzhiyun isync 26*4882a593Smuzhiyun rlwinm r3,r3,3,0xf8 27*4882a593Smuzhiyun bcl 20,31,1f 28*4882a593Smuzhiyunreg = 0 29*4882a593Smuzhiyun .rept 32 30*4882a593Smuzhiyun stfd reg, 0(r4) 31*4882a593Smuzhiyun b 2f 32*4882a593Smuzhiyunreg = reg + 1 33*4882a593Smuzhiyun .endr 34*4882a593Smuzhiyun1: mflr r5 35*4882a593Smuzhiyun add r5,r3,r5 36*4882a593Smuzhiyun mtctr r5 37*4882a593Smuzhiyun mtlr r0 38*4882a593Smuzhiyun bctr 39*4882a593Smuzhiyun2: MTMSRD(r6) 40*4882a593Smuzhiyun isync 41*4882a593Smuzhiyun blr 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun/* Put the contents of *p into frN; N is in r3 and p is in r4. */ 44*4882a593Smuzhiyun_GLOBAL(put_fpr) 45*4882a593Smuzhiyun mflr r0 46*4882a593Smuzhiyun mfmsr r6 47*4882a593Smuzhiyun ori r7, r6, MSR_FP 48*4882a593Smuzhiyun MTMSRD(r7) 49*4882a593Smuzhiyun isync 50*4882a593Smuzhiyun rlwinm r3,r3,3,0xf8 51*4882a593Smuzhiyun bcl 20,31,1f 52*4882a593Smuzhiyunreg = 0 53*4882a593Smuzhiyun .rept 32 54*4882a593Smuzhiyun lfd reg, 0(r4) 55*4882a593Smuzhiyun b 2f 56*4882a593Smuzhiyunreg = reg + 1 57*4882a593Smuzhiyun .endr 58*4882a593Smuzhiyun1: mflr r5 59*4882a593Smuzhiyun add r5,r3,r5 60*4882a593Smuzhiyun mtctr r5 61*4882a593Smuzhiyun mtlr r0 62*4882a593Smuzhiyun bctr 63*4882a593Smuzhiyun2: MTMSRD(r6) 64*4882a593Smuzhiyun isync 65*4882a593Smuzhiyun blr 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun#ifdef CONFIG_ALTIVEC 68*4882a593Smuzhiyun/* Get the contents of vrN into *p; N is in r3 and p is in r4. */ 69*4882a593Smuzhiyun_GLOBAL(get_vr) 70*4882a593Smuzhiyun mflr r0 71*4882a593Smuzhiyun mfmsr r6 72*4882a593Smuzhiyun oris r7, r6, MSR_VEC@h 73*4882a593Smuzhiyun MTMSRD(r7) 74*4882a593Smuzhiyun isync 75*4882a593Smuzhiyun rlwinm r3,r3,3,0xf8 76*4882a593Smuzhiyun bcl 20,31,1f 77*4882a593Smuzhiyunreg = 0 78*4882a593Smuzhiyun .rept 32 79*4882a593Smuzhiyun stvx reg, 0, r4 80*4882a593Smuzhiyun b 2f 81*4882a593Smuzhiyunreg = reg + 1 82*4882a593Smuzhiyun .endr 83*4882a593Smuzhiyun1: mflr r5 84*4882a593Smuzhiyun add r5,r3,r5 85*4882a593Smuzhiyun mtctr r5 86*4882a593Smuzhiyun mtlr r0 87*4882a593Smuzhiyun bctr 88*4882a593Smuzhiyun2: MTMSRD(r6) 89*4882a593Smuzhiyun isync 90*4882a593Smuzhiyun blr 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun/* Put the contents of *p into vrN; N is in r3 and p is in r4. */ 93*4882a593Smuzhiyun_GLOBAL(put_vr) 94*4882a593Smuzhiyun mflr r0 95*4882a593Smuzhiyun mfmsr r6 96*4882a593Smuzhiyun oris r7, r6, MSR_VEC@h 97*4882a593Smuzhiyun MTMSRD(r7) 98*4882a593Smuzhiyun isync 99*4882a593Smuzhiyun rlwinm r3,r3,3,0xf8 100*4882a593Smuzhiyun bcl 20,31,1f 101*4882a593Smuzhiyunreg = 0 102*4882a593Smuzhiyun .rept 32 103*4882a593Smuzhiyun lvx reg, 0, r4 104*4882a593Smuzhiyun b 2f 105*4882a593Smuzhiyunreg = reg + 1 106*4882a593Smuzhiyun .endr 107*4882a593Smuzhiyun1: mflr r5 108*4882a593Smuzhiyun add r5,r3,r5 109*4882a593Smuzhiyun mtctr r5 110*4882a593Smuzhiyun mtlr r0 111*4882a593Smuzhiyun bctr 112*4882a593Smuzhiyun2: MTMSRD(r6) 113*4882a593Smuzhiyun isync 114*4882a593Smuzhiyun blr 115*4882a593Smuzhiyun#endif /* CONFIG_ALTIVEC */ 116*4882a593Smuzhiyun 117*4882a593Smuzhiyun#ifdef CONFIG_VSX 118*4882a593Smuzhiyun/* Get the contents of vsN into vs0; N is in r3. */ 119*4882a593Smuzhiyun_GLOBAL(get_vsr) 120*4882a593Smuzhiyun mflr r0 121*4882a593Smuzhiyun rlwinm r3,r3,3,0x1f8 122*4882a593Smuzhiyun bcl 20,31,1f 123*4882a593Smuzhiyun blr /* vs0 is already in vs0 */ 124*4882a593Smuzhiyun nop 125*4882a593Smuzhiyunreg = 1 126*4882a593Smuzhiyun .rept 63 127*4882a593Smuzhiyun XXLOR(0,reg,reg) 128*4882a593Smuzhiyun blr 129*4882a593Smuzhiyunreg = reg + 1 130*4882a593Smuzhiyun .endr 131*4882a593Smuzhiyun1: mflr r5 132*4882a593Smuzhiyun add r5,r3,r5 133*4882a593Smuzhiyun mtctr r5 134*4882a593Smuzhiyun mtlr r0 135*4882a593Smuzhiyun bctr 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun/* Put the contents of vs0 into vsN; N is in r3. */ 138*4882a593Smuzhiyun_GLOBAL(put_vsr) 139*4882a593Smuzhiyun mflr r0 140*4882a593Smuzhiyun rlwinm r3,r3,3,0x1f8 141*4882a593Smuzhiyun bcl 20,31,1f 142*4882a593Smuzhiyun blr /* v0 is already in v0 */ 143*4882a593Smuzhiyun nop 144*4882a593Smuzhiyunreg = 1 145*4882a593Smuzhiyun .rept 63 146*4882a593Smuzhiyun XXLOR(reg,0,0) 147*4882a593Smuzhiyun blr 148*4882a593Smuzhiyunreg = reg + 1 149*4882a593Smuzhiyun .endr 150*4882a593Smuzhiyun1: mflr r5 151*4882a593Smuzhiyun add r5,r3,r5 152*4882a593Smuzhiyun mtctr r5 153*4882a593Smuzhiyun mtlr r0 154*4882a593Smuzhiyun bctr 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun/* Load VSX reg N from vector doubleword *p. N is in r3, p in r4. */ 157*4882a593Smuzhiyun_GLOBAL(load_vsrn) 158*4882a593Smuzhiyun PPC_STLU r1,-STKFRM(r1) 159*4882a593Smuzhiyun mflr r0 160*4882a593Smuzhiyun PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) 161*4882a593Smuzhiyun mfmsr r6 162*4882a593Smuzhiyun oris r7,r6,MSR_VSX@h 163*4882a593Smuzhiyun cmpwi cr7,r3,0 164*4882a593Smuzhiyun li r8,STKFRM-16 165*4882a593Smuzhiyun MTMSRD(r7) 166*4882a593Smuzhiyun isync 167*4882a593Smuzhiyun beq cr7,1f 168*4882a593Smuzhiyun STXVD2X(0,R1,R8) 169*4882a593Smuzhiyun1: LXVD2X(0,R0,R4) 170*4882a593Smuzhiyun#ifdef __LITTLE_ENDIAN__ 171*4882a593Smuzhiyun XXSWAPD(0,0) 172*4882a593Smuzhiyun#endif 173*4882a593Smuzhiyun beq cr7,4f 174*4882a593Smuzhiyun bl put_vsr 175*4882a593Smuzhiyun LXVD2X(0,R1,R8) 176*4882a593Smuzhiyun4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) 177*4882a593Smuzhiyun mtlr r0 178*4882a593Smuzhiyun MTMSRD(r6) 179*4882a593Smuzhiyun isync 180*4882a593Smuzhiyun addi r1,r1,STKFRM 181*4882a593Smuzhiyun blr 182*4882a593Smuzhiyun 183*4882a593Smuzhiyun/* Store VSX reg N to vector doubleword *p. N is in r3, p in r4. */ 184*4882a593Smuzhiyun_GLOBAL(store_vsrn) 185*4882a593Smuzhiyun PPC_STLU r1,-STKFRM(r1) 186*4882a593Smuzhiyun mflr r0 187*4882a593Smuzhiyun PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) 188*4882a593Smuzhiyun mfmsr r6 189*4882a593Smuzhiyun oris r7,r6,MSR_VSX@h 190*4882a593Smuzhiyun li r8,STKFRM-16 191*4882a593Smuzhiyun MTMSRD(r7) 192*4882a593Smuzhiyun isync 193*4882a593Smuzhiyun STXVD2X(0,R1,R8) 194*4882a593Smuzhiyun bl get_vsr 195*4882a593Smuzhiyun#ifdef __LITTLE_ENDIAN__ 196*4882a593Smuzhiyun XXSWAPD(0,0) 197*4882a593Smuzhiyun#endif 198*4882a593Smuzhiyun STXVD2X(0,R0,R4) 199*4882a593Smuzhiyun LXVD2X(0,R1,R8) 200*4882a593Smuzhiyun PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) 201*4882a593Smuzhiyun mtlr r0 202*4882a593Smuzhiyun MTMSRD(r6) 203*4882a593Smuzhiyun isync 204*4882a593Smuzhiyun mr r3,r9 205*4882a593Smuzhiyun addi r1,r1,STKFRM 206*4882a593Smuzhiyun blr 207*4882a593Smuzhiyun#endif /* CONFIG_VSX */ 208*4882a593Smuzhiyun 209*4882a593Smuzhiyun/* Convert single-precision to double, without disturbing FPRs. */ 210*4882a593Smuzhiyun/* conv_sp_to_dp(float *sp, double *dp) */ 211*4882a593Smuzhiyun_GLOBAL(conv_sp_to_dp) 212*4882a593Smuzhiyun mfmsr r6 213*4882a593Smuzhiyun ori r7, r6, MSR_FP 214*4882a593Smuzhiyun MTMSRD(r7) 215*4882a593Smuzhiyun isync 216*4882a593Smuzhiyun stfd fr0, -16(r1) 217*4882a593Smuzhiyun lfs fr0, 0(r3) 218*4882a593Smuzhiyun stfd fr0, 0(r4) 219*4882a593Smuzhiyun lfd fr0, -16(r1) 220*4882a593Smuzhiyun MTMSRD(r6) 221*4882a593Smuzhiyun isync 222*4882a593Smuzhiyun blr 223*4882a593Smuzhiyun 224*4882a593Smuzhiyun/* Convert single-precision to double, without disturbing FPRs. */ 225*4882a593Smuzhiyun/* conv_sp_to_dp(double *dp, float *sp) */ 226*4882a593Smuzhiyun_GLOBAL(conv_dp_to_sp) 227*4882a593Smuzhiyun mfmsr r6 228*4882a593Smuzhiyun ori r7, r6, MSR_FP 229*4882a593Smuzhiyun MTMSRD(r7) 230*4882a593Smuzhiyun isync 231*4882a593Smuzhiyun stfd fr0, -16(r1) 232*4882a593Smuzhiyun lfd fr0, 0(r3) 233*4882a593Smuzhiyun stfs fr0, 0(r4) 234*4882a593Smuzhiyun lfd fr0, -16(r1) 235*4882a593Smuzhiyun MTMSRD(r6) 236*4882a593Smuzhiyun isync 237*4882a593Smuzhiyun blr 238