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