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 *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
33362306a36Sopenharmony_ci		op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
33462306a36Sopenharmony_ci		op2 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	case AC:
33862306a36Sopenharmony_ci		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
33962306a36Sopenharmony_ci		op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
34062306a36Sopenharmony_ci		op2 = (void *)&current->thread.TS_FPR((insn >>  6) & 0x1f);
34162306a36Sopenharmony_ci		break;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	case ABC:
34462306a36Sopenharmony_ci		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
34562306a36Sopenharmony_ci		op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
34662306a36Sopenharmony_ci		op2 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
34762306a36Sopenharmony_ci		op3 = (void *)&current->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 *)&current->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 *)&current->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 *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	case XA:
37262306a36Sopenharmony_ci		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
37362306a36Sopenharmony_ci		op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
37462306a36Sopenharmony_ci		break;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	case XB:
37762306a36Sopenharmony_ci		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
37862306a36Sopenharmony_ci		op1 = (void *)&current->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 *)&current->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 *)&current->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 *)&regs->ccr;
39962306a36Sopenharmony_ci		op1 = (void *)(long)((insn >> 23) & 0x7);
40062306a36Sopenharmony_ci		op2 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
40162306a36Sopenharmony_ci		op3 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
40262306a36Sopenharmony_ci		break;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	case XCRL:
40562306a36Sopenharmony_ci		op0 = (void *)&regs->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 *)&current->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