162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 1999 Eddie C. Dost (ecd@atecom.com) 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include <linux/sched.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/uaccess.h> 1062306a36Sopenharmony_ci#include <asm/reg.h> 1162306a36Sopenharmony_ci#include <asm/switch_to.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/sfp-machine.h> 1462306a36Sopenharmony_ci#include <math-emu/double.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define FLOATFUNC(x) extern int x(void *, void *, void *, void *) 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* The instructions list which may be not implemented by a hardware FPU */ 1962306a36Sopenharmony_ciFLOATFUNC(fre); 2062306a36Sopenharmony_ciFLOATFUNC(frsqrtes); 2162306a36Sopenharmony_ciFLOATFUNC(fsqrt); 2262306a36Sopenharmony_ciFLOATFUNC(fsqrts); 2362306a36Sopenharmony_ciFLOATFUNC(mtfsf); 2462306a36Sopenharmony_ciFLOATFUNC(mtfsfi); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#ifdef CONFIG_MATH_EMULATION_HW_UNIMPLEMENTED 2762306a36Sopenharmony_ci#undef FLOATFUNC 2862306a36Sopenharmony_ci#define FLOATFUNC(x) static inline int x(void *op1, void *op2, void *op3, \ 2962306a36Sopenharmony_ci void *op4) { return 0; } 3062306a36Sopenharmony_ci#endif 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciFLOATFUNC(fadd); 3362306a36Sopenharmony_ciFLOATFUNC(fadds); 3462306a36Sopenharmony_ciFLOATFUNC(fdiv); 3562306a36Sopenharmony_ciFLOATFUNC(fdivs); 3662306a36Sopenharmony_ciFLOATFUNC(fmul); 3762306a36Sopenharmony_ciFLOATFUNC(fmuls); 3862306a36Sopenharmony_ciFLOATFUNC(fsub); 3962306a36Sopenharmony_ciFLOATFUNC(fsubs); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciFLOATFUNC(fmadd); 4262306a36Sopenharmony_ciFLOATFUNC(fmadds); 4362306a36Sopenharmony_ciFLOATFUNC(fmsub); 4462306a36Sopenharmony_ciFLOATFUNC(fmsubs); 4562306a36Sopenharmony_ciFLOATFUNC(fnmadd); 4662306a36Sopenharmony_ciFLOATFUNC(fnmadds); 4762306a36Sopenharmony_ciFLOATFUNC(fnmsub); 4862306a36Sopenharmony_ciFLOATFUNC(fnmsubs); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciFLOATFUNC(fctiw); 5162306a36Sopenharmony_ciFLOATFUNC(fctiwz); 5262306a36Sopenharmony_ciFLOATFUNC(frsp); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciFLOATFUNC(fcmpo); 5562306a36Sopenharmony_ciFLOATFUNC(fcmpu); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciFLOATFUNC(mcrfs); 5862306a36Sopenharmony_ciFLOATFUNC(mffs); 5962306a36Sopenharmony_ciFLOATFUNC(mtfsb0); 6062306a36Sopenharmony_ciFLOATFUNC(mtfsb1); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciFLOATFUNC(lfd); 6362306a36Sopenharmony_ciFLOATFUNC(lfs); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciFLOATFUNC(stfd); 6662306a36Sopenharmony_ciFLOATFUNC(stfs); 6762306a36Sopenharmony_ciFLOATFUNC(stfiwx); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciFLOATFUNC(fabs); 7062306a36Sopenharmony_ciFLOATFUNC(fmr); 7162306a36Sopenharmony_ciFLOATFUNC(fnabs); 7262306a36Sopenharmony_ciFLOATFUNC(fneg); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Optional */ 7562306a36Sopenharmony_ciFLOATFUNC(fres); 7662306a36Sopenharmony_ciFLOATFUNC(frsqrte); 7762306a36Sopenharmony_ciFLOATFUNC(fsel); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define OP31 0x1f /* 31 */ 8162306a36Sopenharmony_ci#define LFS 0x30 /* 48 */ 8262306a36Sopenharmony_ci#define LFSU 0x31 /* 49 */ 8362306a36Sopenharmony_ci#define LFD 0x32 /* 50 */ 8462306a36Sopenharmony_ci#define LFDU 0x33 /* 51 */ 8562306a36Sopenharmony_ci#define STFS 0x34 /* 52 */ 8662306a36Sopenharmony_ci#define STFSU 0x35 /* 53 */ 8762306a36Sopenharmony_ci#define STFD 0x36 /* 54 */ 8862306a36Sopenharmony_ci#define STFDU 0x37 /* 55 */ 8962306a36Sopenharmony_ci#define OP59 0x3b /* 59 */ 9062306a36Sopenharmony_ci#define OP63 0x3f /* 63 */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* Opcode 31: */ 9362306a36Sopenharmony_ci/* X-Form: */ 9462306a36Sopenharmony_ci#define LFSX 0x217 /* 535 */ 9562306a36Sopenharmony_ci#define LFSUX 0x237 /* 567 */ 9662306a36Sopenharmony_ci#define LFDX 0x257 /* 599 */ 9762306a36Sopenharmony_ci#define LFDUX 0x277 /* 631 */ 9862306a36Sopenharmony_ci#define STFSX 0x297 /* 663 */ 9962306a36Sopenharmony_ci#define STFSUX 0x2b7 /* 695 */ 10062306a36Sopenharmony_ci#define STFDX 0x2d7 /* 727 */ 10162306a36Sopenharmony_ci#define STFDUX 0x2f7 /* 759 */ 10262306a36Sopenharmony_ci#define STFIWX 0x3d7 /* 983 */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Opcode 59: */ 10562306a36Sopenharmony_ci/* A-Form: */ 10662306a36Sopenharmony_ci#define FDIVS 0x012 /* 18 */ 10762306a36Sopenharmony_ci#define FSUBS 0x014 /* 20 */ 10862306a36Sopenharmony_ci#define FADDS 0x015 /* 21 */ 10962306a36Sopenharmony_ci#define FSQRTS 0x016 /* 22 */ 11062306a36Sopenharmony_ci#define FRES 0x018 /* 24 */ 11162306a36Sopenharmony_ci#define FMULS 0x019 /* 25 */ 11262306a36Sopenharmony_ci#define FRSQRTES 0x01a /* 26 */ 11362306a36Sopenharmony_ci#define FMSUBS 0x01c /* 28 */ 11462306a36Sopenharmony_ci#define FMADDS 0x01d /* 29 */ 11562306a36Sopenharmony_ci#define FNMSUBS 0x01e /* 30 */ 11662306a36Sopenharmony_ci#define FNMADDS 0x01f /* 31 */ 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* Opcode 63: */ 11962306a36Sopenharmony_ci/* A-Form: */ 12062306a36Sopenharmony_ci#define FDIV 0x012 /* 18 */ 12162306a36Sopenharmony_ci#define FSUB 0x014 /* 20 */ 12262306a36Sopenharmony_ci#define FADD 0x015 /* 21 */ 12362306a36Sopenharmony_ci#define FSQRT 0x016 /* 22 */ 12462306a36Sopenharmony_ci#define FSEL 0x017 /* 23 */ 12562306a36Sopenharmony_ci#define FRE 0x018 /* 24 */ 12662306a36Sopenharmony_ci#define FMUL 0x019 /* 25 */ 12762306a36Sopenharmony_ci#define FRSQRTE 0x01a /* 26 */ 12862306a36Sopenharmony_ci#define FMSUB 0x01c /* 28 */ 12962306a36Sopenharmony_ci#define FMADD 0x01d /* 29 */ 13062306a36Sopenharmony_ci#define FNMSUB 0x01e /* 30 */ 13162306a36Sopenharmony_ci#define FNMADD 0x01f /* 31 */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* X-Form: */ 13462306a36Sopenharmony_ci#define FCMPU 0x000 /* 0 */ 13562306a36Sopenharmony_ci#define FRSP 0x00c /* 12 */ 13662306a36Sopenharmony_ci#define FCTIW 0x00e /* 14 */ 13762306a36Sopenharmony_ci#define FCTIWZ 0x00f /* 15 */ 13862306a36Sopenharmony_ci#define FCMPO 0x020 /* 32 */ 13962306a36Sopenharmony_ci#define MTFSB1 0x026 /* 38 */ 14062306a36Sopenharmony_ci#define FNEG 0x028 /* 40 */ 14162306a36Sopenharmony_ci#define MCRFS 0x040 /* 64 */ 14262306a36Sopenharmony_ci#define MTFSB0 0x046 /* 70 */ 14362306a36Sopenharmony_ci#define FMR 0x048 /* 72 */ 14462306a36Sopenharmony_ci#define MTFSFI 0x086 /* 134 */ 14562306a36Sopenharmony_ci#define FNABS 0x088 /* 136 */ 14662306a36Sopenharmony_ci#define FABS 0x108 /* 264 */ 14762306a36Sopenharmony_ci#define MFFS 0x247 /* 583 */ 14862306a36Sopenharmony_ci#define MTFSF 0x2c7 /* 711 */ 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define AB 2 15262306a36Sopenharmony_ci#define AC 3 15362306a36Sopenharmony_ci#define ABC 4 15462306a36Sopenharmony_ci#define D 5 15562306a36Sopenharmony_ci#define DU 6 15662306a36Sopenharmony_ci#define X 7 15762306a36Sopenharmony_ci#define XA 8 15862306a36Sopenharmony_ci#define XB 9 15962306a36Sopenharmony_ci#define XCR 11 16062306a36Sopenharmony_ci#define XCRB 12 16162306a36Sopenharmony_ci#define XCRI 13 16262306a36Sopenharmony_ci#define XCRL 16 16362306a36Sopenharmony_ci#define XE 14 16462306a36Sopenharmony_ci#define XEU 15 16562306a36Sopenharmony_ci#define XFLB 10 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int 16862306a36Sopenharmony_cirecord_exception(struct pt_regs *regs, int eflag) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci u32 fpscr; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci fpscr = __FPU_FPSCR; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (eflag) { 17562306a36Sopenharmony_ci fpscr |= FPSCR_FX; 17662306a36Sopenharmony_ci if (eflag & EFLAG_OVERFLOW) 17762306a36Sopenharmony_ci fpscr |= FPSCR_OX; 17862306a36Sopenharmony_ci if (eflag & EFLAG_UNDERFLOW) 17962306a36Sopenharmony_ci fpscr |= FPSCR_UX; 18062306a36Sopenharmony_ci if (eflag & EFLAG_DIVZERO) 18162306a36Sopenharmony_ci fpscr |= FPSCR_ZX; 18262306a36Sopenharmony_ci if (eflag & EFLAG_INEXACT) 18362306a36Sopenharmony_ci fpscr |= FPSCR_XX; 18462306a36Sopenharmony_ci if (eflag & EFLAG_INVALID) 18562306a36Sopenharmony_ci fpscr |= FPSCR_VX; 18662306a36Sopenharmony_ci if (eflag & EFLAG_VXSNAN) 18762306a36Sopenharmony_ci fpscr |= FPSCR_VXSNAN; 18862306a36Sopenharmony_ci if (eflag & EFLAG_VXISI) 18962306a36Sopenharmony_ci fpscr |= FPSCR_VXISI; 19062306a36Sopenharmony_ci if (eflag & EFLAG_VXIDI) 19162306a36Sopenharmony_ci fpscr |= FPSCR_VXIDI; 19262306a36Sopenharmony_ci if (eflag & EFLAG_VXZDZ) 19362306a36Sopenharmony_ci fpscr |= FPSCR_VXZDZ; 19462306a36Sopenharmony_ci if (eflag & EFLAG_VXIMZ) 19562306a36Sopenharmony_ci fpscr |= FPSCR_VXIMZ; 19662306a36Sopenharmony_ci if (eflag & EFLAG_VXVC) 19762306a36Sopenharmony_ci fpscr |= FPSCR_VXVC; 19862306a36Sopenharmony_ci if (eflag & EFLAG_VXSOFT) 19962306a36Sopenharmony_ci fpscr |= FPSCR_VXSOFT; 20062306a36Sopenharmony_ci if (eflag & EFLAG_VXSQRT) 20162306a36Sopenharmony_ci fpscr |= FPSCR_VXSQRT; 20262306a36Sopenharmony_ci if (eflag & EFLAG_VXCVI) 20362306a36Sopenharmony_ci fpscr |= FPSCR_VXCVI; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci// fpscr &= ~(FPSCR_VX); 20762306a36Sopenharmony_ci if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | 20862306a36Sopenharmony_ci FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | 20962306a36Sopenharmony_ci FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI)) 21062306a36Sopenharmony_ci fpscr |= FPSCR_VX; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci fpscr &= ~(FPSCR_FEX); 21362306a36Sopenharmony_ci if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) || 21462306a36Sopenharmony_ci ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) || 21562306a36Sopenharmony_ci ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) || 21662306a36Sopenharmony_ci ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) || 21762306a36Sopenharmony_ci ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE))) 21862306a36Sopenharmony_ci fpscr |= FPSCR_FEX; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci __FPU_FPSCR = fpscr; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return (fpscr & FPSCR_FEX) ? 1 : 0; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ciint 22662306a36Sopenharmony_cido_mathemu(struct pt_regs *regs) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci void *op0 = NULL, *op1 = NULL, *op2 = NULL, *op3 = NULL; 22962306a36Sopenharmony_ci unsigned long pc = regs->nip; 23062306a36Sopenharmony_ci signed short sdisp; 23162306a36Sopenharmony_ci u32 insn = 0; 23262306a36Sopenharmony_ci int idx = 0; 23362306a36Sopenharmony_ci int (*func)(void *, void *, void *, void *); 23462306a36Sopenharmony_ci int type = 0; 23562306a36Sopenharmony_ci int eflag, trap; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (get_user(insn, (u32 __user *)pc)) 23862306a36Sopenharmony_ci return -EFAULT; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci switch (insn >> 26) { 24162306a36Sopenharmony_ci case LFS: func = lfs; type = D; break; 24262306a36Sopenharmony_ci case LFSU: func = lfs; type = DU; break; 24362306a36Sopenharmony_ci case LFD: func = lfd; type = D; break; 24462306a36Sopenharmony_ci case LFDU: func = lfd; type = DU; break; 24562306a36Sopenharmony_ci case STFS: func = stfs; type = D; break; 24662306a36Sopenharmony_ci case STFSU: func = stfs; type = DU; break; 24762306a36Sopenharmony_ci case STFD: func = stfd; type = D; break; 24862306a36Sopenharmony_ci case STFDU: func = stfd; type = DU; break; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci case OP31: 25162306a36Sopenharmony_ci switch ((insn >> 1) & 0x3ff) { 25262306a36Sopenharmony_ci case LFSX: func = lfs; type = XE; break; 25362306a36Sopenharmony_ci case LFSUX: func = lfs; type = XEU; break; 25462306a36Sopenharmony_ci case LFDX: func = lfd; type = XE; break; 25562306a36Sopenharmony_ci case LFDUX: func = lfd; type = XEU; break; 25662306a36Sopenharmony_ci case STFSX: func = stfs; type = XE; break; 25762306a36Sopenharmony_ci case STFSUX: func = stfs; type = XEU; break; 25862306a36Sopenharmony_ci case STFDX: func = stfd; type = XE; break; 25962306a36Sopenharmony_ci case STFDUX: func = stfd; type = XEU; break; 26062306a36Sopenharmony_ci case STFIWX: func = stfiwx; type = XE; break; 26162306a36Sopenharmony_ci default: 26262306a36Sopenharmony_ci goto illegal; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci break; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci case OP59: 26762306a36Sopenharmony_ci switch ((insn >> 1) & 0x1f) { 26862306a36Sopenharmony_ci case FDIVS: func = fdivs; type = AB; break; 26962306a36Sopenharmony_ci case FSUBS: func = fsubs; type = AB; break; 27062306a36Sopenharmony_ci case FADDS: func = fadds; type = AB; break; 27162306a36Sopenharmony_ci case FSQRTS: func = fsqrts; type = XB; break; 27262306a36Sopenharmony_ci case FRES: func = fres; type = XB; break; 27362306a36Sopenharmony_ci case FMULS: func = fmuls; type = AC; break; 27462306a36Sopenharmony_ci case FRSQRTES: func = frsqrtes;type = XB; break; 27562306a36Sopenharmony_ci case FMSUBS: func = fmsubs; type = ABC; break; 27662306a36Sopenharmony_ci case FMADDS: func = fmadds; type = ABC; break; 27762306a36Sopenharmony_ci case FNMSUBS: func = fnmsubs; type = ABC; break; 27862306a36Sopenharmony_ci case FNMADDS: func = fnmadds; type = ABC; break; 27962306a36Sopenharmony_ci default: 28062306a36Sopenharmony_ci goto illegal; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci case OP63: 28562306a36Sopenharmony_ci if (insn & 0x20) { 28662306a36Sopenharmony_ci switch ((insn >> 1) & 0x1f) { 28762306a36Sopenharmony_ci case FDIV: func = fdiv; type = AB; break; 28862306a36Sopenharmony_ci case FSUB: func = fsub; type = AB; break; 28962306a36Sopenharmony_ci case FADD: func = fadd; type = AB; break; 29062306a36Sopenharmony_ci case FSQRT: func = fsqrt; type = XB; break; 29162306a36Sopenharmony_ci case FRE: func = fre; type = XB; break; 29262306a36Sopenharmony_ci case FSEL: func = fsel; type = ABC; break; 29362306a36Sopenharmony_ci case FMUL: func = fmul; type = AC; break; 29462306a36Sopenharmony_ci case FRSQRTE: func = frsqrte; type = XB; break; 29562306a36Sopenharmony_ci case FMSUB: func = fmsub; type = ABC; break; 29662306a36Sopenharmony_ci case FMADD: func = fmadd; type = ABC; break; 29762306a36Sopenharmony_ci case FNMSUB: func = fnmsub; type = ABC; break; 29862306a36Sopenharmony_ci case FNMADD: func = fnmadd; type = ABC; break; 29962306a36Sopenharmony_ci default: 30062306a36Sopenharmony_ci goto illegal; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci switch ((insn >> 1) & 0x3ff) { 30662306a36Sopenharmony_ci case FCMPU: func = fcmpu; type = XCR; break; 30762306a36Sopenharmony_ci case FRSP: func = frsp; type = XB; break; 30862306a36Sopenharmony_ci case FCTIW: func = fctiw; type = XB; break; 30962306a36Sopenharmony_ci case FCTIWZ: func = fctiwz; type = XB; break; 31062306a36Sopenharmony_ci case FCMPO: func = fcmpo; type = XCR; break; 31162306a36Sopenharmony_ci case MTFSB1: func = mtfsb1; type = XCRB; break; 31262306a36Sopenharmony_ci case FNEG: func = fneg; type = XB; break; 31362306a36Sopenharmony_ci case MCRFS: func = mcrfs; type = XCRL; break; 31462306a36Sopenharmony_ci case MTFSB0: func = mtfsb0; type = XCRB; break; 31562306a36Sopenharmony_ci case FMR: func = fmr; type = XB; break; 31662306a36Sopenharmony_ci case MTFSFI: func = mtfsfi; type = XCRI; break; 31762306a36Sopenharmony_ci case FNABS: func = fnabs; type = XB; break; 31862306a36Sopenharmony_ci case FABS: func = fabs; type = XB; break; 31962306a36Sopenharmony_ci case MFFS: func = mffs; type = X; break; 32062306a36Sopenharmony_ci case MTFSF: func = mtfsf; type = XFLB; break; 32162306a36Sopenharmony_ci default: 32262306a36Sopenharmony_ci goto illegal; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci default: 32762306a36Sopenharmony_ci goto illegal; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci switch (type) { 33162306a36Sopenharmony_ci case AB: 33262306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 33362306a36Sopenharmony_ci op1 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f); 33462306a36Sopenharmony_ci op2 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f); 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci case AC: 33862306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 33962306a36Sopenharmony_ci op1 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f); 34062306a36Sopenharmony_ci op2 = (void *)¤t->thread.TS_FPR((insn >> 6) & 0x1f); 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci case ABC: 34462306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 34562306a36Sopenharmony_ci op1 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f); 34662306a36Sopenharmony_ci op2 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f); 34762306a36Sopenharmony_ci op3 = (void *)¤t->thread.TS_FPR((insn >> 6) & 0x1f); 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci case D: 35162306a36Sopenharmony_ci idx = (insn >> 16) & 0x1f; 35262306a36Sopenharmony_ci sdisp = (insn & 0xffff); 35362306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 35462306a36Sopenharmony_ci op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci case DU: 35862306a36Sopenharmony_ci idx = (insn >> 16) & 0x1f; 35962306a36Sopenharmony_ci if (!idx) 36062306a36Sopenharmony_ci goto illegal; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci sdisp = (insn & 0xffff); 36362306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 36462306a36Sopenharmony_ci op1 = (void *)(regs->gpr[idx] + sdisp); 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci case X: 36862306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci case XA: 37262306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 37362306a36Sopenharmony_ci op1 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f); 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci case XB: 37762306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 37862306a36Sopenharmony_ci op1 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f); 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci case XE: 38262306a36Sopenharmony_ci idx = (insn >> 16) & 0x1f; 38362306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 38462306a36Sopenharmony_ci op1 = (void *)((idx ? regs->gpr[idx] : 0) 38562306a36Sopenharmony_ci + regs->gpr[(insn >> 11) & 0x1f]); 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci case XEU: 38962306a36Sopenharmony_ci idx = (insn >> 16) & 0x1f; 39062306a36Sopenharmony_ci if (!idx) 39162306a36Sopenharmony_ci goto illegal; 39262306a36Sopenharmony_ci op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); 39362306a36Sopenharmony_ci op1 = (void *)(regs->gpr[idx] 39462306a36Sopenharmony_ci + regs->gpr[(insn >> 11) & 0x1f]); 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci case XCR: 39862306a36Sopenharmony_ci op0 = (void *)®s->ccr; 39962306a36Sopenharmony_ci op1 = (void *)(long)((insn >> 23) & 0x7); 40062306a36Sopenharmony_ci op2 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f); 40162306a36Sopenharmony_ci op3 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f); 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci case XCRL: 40562306a36Sopenharmony_ci op0 = (void *)®s->ccr; 40662306a36Sopenharmony_ci op1 = (void *)(long)((insn >> 23) & 0x7); 40762306a36Sopenharmony_ci op2 = (void *)(long)((insn >> 18) & 0x7); 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci case XCRB: 41162306a36Sopenharmony_ci op0 = (void *)(long)((insn >> 21) & 0x1f); 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci case XCRI: 41562306a36Sopenharmony_ci op0 = (void *)(long)((insn >> 23) & 0x7); 41662306a36Sopenharmony_ci op1 = (void *)(long)((insn >> 12) & 0xf); 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci case XFLB: 42062306a36Sopenharmony_ci op0 = (void *)(long)((insn >> 17) & 0xff); 42162306a36Sopenharmony_ci op1 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f); 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci default: 42562306a36Sopenharmony_ci goto illegal; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* 42962306a36Sopenharmony_ci * If we support a HW FPU, we need to ensure the FP state 43062306a36Sopenharmony_ci * is flushed into the thread_struct before attempting 43162306a36Sopenharmony_ci * emulation 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_ci flush_fp_to_thread(current); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci eflag = func(op0, op1, op2, op3); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (insn & 1) { 43862306a36Sopenharmony_ci regs->ccr &= ~(0x0f000000); 43962306a36Sopenharmony_ci regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci trap = record_exception(regs, eflag); 44362306a36Sopenharmony_ci if (trap) 44462306a36Sopenharmony_ci return 1; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci switch (type) { 44762306a36Sopenharmony_ci case DU: 44862306a36Sopenharmony_ci case XEU: 44962306a36Sopenharmony_ci regs->gpr[idx] = (unsigned long)op1; 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci default: 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci regs_add_return_ip(regs, 4); 45762306a36Sopenharmony_ci return 0; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ciillegal: 46062306a36Sopenharmony_ci return -ENOSYS; 46162306a36Sopenharmony_ci} 462