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