162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Floating-point, VMX/Altivec and VSX loads and stores 462306a36Sopenharmony_ci * for use in instruction emulation. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/processor.h> 1062306a36Sopenharmony_ci#include <asm/ppc_asm.h> 1162306a36Sopenharmony_ci#include <asm/ppc-opcode.h> 1262306a36Sopenharmony_ci#include <asm/reg.h> 1362306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1462306a36Sopenharmony_ci#include <asm/asm-compat.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define STKFRM (PPC_MIN_STKFRM + 16) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* Get the contents of frN into *p; N is in r3 and p is in r4. */ 2062306a36Sopenharmony_ci_GLOBAL(get_fpr) 2162306a36Sopenharmony_ci mflr r0 2262306a36Sopenharmony_ci mfmsr r6 2362306a36Sopenharmony_ci ori r7, r6, MSR_FP 2462306a36Sopenharmony_ci MTMSRD(r7) 2562306a36Sopenharmony_ci isync 2662306a36Sopenharmony_ci rlwinm r3,r3,3,0xf8 2762306a36Sopenharmony_ci bcl 20,31,1f 2862306a36Sopenharmony_cireg = 0 2962306a36Sopenharmony_ci .rept 32 3062306a36Sopenharmony_ci stfd reg, 0(r4) 3162306a36Sopenharmony_ci b 2f 3262306a36Sopenharmony_cireg = reg + 1 3362306a36Sopenharmony_ci .endr 3462306a36Sopenharmony_ci1: mflr r5 3562306a36Sopenharmony_ci add r5,r3,r5 3662306a36Sopenharmony_ci mtctr r5 3762306a36Sopenharmony_ci mtlr r0 3862306a36Sopenharmony_ci bctr 3962306a36Sopenharmony_ci2: MTMSRD(r6) 4062306a36Sopenharmony_ci isync 4162306a36Sopenharmony_ci blr 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Put the contents of *p into frN; N is in r3 and p is in r4. */ 4462306a36Sopenharmony_ci_GLOBAL(put_fpr) 4562306a36Sopenharmony_ci mflr r0 4662306a36Sopenharmony_ci mfmsr r6 4762306a36Sopenharmony_ci ori r7, r6, MSR_FP 4862306a36Sopenharmony_ci MTMSRD(r7) 4962306a36Sopenharmony_ci isync 5062306a36Sopenharmony_ci rlwinm r3,r3,3,0xf8 5162306a36Sopenharmony_ci bcl 20,31,1f 5262306a36Sopenharmony_cireg = 0 5362306a36Sopenharmony_ci .rept 32 5462306a36Sopenharmony_ci lfd reg, 0(r4) 5562306a36Sopenharmony_ci b 2f 5662306a36Sopenharmony_cireg = reg + 1 5762306a36Sopenharmony_ci .endr 5862306a36Sopenharmony_ci1: mflr r5 5962306a36Sopenharmony_ci add r5,r3,r5 6062306a36Sopenharmony_ci mtctr r5 6162306a36Sopenharmony_ci mtlr r0 6262306a36Sopenharmony_ci bctr 6362306a36Sopenharmony_ci2: MTMSRD(r6) 6462306a36Sopenharmony_ci isync 6562306a36Sopenharmony_ci blr 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC 6862306a36Sopenharmony_ci/* Get the contents of vrN into *p; N is in r3 and p is in r4. */ 6962306a36Sopenharmony_ci_GLOBAL(get_vr) 7062306a36Sopenharmony_ci mflr r0 7162306a36Sopenharmony_ci mfmsr r6 7262306a36Sopenharmony_ci oris r7, r6, MSR_VEC@h 7362306a36Sopenharmony_ci MTMSRD(r7) 7462306a36Sopenharmony_ci isync 7562306a36Sopenharmony_ci rlwinm r3,r3,3,0xf8 7662306a36Sopenharmony_ci bcl 20,31,1f 7762306a36Sopenharmony_cireg = 0 7862306a36Sopenharmony_ci .rept 32 7962306a36Sopenharmony_ci stvx reg, 0, r4 8062306a36Sopenharmony_ci b 2f 8162306a36Sopenharmony_cireg = reg + 1 8262306a36Sopenharmony_ci .endr 8362306a36Sopenharmony_ci1: mflr r5 8462306a36Sopenharmony_ci add r5,r3,r5 8562306a36Sopenharmony_ci mtctr r5 8662306a36Sopenharmony_ci mtlr r0 8762306a36Sopenharmony_ci bctr 8862306a36Sopenharmony_ci2: MTMSRD(r6) 8962306a36Sopenharmony_ci isync 9062306a36Sopenharmony_ci blr 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* Put the contents of *p into vrN; N is in r3 and p is in r4. */ 9362306a36Sopenharmony_ci_GLOBAL(put_vr) 9462306a36Sopenharmony_ci mflr r0 9562306a36Sopenharmony_ci mfmsr r6 9662306a36Sopenharmony_ci oris r7, r6, MSR_VEC@h 9762306a36Sopenharmony_ci MTMSRD(r7) 9862306a36Sopenharmony_ci isync 9962306a36Sopenharmony_ci rlwinm r3,r3,3,0xf8 10062306a36Sopenharmony_ci bcl 20,31,1f 10162306a36Sopenharmony_cireg = 0 10262306a36Sopenharmony_ci .rept 32 10362306a36Sopenharmony_ci lvx reg, 0, r4 10462306a36Sopenharmony_ci b 2f 10562306a36Sopenharmony_cireg = reg + 1 10662306a36Sopenharmony_ci .endr 10762306a36Sopenharmony_ci1: mflr r5 10862306a36Sopenharmony_ci add r5,r3,r5 10962306a36Sopenharmony_ci mtctr r5 11062306a36Sopenharmony_ci mtlr r0 11162306a36Sopenharmony_ci bctr 11262306a36Sopenharmony_ci2: MTMSRD(r6) 11362306a36Sopenharmony_ci isync 11462306a36Sopenharmony_ci blr 11562306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#ifdef CONFIG_VSX 11862306a36Sopenharmony_ci/* Get the contents of vsN into vs0; N is in r3. */ 11962306a36Sopenharmony_ci_GLOBAL(get_vsr) 12062306a36Sopenharmony_ci mflr r0 12162306a36Sopenharmony_ci rlwinm r3,r3,3,0x1f8 12262306a36Sopenharmony_ci bcl 20,31,1f 12362306a36Sopenharmony_ci blr /* vs0 is already in vs0 */ 12462306a36Sopenharmony_ci nop 12562306a36Sopenharmony_cireg = 1 12662306a36Sopenharmony_ci .rept 63 12762306a36Sopenharmony_ci XXLOR(0,reg,reg) 12862306a36Sopenharmony_ci blr 12962306a36Sopenharmony_cireg = reg + 1 13062306a36Sopenharmony_ci .endr 13162306a36Sopenharmony_ci1: mflr r5 13262306a36Sopenharmony_ci add r5,r3,r5 13362306a36Sopenharmony_ci mtctr r5 13462306a36Sopenharmony_ci mtlr r0 13562306a36Sopenharmony_ci bctr 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* Put the contents of vs0 into vsN; N is in r3. */ 13862306a36Sopenharmony_ci_GLOBAL(put_vsr) 13962306a36Sopenharmony_ci mflr r0 14062306a36Sopenharmony_ci rlwinm r3,r3,3,0x1f8 14162306a36Sopenharmony_ci bcl 20,31,1f 14262306a36Sopenharmony_ci blr /* v0 is already in v0 */ 14362306a36Sopenharmony_ci nop 14462306a36Sopenharmony_cireg = 1 14562306a36Sopenharmony_ci .rept 63 14662306a36Sopenharmony_ci XXLOR(reg,0,0) 14762306a36Sopenharmony_ci blr 14862306a36Sopenharmony_cireg = reg + 1 14962306a36Sopenharmony_ci .endr 15062306a36Sopenharmony_ci1: mflr r5 15162306a36Sopenharmony_ci add r5,r3,r5 15262306a36Sopenharmony_ci mtctr r5 15362306a36Sopenharmony_ci mtlr r0 15462306a36Sopenharmony_ci bctr 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* Load VSX reg N from vector doubleword *p. N is in r3, p in r4. */ 15762306a36Sopenharmony_ci_GLOBAL(load_vsrn) 15862306a36Sopenharmony_ci PPC_STLU r1,-STKFRM(r1) 15962306a36Sopenharmony_ci mflr r0 16062306a36Sopenharmony_ci PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) 16162306a36Sopenharmony_ci mfmsr r6 16262306a36Sopenharmony_ci oris r7,r6,MSR_VSX@h 16362306a36Sopenharmony_ci cmpwi cr7,r3,0 16462306a36Sopenharmony_ci li r8,STKFRM-16 16562306a36Sopenharmony_ci MTMSRD(r7) 16662306a36Sopenharmony_ci isync 16762306a36Sopenharmony_ci beq cr7,1f 16862306a36Sopenharmony_ci STXVD2X(0,R1,R8) 16962306a36Sopenharmony_ci1: LXVD2X(0,R0,R4) 17062306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 17162306a36Sopenharmony_ci XXSWAPD(0,0) 17262306a36Sopenharmony_ci#endif 17362306a36Sopenharmony_ci beq cr7,4f 17462306a36Sopenharmony_ci bl put_vsr 17562306a36Sopenharmony_ci LXVD2X(0,R1,R8) 17662306a36Sopenharmony_ci4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) 17762306a36Sopenharmony_ci mtlr r0 17862306a36Sopenharmony_ci MTMSRD(r6) 17962306a36Sopenharmony_ci isync 18062306a36Sopenharmony_ci addi r1,r1,STKFRM 18162306a36Sopenharmony_ci blr 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* Store VSX reg N to vector doubleword *p. N is in r3, p in r4. */ 18462306a36Sopenharmony_ci_GLOBAL(store_vsrn) 18562306a36Sopenharmony_ci PPC_STLU r1,-STKFRM(r1) 18662306a36Sopenharmony_ci mflr r0 18762306a36Sopenharmony_ci PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1) 18862306a36Sopenharmony_ci mfmsr r6 18962306a36Sopenharmony_ci oris r7,r6,MSR_VSX@h 19062306a36Sopenharmony_ci li r8,STKFRM-16 19162306a36Sopenharmony_ci MTMSRD(r7) 19262306a36Sopenharmony_ci isync 19362306a36Sopenharmony_ci STXVD2X(0,R1,R8) 19462306a36Sopenharmony_ci bl get_vsr 19562306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 19662306a36Sopenharmony_ci XXSWAPD(0,0) 19762306a36Sopenharmony_ci#endif 19862306a36Sopenharmony_ci STXVD2X(0,R0,R4) 19962306a36Sopenharmony_ci LXVD2X(0,R1,R8) 20062306a36Sopenharmony_ci PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) 20162306a36Sopenharmony_ci mtlr r0 20262306a36Sopenharmony_ci MTMSRD(r6) 20362306a36Sopenharmony_ci isync 20462306a36Sopenharmony_ci mr r3,r9 20562306a36Sopenharmony_ci addi r1,r1,STKFRM 20662306a36Sopenharmony_ci blr 20762306a36Sopenharmony_ci#endif /* CONFIG_VSX */ 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* Convert single-precision to double, without disturbing FPRs. */ 21062306a36Sopenharmony_ci/* conv_sp_to_dp(float *sp, double *dp) */ 21162306a36Sopenharmony_ci_GLOBAL(conv_sp_to_dp) 21262306a36Sopenharmony_ci mfmsr r6 21362306a36Sopenharmony_ci ori r7, r6, MSR_FP 21462306a36Sopenharmony_ci MTMSRD(r7) 21562306a36Sopenharmony_ci isync 21662306a36Sopenharmony_ci stfd fr0, -16(r1) 21762306a36Sopenharmony_ci lfs fr0, 0(r3) 21862306a36Sopenharmony_ci stfd fr0, 0(r4) 21962306a36Sopenharmony_ci lfd fr0, -16(r1) 22062306a36Sopenharmony_ci MTMSRD(r6) 22162306a36Sopenharmony_ci isync 22262306a36Sopenharmony_ci blr 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/* Convert single-precision to double, without disturbing FPRs. */ 22562306a36Sopenharmony_ci/* conv_sp_to_dp(double *dp, float *sp) */ 22662306a36Sopenharmony_ci_GLOBAL(conv_dp_to_sp) 22762306a36Sopenharmony_ci mfmsr r6 22862306a36Sopenharmony_ci ori r7, r6, MSR_FP 22962306a36Sopenharmony_ci MTMSRD(r7) 23062306a36Sopenharmony_ci isync 23162306a36Sopenharmony_ci stfd fr0, -16(r1) 23262306a36Sopenharmony_ci lfd fr0, 0(r3) 23362306a36Sopenharmony_ci stfs fr0, 0(r4) 23462306a36Sopenharmony_ci lfd fr0, -16(r1) 23562306a36Sopenharmony_ci MTMSRD(r6) 23662306a36Sopenharmony_ci isync 23762306a36Sopenharmony_ci blr 238