18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Floating-point, VMX/Altivec and VSX loads and stores 48c2ecf20Sopenharmony_ci * for use in instruction emulation. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/processor.h> 108c2ecf20Sopenharmony_ci#include <asm/ppc_asm.h> 118c2ecf20Sopenharmony_ci#include <asm/ppc-opcode.h> 128c2ecf20Sopenharmony_ci#include <asm/reg.h> 138c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h> 148c2ecf20Sopenharmony_ci#include <asm/asm-compat.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define STKFRM (PPC_MIN_STKFRM + 16) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Get the contents of frN into *p; N is in r3 and p is in r4. */ 208c2ecf20Sopenharmony_ci_GLOBAL(get_fpr) 218c2ecf20Sopenharmony_ci mflr r0 228c2ecf20Sopenharmony_ci mfmsr r6 238c2ecf20Sopenharmony_ci ori r7, r6, MSR_FP 248c2ecf20Sopenharmony_ci MTMSRD(r7) 258c2ecf20Sopenharmony_ci isync 268c2ecf20Sopenharmony_ci rlwinm r3,r3,3,0xf8 278c2ecf20Sopenharmony_ci bcl 20,31,1f 288c2ecf20Sopenharmony_cireg = 0 298c2ecf20Sopenharmony_ci .rept 32 308c2ecf20Sopenharmony_ci stfd reg, 0(r4) 318c2ecf20Sopenharmony_ci b 2f 328c2ecf20Sopenharmony_cireg = reg + 1 338c2ecf20Sopenharmony_ci .endr 348c2ecf20Sopenharmony_ci1: mflr r5 358c2ecf20Sopenharmony_ci add r5,r3,r5 368c2ecf20Sopenharmony_ci mtctr r5 378c2ecf20Sopenharmony_ci mtlr r0 388c2ecf20Sopenharmony_ci bctr 398c2ecf20Sopenharmony_ci2: MTMSRD(r6) 408c2ecf20Sopenharmony_ci isync 418c2ecf20Sopenharmony_ci blr 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* Put the contents of *p into frN; N is in r3 and p is in r4. */ 448c2ecf20Sopenharmony_ci_GLOBAL(put_fpr) 458c2ecf20Sopenharmony_ci mflr r0 468c2ecf20Sopenharmony_ci mfmsr r6 478c2ecf20Sopenharmony_ci ori r7, r6, MSR_FP 488c2ecf20Sopenharmony_ci MTMSRD(r7) 498c2ecf20Sopenharmony_ci isync 508c2ecf20Sopenharmony_ci rlwinm r3,r3,3,0xf8 518c2ecf20Sopenharmony_ci bcl 20,31,1f 528c2ecf20Sopenharmony_cireg = 0 538c2ecf20Sopenharmony_ci .rept 32 548c2ecf20Sopenharmony_ci lfd reg, 0(r4) 558c2ecf20Sopenharmony_ci b 2f 568c2ecf20Sopenharmony_cireg = reg + 1 578c2ecf20Sopenharmony_ci .endr 588c2ecf20Sopenharmony_ci1: mflr r5 598c2ecf20Sopenharmony_ci add r5,r3,r5 608c2ecf20Sopenharmony_ci mtctr r5 618c2ecf20Sopenharmony_ci mtlr r0 628c2ecf20Sopenharmony_ci bctr 638c2ecf20Sopenharmony_ci2: MTMSRD(r6) 648c2ecf20Sopenharmony_ci isync 658c2ecf20Sopenharmony_ci blr 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC 688c2ecf20Sopenharmony_ci/* Get the contents of vrN into *p; N is in r3 and p is in r4. */ 698c2ecf20Sopenharmony_ci_GLOBAL(get_vr) 708c2ecf20Sopenharmony_ci mflr r0 718c2ecf20Sopenharmony_ci mfmsr r6 728c2ecf20Sopenharmony_ci oris r7, r6, MSR_VEC@h 738c2ecf20Sopenharmony_ci MTMSRD(r7) 748c2ecf20Sopenharmony_ci isync 758c2ecf20Sopenharmony_ci rlwinm r3,r3,3,0xf8 768c2ecf20Sopenharmony_ci bcl 20,31,1f 778c2ecf20Sopenharmony_cireg = 0 788c2ecf20Sopenharmony_ci .rept 32 798c2ecf20Sopenharmony_ci stvx reg, 0, r4 808c2ecf20Sopenharmony_ci b 2f 818c2ecf20Sopenharmony_cireg = reg + 1 828c2ecf20Sopenharmony_ci .endr 838c2ecf20Sopenharmony_ci1: mflr r5 848c2ecf20Sopenharmony_ci add r5,r3,r5 858c2ecf20Sopenharmony_ci mtctr r5 868c2ecf20Sopenharmony_ci mtlr r0 878c2ecf20Sopenharmony_ci bctr 888c2ecf20Sopenharmony_ci2: MTMSRD(r6) 898c2ecf20Sopenharmony_ci isync 908c2ecf20Sopenharmony_ci blr 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Put the contents of *p into vrN; N is in r3 and p is in r4. */ 938c2ecf20Sopenharmony_ci_GLOBAL(put_vr) 948c2ecf20Sopenharmony_ci mflr r0 958c2ecf20Sopenharmony_ci mfmsr r6 968c2ecf20Sopenharmony_ci oris r7, r6, MSR_VEC@h 978c2ecf20Sopenharmony_ci MTMSRD(r7) 988c2ecf20Sopenharmony_ci isync 998c2ecf20Sopenharmony_ci rlwinm r3,r3,3,0xf8 1008c2ecf20Sopenharmony_ci bcl 20,31,1f 1018c2ecf20Sopenharmony_cireg = 0 1028c2ecf20Sopenharmony_ci .rept 32 1038c2ecf20Sopenharmony_ci lvx reg, 0, r4 1048c2ecf20Sopenharmony_ci b 2f 1058c2ecf20Sopenharmony_cireg = reg + 1 1068c2ecf20Sopenharmony_ci .endr 1078c2ecf20Sopenharmony_ci1: mflr r5 1088c2ecf20Sopenharmony_ci add r5,r3,r5 1098c2ecf20Sopenharmony_ci mtctr r5 1108c2ecf20Sopenharmony_ci mtlr r0 1118c2ecf20Sopenharmony_ci bctr 1128c2ecf20Sopenharmony_ci2: MTMSRD(r6) 1138c2ecf20Sopenharmony_ci isync 1148c2ecf20Sopenharmony_ci blr 1158c2ecf20Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX 1188c2ecf20Sopenharmony_ci/* Get the contents of vsN into vs0; N is in r3. */ 1198c2ecf20Sopenharmony_ci_GLOBAL(get_vsr) 1208c2ecf20Sopenharmony_ci mflr r0 1218c2ecf20Sopenharmony_ci rlwinm r3,r3,3,0x1f8 1228c2ecf20Sopenharmony_ci bcl 20,31,1f 1238c2ecf20Sopenharmony_ci blr /* vs0 is already in vs0 */ 1248c2ecf20Sopenharmony_ci nop 1258c2ecf20Sopenharmony_cireg = 1 1268c2ecf20Sopenharmony_ci .rept 63 1278c2ecf20Sopenharmony_ci XXLOR(0,reg,reg) 1288c2ecf20Sopenharmony_ci blr 1298c2ecf20Sopenharmony_cireg = reg + 1 1308c2ecf20Sopenharmony_ci .endr 1318c2ecf20Sopenharmony_ci1: mflr r5 1328c2ecf20Sopenharmony_ci add r5,r3,r5 1338c2ecf20Sopenharmony_ci mtctr r5 1348c2ecf20Sopenharmony_ci mtlr r0 1358c2ecf20Sopenharmony_ci bctr 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* Put the contents of vs0 into vsN; N is in r3. */ 1388c2ecf20Sopenharmony_ci_GLOBAL(put_vsr) 1398c2ecf20Sopenharmony_ci mflr r0 1408c2ecf20Sopenharmony_ci rlwinm r3,r3,3,0x1f8 1418c2ecf20Sopenharmony_ci bcl 20,31,1f 1428c2ecf20Sopenharmony_ci blr /* v0 is already in v0 */ 1438c2ecf20Sopenharmony_ci nop 1448c2ecf20Sopenharmony_cireg = 1 1458c2ecf20Sopenharmony_ci .rept 63 1468c2ecf20Sopenharmony_ci XXLOR(reg,0,0) 1478c2ecf20Sopenharmony_ci blr 1488c2ecf20Sopenharmony_cireg = reg + 1 1498c2ecf20Sopenharmony_ci .endr 1508c2ecf20Sopenharmony_ci1: mflr r5 1518c2ecf20Sopenharmony_ci add r5,r3,r5 1528c2ecf20Sopenharmony_ci mtctr r5 1538c2ecf20Sopenharmony_ci mtlr r0 1548c2ecf20Sopenharmony_ci bctr 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* Load VSX reg N from vector doubleword *p. N is in r3, p in r4. */ 1578c2ecf20Sopenharmony_ci_GLOBAL(load_vsrn) 1588c2ecf20Sopenharmony_ci PPC_STLU r1,-STKFRM(r1) 1598c2ecf20Sopenharmony_ci mflr r0 1608c2ecf20Sopenharmony_ci PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) 1618c2ecf20Sopenharmony_ci mfmsr r6 1628c2ecf20Sopenharmony_ci oris r7,r6,MSR_VSX@h 1638c2ecf20Sopenharmony_ci cmpwi cr7,r3,0 1648c2ecf20Sopenharmony_ci li r8,STKFRM-16 1658c2ecf20Sopenharmony_ci MTMSRD(r7) 1668c2ecf20Sopenharmony_ci isync 1678c2ecf20Sopenharmony_ci beq cr7,1f 1688c2ecf20Sopenharmony_ci STXVD2X(0,R1,R8) 1698c2ecf20Sopenharmony_ci1: LXVD2X(0,R0,R4) 1708c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 1718c2ecf20Sopenharmony_ci XXSWAPD(0,0) 1728c2ecf20Sopenharmony_ci#endif 1738c2ecf20Sopenharmony_ci beq cr7,4f 1748c2ecf20Sopenharmony_ci bl put_vsr 1758c2ecf20Sopenharmony_ci LXVD2X(0,R1,R8) 1768c2ecf20Sopenharmony_ci4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) 1778c2ecf20Sopenharmony_ci mtlr r0 1788c2ecf20Sopenharmony_ci MTMSRD(r6) 1798c2ecf20Sopenharmony_ci isync 1808c2ecf20Sopenharmony_ci addi r1,r1,STKFRM 1818c2ecf20Sopenharmony_ci blr 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* Store VSX reg N to vector doubleword *p. N is in r3, p in r4. */ 1848c2ecf20Sopenharmony_ci_GLOBAL(store_vsrn) 1858c2ecf20Sopenharmony_ci PPC_STLU r1,-STKFRM(r1) 1868c2ecf20Sopenharmony_ci mflr r0 1878c2ecf20Sopenharmony_ci PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) 1888c2ecf20Sopenharmony_ci mfmsr r6 1898c2ecf20Sopenharmony_ci oris r7,r6,MSR_VSX@h 1908c2ecf20Sopenharmony_ci li r8,STKFRM-16 1918c2ecf20Sopenharmony_ci MTMSRD(r7) 1928c2ecf20Sopenharmony_ci isync 1938c2ecf20Sopenharmony_ci STXVD2X(0,R1,R8) 1948c2ecf20Sopenharmony_ci bl get_vsr 1958c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 1968c2ecf20Sopenharmony_ci XXSWAPD(0,0) 1978c2ecf20Sopenharmony_ci#endif 1988c2ecf20Sopenharmony_ci STXVD2X(0,R0,R4) 1998c2ecf20Sopenharmony_ci LXVD2X(0,R1,R8) 2008c2ecf20Sopenharmony_ci PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) 2018c2ecf20Sopenharmony_ci mtlr r0 2028c2ecf20Sopenharmony_ci MTMSRD(r6) 2038c2ecf20Sopenharmony_ci isync 2048c2ecf20Sopenharmony_ci mr r3,r9 2058c2ecf20Sopenharmony_ci addi r1,r1,STKFRM 2068c2ecf20Sopenharmony_ci blr 2078c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */ 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* Convert single-precision to double, without disturbing FPRs. */ 2108c2ecf20Sopenharmony_ci/* conv_sp_to_dp(float *sp, double *dp) */ 2118c2ecf20Sopenharmony_ci_GLOBAL(conv_sp_to_dp) 2128c2ecf20Sopenharmony_ci mfmsr r6 2138c2ecf20Sopenharmony_ci ori r7, r6, MSR_FP 2148c2ecf20Sopenharmony_ci MTMSRD(r7) 2158c2ecf20Sopenharmony_ci isync 2168c2ecf20Sopenharmony_ci stfd fr0, -16(r1) 2178c2ecf20Sopenharmony_ci lfs fr0, 0(r3) 2188c2ecf20Sopenharmony_ci stfd fr0, 0(r4) 2198c2ecf20Sopenharmony_ci lfd fr0, -16(r1) 2208c2ecf20Sopenharmony_ci MTMSRD(r6) 2218c2ecf20Sopenharmony_ci isync 2228c2ecf20Sopenharmony_ci blr 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* Convert single-precision to double, without disturbing FPRs. */ 2258c2ecf20Sopenharmony_ci/* conv_sp_to_dp(double *dp, float *sp) */ 2268c2ecf20Sopenharmony_ci_GLOBAL(conv_dp_to_sp) 2278c2ecf20Sopenharmony_ci mfmsr r6 2288c2ecf20Sopenharmony_ci ori r7, r6, MSR_FP 2298c2ecf20Sopenharmony_ci MTMSRD(r7) 2308c2ecf20Sopenharmony_ci isync 2318c2ecf20Sopenharmony_ci stfd fr0, -16(r1) 2328c2ecf20Sopenharmony_ci lfd fr0, 0(r3) 2338c2ecf20Sopenharmony_ci stfs fr0, 0(r4) 2348c2ecf20Sopenharmony_ci lfd fr0, -16(r1) 2358c2ecf20Sopenharmony_ci MTMSRD(r6) 2368c2ecf20Sopenharmony_ci isync 2378c2ecf20Sopenharmony_ci blr 238