18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (C) 2005-2018 Andes Technology Corporation
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <asm/bitfield.h>
58c2ecf20Sopenharmony_ci#include <asm/uaccess.h>
68c2ecf20Sopenharmony_ci#include <asm/sfp-machine.h>
78c2ecf20Sopenharmony_ci#include <asm/fpuemu.h>
88c2ecf20Sopenharmony_ci#include <asm/nds32_fpu_inst.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define DPFROMREG(dp, x) (dp = (void *)((unsigned long *)fpu_reg + 2*x))
118c2ecf20Sopenharmony_ci#ifdef __NDS32_EL__
128c2ecf20Sopenharmony_ci#define SPFROMREG(sp, x)\
138c2ecf20Sopenharmony_ci	((sp) = (void *)((unsigned long *)fpu_reg + (x^1)))
148c2ecf20Sopenharmony_ci#else
158c2ecf20Sopenharmony_ci#define SPFROMREG(sp, x) ((sp) = (void *)((unsigned long *)fpu_reg + x))
168c2ecf20Sopenharmony_ci#endif
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define DEF3OP(name, p, f1, f2) \
198c2ecf20Sopenharmony_civoid fpemu_##name##p(void *ft, void *fa, void *fb) \
208c2ecf20Sopenharmony_ci{ \
218c2ecf20Sopenharmony_ci	f1(fa, fa, fb); \
228c2ecf20Sopenharmony_ci	f2(ft, ft, fa); \
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define DEF3OPNEG(name, p, f1, f2, f3) \
268c2ecf20Sopenharmony_civoid fpemu_##name##p(void *ft, void *fa, void *fb) \
278c2ecf20Sopenharmony_ci{ \
288c2ecf20Sopenharmony_ci	f1(fa, fa, fb); \
298c2ecf20Sopenharmony_ci	f2(ft, ft, fa); \
308c2ecf20Sopenharmony_ci	f3(ft, ft); \
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ciDEF3OP(fmadd, s, fmuls, fadds);
338c2ecf20Sopenharmony_ciDEF3OP(fmsub, s, fmuls, fsubs);
348c2ecf20Sopenharmony_ciDEF3OP(fmadd, d, fmuld, faddd);
358c2ecf20Sopenharmony_ciDEF3OP(fmsub, d, fmuld, fsubd);
368c2ecf20Sopenharmony_ciDEF3OPNEG(fnmadd, s, fmuls, fadds, fnegs);
378c2ecf20Sopenharmony_ciDEF3OPNEG(fnmsub, s, fmuls, fsubs, fnegs);
388c2ecf20Sopenharmony_ciDEF3OPNEG(fnmadd, d, fmuld, faddd, fnegd);
398c2ecf20Sopenharmony_ciDEF3OPNEG(fnmsub, d, fmuld, fsubd, fnegd);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic const unsigned char cmptab[8] = {
428c2ecf20Sopenharmony_ci	SF_CEQ,
438c2ecf20Sopenharmony_ci	SF_CEQ,
448c2ecf20Sopenharmony_ci	SF_CLT,
458c2ecf20Sopenharmony_ci	SF_CLT,
468c2ecf20Sopenharmony_ci	SF_CLT | SF_CEQ,
478c2ecf20Sopenharmony_ci	SF_CLT | SF_CEQ,
488c2ecf20Sopenharmony_ci	SF_CUN,
498c2ecf20Sopenharmony_ci	SF_CUN
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cienum ARGTYPE {
538c2ecf20Sopenharmony_ci	S1S = 1,
548c2ecf20Sopenharmony_ci	S2S,
558c2ecf20Sopenharmony_ci	S1D,
568c2ecf20Sopenharmony_ci	CS,
578c2ecf20Sopenharmony_ci	D1D,
588c2ecf20Sopenharmony_ci	D2D,
598c2ecf20Sopenharmony_ci	D1S,
608c2ecf20Sopenharmony_ci	CD
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ciunion func_t {
638c2ecf20Sopenharmony_ci	void (*t)(void *ft, void *fa, void *fb);
648c2ecf20Sopenharmony_ci	void (*b)(void *ft, void *fa);
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci/*
678c2ecf20Sopenharmony_ci * Emulate a single FPU arithmetic instruction.
688c2ecf20Sopenharmony_ci */
698c2ecf20Sopenharmony_cistatic int fpu_emu(struct fpu_struct *fpu_reg, unsigned long insn)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	int rfmt;		/* resulting format */
728c2ecf20Sopenharmony_ci	union func_t func;
738c2ecf20Sopenharmony_ci	int ftype = 0;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	switch (rfmt = NDS32Insn_OPCODE_COP0(insn)) {
768c2ecf20Sopenharmony_ci	case fs1_op:{
778c2ecf20Sopenharmony_ci			switch (NDS32Insn_OPCODE_BIT69(insn)) {
788c2ecf20Sopenharmony_ci			case fadds_op:
798c2ecf20Sopenharmony_ci				func.t = fadds;
808c2ecf20Sopenharmony_ci				ftype = S2S;
818c2ecf20Sopenharmony_ci				break;
828c2ecf20Sopenharmony_ci			case fsubs_op:
838c2ecf20Sopenharmony_ci				func.t = fsubs;
848c2ecf20Sopenharmony_ci				ftype = S2S;
858c2ecf20Sopenharmony_ci				break;
868c2ecf20Sopenharmony_ci			case fmadds_op:
878c2ecf20Sopenharmony_ci				func.t = fpemu_fmadds;
888c2ecf20Sopenharmony_ci				ftype = S2S;
898c2ecf20Sopenharmony_ci				break;
908c2ecf20Sopenharmony_ci			case fmsubs_op:
918c2ecf20Sopenharmony_ci				func.t = fpemu_fmsubs;
928c2ecf20Sopenharmony_ci				ftype = S2S;
938c2ecf20Sopenharmony_ci				break;
948c2ecf20Sopenharmony_ci			case fnmadds_op:
958c2ecf20Sopenharmony_ci				func.t = fpemu_fnmadds;
968c2ecf20Sopenharmony_ci				ftype = S2S;
978c2ecf20Sopenharmony_ci				break;
988c2ecf20Sopenharmony_ci			case fnmsubs_op:
998c2ecf20Sopenharmony_ci				func.t = fpemu_fnmsubs;
1008c2ecf20Sopenharmony_ci				ftype = S2S;
1018c2ecf20Sopenharmony_ci				break;
1028c2ecf20Sopenharmony_ci			case fmuls_op:
1038c2ecf20Sopenharmony_ci				func.t = fmuls;
1048c2ecf20Sopenharmony_ci				ftype = S2S;
1058c2ecf20Sopenharmony_ci				break;
1068c2ecf20Sopenharmony_ci			case fdivs_op:
1078c2ecf20Sopenharmony_ci				func.t = fdivs;
1088c2ecf20Sopenharmony_ci				ftype = S2S;
1098c2ecf20Sopenharmony_ci				break;
1108c2ecf20Sopenharmony_ci			case fs1_f2op_op:
1118c2ecf20Sopenharmony_ci				switch (NDS32Insn_OPCODE_BIT1014(insn)) {
1128c2ecf20Sopenharmony_ci				case fs2d_op:
1138c2ecf20Sopenharmony_ci					func.b = fs2d;
1148c2ecf20Sopenharmony_ci					ftype = S1D;
1158c2ecf20Sopenharmony_ci					break;
1168c2ecf20Sopenharmony_ci				case fs2si_op:
1178c2ecf20Sopenharmony_ci					func.b = fs2si;
1188c2ecf20Sopenharmony_ci					ftype = S1S;
1198c2ecf20Sopenharmony_ci					break;
1208c2ecf20Sopenharmony_ci				case fs2si_z_op:
1218c2ecf20Sopenharmony_ci					func.b = fs2si_z;
1228c2ecf20Sopenharmony_ci					ftype = S1S;
1238c2ecf20Sopenharmony_ci					break;
1248c2ecf20Sopenharmony_ci				case fs2ui_op:
1258c2ecf20Sopenharmony_ci					func.b = fs2ui;
1268c2ecf20Sopenharmony_ci					ftype = S1S;
1278c2ecf20Sopenharmony_ci					break;
1288c2ecf20Sopenharmony_ci				case fs2ui_z_op:
1298c2ecf20Sopenharmony_ci					func.b = fs2ui_z;
1308c2ecf20Sopenharmony_ci					ftype = S1S;
1318c2ecf20Sopenharmony_ci					break;
1328c2ecf20Sopenharmony_ci				case fsi2s_op:
1338c2ecf20Sopenharmony_ci					func.b = fsi2s;
1348c2ecf20Sopenharmony_ci					ftype = S1S;
1358c2ecf20Sopenharmony_ci					break;
1368c2ecf20Sopenharmony_ci				case fui2s_op:
1378c2ecf20Sopenharmony_ci					func.b = fui2s;
1388c2ecf20Sopenharmony_ci					ftype = S1S;
1398c2ecf20Sopenharmony_ci					break;
1408c2ecf20Sopenharmony_ci				case fsqrts_op:
1418c2ecf20Sopenharmony_ci					func.b = fsqrts;
1428c2ecf20Sopenharmony_ci					ftype = S1S;
1438c2ecf20Sopenharmony_ci					break;
1448c2ecf20Sopenharmony_ci				default:
1458c2ecf20Sopenharmony_ci					return SIGILL;
1468c2ecf20Sopenharmony_ci				}
1478c2ecf20Sopenharmony_ci				break;
1488c2ecf20Sopenharmony_ci			default:
1498c2ecf20Sopenharmony_ci				return SIGILL;
1508c2ecf20Sopenharmony_ci			}
1518c2ecf20Sopenharmony_ci			break;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci	case fs2_op:
1548c2ecf20Sopenharmony_ci		switch (NDS32Insn_OPCODE_BIT69(insn)) {
1558c2ecf20Sopenharmony_ci		case fcmpeqs_op:
1568c2ecf20Sopenharmony_ci		case fcmpeqs_e_op:
1578c2ecf20Sopenharmony_ci		case fcmplts_op:
1588c2ecf20Sopenharmony_ci		case fcmplts_e_op:
1598c2ecf20Sopenharmony_ci		case fcmples_op:
1608c2ecf20Sopenharmony_ci		case fcmples_e_op:
1618c2ecf20Sopenharmony_ci		case fcmpuns_op:
1628c2ecf20Sopenharmony_ci		case fcmpuns_e_op:
1638c2ecf20Sopenharmony_ci			ftype = CS;
1648c2ecf20Sopenharmony_ci			break;
1658c2ecf20Sopenharmony_ci		default:
1668c2ecf20Sopenharmony_ci			return SIGILL;
1678c2ecf20Sopenharmony_ci		}
1688c2ecf20Sopenharmony_ci		break;
1698c2ecf20Sopenharmony_ci	case fd1_op:{
1708c2ecf20Sopenharmony_ci			switch (NDS32Insn_OPCODE_BIT69(insn)) {
1718c2ecf20Sopenharmony_ci			case faddd_op:
1728c2ecf20Sopenharmony_ci				func.t = faddd;
1738c2ecf20Sopenharmony_ci				ftype = D2D;
1748c2ecf20Sopenharmony_ci				break;
1758c2ecf20Sopenharmony_ci			case fsubd_op:
1768c2ecf20Sopenharmony_ci				func.t = fsubd;
1778c2ecf20Sopenharmony_ci				ftype = D2D;
1788c2ecf20Sopenharmony_ci				break;
1798c2ecf20Sopenharmony_ci			case fmaddd_op:
1808c2ecf20Sopenharmony_ci				func.t = fpemu_fmaddd;
1818c2ecf20Sopenharmony_ci				ftype = D2D;
1828c2ecf20Sopenharmony_ci				break;
1838c2ecf20Sopenharmony_ci			case fmsubd_op:
1848c2ecf20Sopenharmony_ci				func.t = fpemu_fmsubd;
1858c2ecf20Sopenharmony_ci				ftype = D2D;
1868c2ecf20Sopenharmony_ci				break;
1878c2ecf20Sopenharmony_ci			case fnmaddd_op:
1888c2ecf20Sopenharmony_ci				func.t = fpemu_fnmaddd;
1898c2ecf20Sopenharmony_ci				ftype = D2D;
1908c2ecf20Sopenharmony_ci				break;
1918c2ecf20Sopenharmony_ci			case fnmsubd_op:
1928c2ecf20Sopenharmony_ci				func.t = fpemu_fnmsubd;
1938c2ecf20Sopenharmony_ci				ftype = D2D;
1948c2ecf20Sopenharmony_ci				break;
1958c2ecf20Sopenharmony_ci			case fmuld_op:
1968c2ecf20Sopenharmony_ci				func.t = fmuld;
1978c2ecf20Sopenharmony_ci				ftype = D2D;
1988c2ecf20Sopenharmony_ci				break;
1998c2ecf20Sopenharmony_ci			case fdivd_op:
2008c2ecf20Sopenharmony_ci				func.t = fdivd;
2018c2ecf20Sopenharmony_ci				ftype = D2D;
2028c2ecf20Sopenharmony_ci				break;
2038c2ecf20Sopenharmony_ci			case fd1_f2op_op:
2048c2ecf20Sopenharmony_ci				switch (NDS32Insn_OPCODE_BIT1014(insn)) {
2058c2ecf20Sopenharmony_ci				case fd2s_op:
2068c2ecf20Sopenharmony_ci					func.b = fd2s;
2078c2ecf20Sopenharmony_ci					ftype = D1S;
2088c2ecf20Sopenharmony_ci					break;
2098c2ecf20Sopenharmony_ci				case fd2si_op:
2108c2ecf20Sopenharmony_ci					func.b = fd2si;
2118c2ecf20Sopenharmony_ci					ftype = D1S;
2128c2ecf20Sopenharmony_ci					break;
2138c2ecf20Sopenharmony_ci				case fd2si_z_op:
2148c2ecf20Sopenharmony_ci					func.b = fd2si_z;
2158c2ecf20Sopenharmony_ci					ftype = D1S;
2168c2ecf20Sopenharmony_ci					break;
2178c2ecf20Sopenharmony_ci				case fd2ui_op:
2188c2ecf20Sopenharmony_ci					func.b = fd2ui;
2198c2ecf20Sopenharmony_ci					ftype = D1S;
2208c2ecf20Sopenharmony_ci					break;
2218c2ecf20Sopenharmony_ci				case fd2ui_z_op:
2228c2ecf20Sopenharmony_ci					func.b = fd2ui_z;
2238c2ecf20Sopenharmony_ci					ftype = D1S;
2248c2ecf20Sopenharmony_ci					break;
2258c2ecf20Sopenharmony_ci				case fsi2d_op:
2268c2ecf20Sopenharmony_ci					func.b = fsi2d;
2278c2ecf20Sopenharmony_ci					ftype = D1S;
2288c2ecf20Sopenharmony_ci					break;
2298c2ecf20Sopenharmony_ci				case fui2d_op:
2308c2ecf20Sopenharmony_ci					func.b = fui2d;
2318c2ecf20Sopenharmony_ci					ftype = D1S;
2328c2ecf20Sopenharmony_ci					break;
2338c2ecf20Sopenharmony_ci				case fsqrtd_op:
2348c2ecf20Sopenharmony_ci					func.b = fsqrtd;
2358c2ecf20Sopenharmony_ci					ftype = D1D;
2368c2ecf20Sopenharmony_ci					break;
2378c2ecf20Sopenharmony_ci				default:
2388c2ecf20Sopenharmony_ci					return SIGILL;
2398c2ecf20Sopenharmony_ci				}
2408c2ecf20Sopenharmony_ci				break;
2418c2ecf20Sopenharmony_ci			default:
2428c2ecf20Sopenharmony_ci				return SIGILL;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci			}
2458c2ecf20Sopenharmony_ci			break;
2468c2ecf20Sopenharmony_ci		}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	case fd2_op:
2498c2ecf20Sopenharmony_ci		switch (NDS32Insn_OPCODE_BIT69(insn)) {
2508c2ecf20Sopenharmony_ci		case fcmpeqd_op:
2518c2ecf20Sopenharmony_ci		case fcmpeqd_e_op:
2528c2ecf20Sopenharmony_ci		case fcmpltd_op:
2538c2ecf20Sopenharmony_ci		case fcmpltd_e_op:
2548c2ecf20Sopenharmony_ci		case fcmpled_op:
2558c2ecf20Sopenharmony_ci		case fcmpled_e_op:
2568c2ecf20Sopenharmony_ci		case fcmpund_op:
2578c2ecf20Sopenharmony_ci		case fcmpund_e_op:
2588c2ecf20Sopenharmony_ci			ftype = CD;
2598c2ecf20Sopenharmony_ci			break;
2608c2ecf20Sopenharmony_ci		default:
2618c2ecf20Sopenharmony_ci			return SIGILL;
2628c2ecf20Sopenharmony_ci		}
2638c2ecf20Sopenharmony_ci		break;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	default:
2668c2ecf20Sopenharmony_ci		return SIGILL;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	switch (ftype) {
2708c2ecf20Sopenharmony_ci	case S1S:{
2718c2ecf20Sopenharmony_ci			void *ft, *fa;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci			SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
2748c2ecf20Sopenharmony_ci			SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
2758c2ecf20Sopenharmony_ci			func.b(ft, fa);
2768c2ecf20Sopenharmony_ci			break;
2778c2ecf20Sopenharmony_ci		}
2788c2ecf20Sopenharmony_ci	case S2S:{
2798c2ecf20Sopenharmony_ci			void *ft, *fa, *fb;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci			SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
2828c2ecf20Sopenharmony_ci			SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
2838c2ecf20Sopenharmony_ci			SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
2848c2ecf20Sopenharmony_ci			func.t(ft, fa, fb);
2858c2ecf20Sopenharmony_ci			break;
2868c2ecf20Sopenharmony_ci		}
2878c2ecf20Sopenharmony_ci	case S1D:{
2888c2ecf20Sopenharmony_ci			void *ft, *fa;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci			DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
2918c2ecf20Sopenharmony_ci			SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
2928c2ecf20Sopenharmony_ci			func.b(ft, fa);
2938c2ecf20Sopenharmony_ci			break;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci	case CS:{
2968c2ecf20Sopenharmony_ci			unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn);
2978c2ecf20Sopenharmony_ci			void *ft, *fa, *fb;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci			SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
3008c2ecf20Sopenharmony_ci			SPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
3018c2ecf20Sopenharmony_ci			SPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
3028c2ecf20Sopenharmony_ci			if (cmpop < 0x8) {
3038c2ecf20Sopenharmony_ci				cmpop = cmptab[cmpop];
3048c2ecf20Sopenharmony_ci				fcmps(ft, fa, fb, cmpop);
3058c2ecf20Sopenharmony_ci			} else
3068c2ecf20Sopenharmony_ci				return SIGILL;
3078c2ecf20Sopenharmony_ci			break;
3088c2ecf20Sopenharmony_ci		}
3098c2ecf20Sopenharmony_ci	case D1D:{
3108c2ecf20Sopenharmony_ci			void *ft, *fa;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci			DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
3138c2ecf20Sopenharmony_ci			DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
3148c2ecf20Sopenharmony_ci			func.b(ft, fa);
3158c2ecf20Sopenharmony_ci			break;
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci	case D2D:{
3188c2ecf20Sopenharmony_ci			void *ft, *fa, *fb;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci			DPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
3218c2ecf20Sopenharmony_ci			DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
3228c2ecf20Sopenharmony_ci			DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
3238c2ecf20Sopenharmony_ci			func.t(ft, fa, fb);
3248c2ecf20Sopenharmony_ci			break;
3258c2ecf20Sopenharmony_ci		}
3268c2ecf20Sopenharmony_ci	case D1S:{
3278c2ecf20Sopenharmony_ci			void *ft, *fa;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci			SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
3308c2ecf20Sopenharmony_ci			DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
3318c2ecf20Sopenharmony_ci			func.b(ft, fa);
3328c2ecf20Sopenharmony_ci			break;
3338c2ecf20Sopenharmony_ci		}
3348c2ecf20Sopenharmony_ci	case CD:{
3358c2ecf20Sopenharmony_ci			unsigned int cmpop = NDS32Insn_OPCODE_BIT69(insn);
3368c2ecf20Sopenharmony_ci			void *ft, *fa, *fb;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci			SPFROMREG(ft, NDS32Insn_OPCODE_Rt(insn));
3398c2ecf20Sopenharmony_ci			DPFROMREG(fa, NDS32Insn_OPCODE_Ra(insn));
3408c2ecf20Sopenharmony_ci			DPFROMREG(fb, NDS32Insn_OPCODE_Rb(insn));
3418c2ecf20Sopenharmony_ci			if (cmpop < 0x8) {
3428c2ecf20Sopenharmony_ci				cmpop = cmptab[cmpop];
3438c2ecf20Sopenharmony_ci				fcmpd(ft, fa, fb, cmpop);
3448c2ecf20Sopenharmony_ci			} else
3458c2ecf20Sopenharmony_ci				return SIGILL;
3468c2ecf20Sopenharmony_ci			break;
3478c2ecf20Sopenharmony_ci		}
3488c2ecf20Sopenharmony_ci	default:
3498c2ecf20Sopenharmony_ci		return SIGILL;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/*
3538c2ecf20Sopenharmony_ci	 * If an exception is required, generate a tidy SIGFPE exception.
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
3568c2ecf20Sopenharmony_ci	if (((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE_NO_UDF_IEXE)
3578c2ecf20Sopenharmony_ci	    || ((fpu_reg->fpcsr << 5) & (fpu_reg->UDF_IEX_trap))) {
3588c2ecf20Sopenharmony_ci#else
3598c2ecf20Sopenharmony_ci	if ((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE) {
3608c2ecf20Sopenharmony_ci#endif
3618c2ecf20Sopenharmony_ci		return SIGFPE;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci	return 0;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ciint do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	unsigned long insn = 0, addr = regs->ipc;
3698c2ecf20Sopenharmony_ci	unsigned long emulpc, contpc;
3708c2ecf20Sopenharmony_ci	unsigned char *pc = (void *)&insn;
3718c2ecf20Sopenharmony_ci	char c;
3728c2ecf20Sopenharmony_ci	int i = 0, ret;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
3758c2ecf20Sopenharmony_ci		if (__get_user(c, (unsigned char *)addr++))
3768c2ecf20Sopenharmony_ci			return SIGBUS;
3778c2ecf20Sopenharmony_ci		*pc++ = c;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	insn = be32_to_cpu(insn);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	emulpc = regs->ipc;
3838c2ecf20Sopenharmony_ci	contpc = regs->ipc + 4;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (NDS32Insn_OPCODE(insn) != cop0_op)
3868c2ecf20Sopenharmony_ci		return SIGILL;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	switch (NDS32Insn_OPCODE_COP0(insn)) {
3898c2ecf20Sopenharmony_ci	case fs1_op:
3908c2ecf20Sopenharmony_ci	case fs2_op:
3918c2ecf20Sopenharmony_ci	case fd1_op:
3928c2ecf20Sopenharmony_ci	case fd2_op:
3938c2ecf20Sopenharmony_ci		{
3948c2ecf20Sopenharmony_ci			/* a real fpu computation instruction */
3958c2ecf20Sopenharmony_ci			ret = fpu_emu(fpu, insn);
3968c2ecf20Sopenharmony_ci			if (!ret)
3978c2ecf20Sopenharmony_ci				regs->ipc = contpc;
3988c2ecf20Sopenharmony_ci		}
3998c2ecf20Sopenharmony_ci		break;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	default:
4028c2ecf20Sopenharmony_ci		return SIGILL;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return ret;
4068c2ecf20Sopenharmony_ci}
407