18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/powerpc/math-emu/math_efp.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008, 2010 Freescale Semiconductor, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Ebony Zhu, <ebony.zhu@freescale.com> 88c2ecf20Sopenharmony_ci * Yu Liu, <yu.liu@freescale.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Derived from arch/alpha/math-emu/math.c 118c2ecf20Sopenharmony_ci * arch/powerpc/math-emu/math.c 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Description: 148c2ecf20Sopenharmony_ci * This file is the exception handler to make E500 SPE instructions 158c2ecf20Sopenharmony_ci * fully comply with IEEE-754 floating point standard. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <linux/prctl.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 238c2ecf20Sopenharmony_ci#include <asm/reg.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define FP_EX_BOOKE_E500_SPE 268c2ecf20Sopenharmony_ci#include <asm/sfp-machine.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <math-emu/soft-fp.h> 298c2ecf20Sopenharmony_ci#include <math-emu/single.h> 308c2ecf20Sopenharmony_ci#include <math-emu/double.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define EFAPU 0x4 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define VCT 0x4 358c2ecf20Sopenharmony_ci#define SPFP 0x6 368c2ecf20Sopenharmony_ci#define DPFP 0x7 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define EFSADD 0x2c0 398c2ecf20Sopenharmony_ci#define EFSSUB 0x2c1 408c2ecf20Sopenharmony_ci#define EFSABS 0x2c4 418c2ecf20Sopenharmony_ci#define EFSNABS 0x2c5 428c2ecf20Sopenharmony_ci#define EFSNEG 0x2c6 438c2ecf20Sopenharmony_ci#define EFSMUL 0x2c8 448c2ecf20Sopenharmony_ci#define EFSDIV 0x2c9 458c2ecf20Sopenharmony_ci#define EFSCMPGT 0x2cc 468c2ecf20Sopenharmony_ci#define EFSCMPLT 0x2cd 478c2ecf20Sopenharmony_ci#define EFSCMPEQ 0x2ce 488c2ecf20Sopenharmony_ci#define EFSCFD 0x2cf 498c2ecf20Sopenharmony_ci#define EFSCFSI 0x2d1 508c2ecf20Sopenharmony_ci#define EFSCTUI 0x2d4 518c2ecf20Sopenharmony_ci#define EFSCTSI 0x2d5 528c2ecf20Sopenharmony_ci#define EFSCTUF 0x2d6 538c2ecf20Sopenharmony_ci#define EFSCTSF 0x2d7 548c2ecf20Sopenharmony_ci#define EFSCTUIZ 0x2d8 558c2ecf20Sopenharmony_ci#define EFSCTSIZ 0x2da 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define EVFSADD 0x280 588c2ecf20Sopenharmony_ci#define EVFSSUB 0x281 598c2ecf20Sopenharmony_ci#define EVFSABS 0x284 608c2ecf20Sopenharmony_ci#define EVFSNABS 0x285 618c2ecf20Sopenharmony_ci#define EVFSNEG 0x286 628c2ecf20Sopenharmony_ci#define EVFSMUL 0x288 638c2ecf20Sopenharmony_ci#define EVFSDIV 0x289 648c2ecf20Sopenharmony_ci#define EVFSCMPGT 0x28c 658c2ecf20Sopenharmony_ci#define EVFSCMPLT 0x28d 668c2ecf20Sopenharmony_ci#define EVFSCMPEQ 0x28e 678c2ecf20Sopenharmony_ci#define EVFSCTUI 0x294 688c2ecf20Sopenharmony_ci#define EVFSCTSI 0x295 698c2ecf20Sopenharmony_ci#define EVFSCTUF 0x296 708c2ecf20Sopenharmony_ci#define EVFSCTSF 0x297 718c2ecf20Sopenharmony_ci#define EVFSCTUIZ 0x298 728c2ecf20Sopenharmony_ci#define EVFSCTSIZ 0x29a 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define EFDADD 0x2e0 758c2ecf20Sopenharmony_ci#define EFDSUB 0x2e1 768c2ecf20Sopenharmony_ci#define EFDABS 0x2e4 778c2ecf20Sopenharmony_ci#define EFDNABS 0x2e5 788c2ecf20Sopenharmony_ci#define EFDNEG 0x2e6 798c2ecf20Sopenharmony_ci#define EFDMUL 0x2e8 808c2ecf20Sopenharmony_ci#define EFDDIV 0x2e9 818c2ecf20Sopenharmony_ci#define EFDCTUIDZ 0x2ea 828c2ecf20Sopenharmony_ci#define EFDCTSIDZ 0x2eb 838c2ecf20Sopenharmony_ci#define EFDCMPGT 0x2ec 848c2ecf20Sopenharmony_ci#define EFDCMPLT 0x2ed 858c2ecf20Sopenharmony_ci#define EFDCMPEQ 0x2ee 868c2ecf20Sopenharmony_ci#define EFDCFS 0x2ef 878c2ecf20Sopenharmony_ci#define EFDCTUI 0x2f4 888c2ecf20Sopenharmony_ci#define EFDCTSI 0x2f5 898c2ecf20Sopenharmony_ci#define EFDCTUF 0x2f6 908c2ecf20Sopenharmony_ci#define EFDCTSF 0x2f7 918c2ecf20Sopenharmony_ci#define EFDCTUIZ 0x2f8 928c2ecf20Sopenharmony_ci#define EFDCTSIZ 0x2fa 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define AB 2 958c2ecf20Sopenharmony_ci#define XA 3 968c2ecf20Sopenharmony_ci#define XB 4 978c2ecf20Sopenharmony_ci#define XCR 5 988c2ecf20Sopenharmony_ci#define NOTYPE 0 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define SIGN_BIT_S (1UL << 31) 1018c2ecf20Sopenharmony_ci#define SIGN_BIT_D (1ULL << 63) 1028c2ecf20Sopenharmony_ci#define FP_EX_MASK (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \ 1038c2ecf20Sopenharmony_ci FP_EX_UNDERFLOW | FP_EX_OVERFLOW) 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int have_e500_cpu_a005_erratum; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ciunion dw_union { 1088c2ecf20Sopenharmony_ci u64 dp[1]; 1098c2ecf20Sopenharmony_ci u32 wp[2]; 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic unsigned long insn_type(unsigned long speinsn) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci unsigned long ret = NOTYPE; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci switch (speinsn & 0x7ff) { 1178c2ecf20Sopenharmony_ci case EFSABS: ret = XA; break; 1188c2ecf20Sopenharmony_ci case EFSADD: ret = AB; break; 1198c2ecf20Sopenharmony_ci case EFSCFD: ret = XB; break; 1208c2ecf20Sopenharmony_ci case EFSCMPEQ: ret = XCR; break; 1218c2ecf20Sopenharmony_ci case EFSCMPGT: ret = XCR; break; 1228c2ecf20Sopenharmony_ci case EFSCMPLT: ret = XCR; break; 1238c2ecf20Sopenharmony_ci case EFSCTSF: ret = XB; break; 1248c2ecf20Sopenharmony_ci case EFSCTSI: ret = XB; break; 1258c2ecf20Sopenharmony_ci case EFSCTSIZ: ret = XB; break; 1268c2ecf20Sopenharmony_ci case EFSCTUF: ret = XB; break; 1278c2ecf20Sopenharmony_ci case EFSCTUI: ret = XB; break; 1288c2ecf20Sopenharmony_ci case EFSCTUIZ: ret = XB; break; 1298c2ecf20Sopenharmony_ci case EFSDIV: ret = AB; break; 1308c2ecf20Sopenharmony_ci case EFSMUL: ret = AB; break; 1318c2ecf20Sopenharmony_ci case EFSNABS: ret = XA; break; 1328c2ecf20Sopenharmony_ci case EFSNEG: ret = XA; break; 1338c2ecf20Sopenharmony_ci case EFSSUB: ret = AB; break; 1348c2ecf20Sopenharmony_ci case EFSCFSI: ret = XB; break; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci case EVFSABS: ret = XA; break; 1378c2ecf20Sopenharmony_ci case EVFSADD: ret = AB; break; 1388c2ecf20Sopenharmony_ci case EVFSCMPEQ: ret = XCR; break; 1398c2ecf20Sopenharmony_ci case EVFSCMPGT: ret = XCR; break; 1408c2ecf20Sopenharmony_ci case EVFSCMPLT: ret = XCR; break; 1418c2ecf20Sopenharmony_ci case EVFSCTSF: ret = XB; break; 1428c2ecf20Sopenharmony_ci case EVFSCTSI: ret = XB; break; 1438c2ecf20Sopenharmony_ci case EVFSCTSIZ: ret = XB; break; 1448c2ecf20Sopenharmony_ci case EVFSCTUF: ret = XB; break; 1458c2ecf20Sopenharmony_ci case EVFSCTUI: ret = XB; break; 1468c2ecf20Sopenharmony_ci case EVFSCTUIZ: ret = XB; break; 1478c2ecf20Sopenharmony_ci case EVFSDIV: ret = AB; break; 1488c2ecf20Sopenharmony_ci case EVFSMUL: ret = AB; break; 1498c2ecf20Sopenharmony_ci case EVFSNABS: ret = XA; break; 1508c2ecf20Sopenharmony_ci case EVFSNEG: ret = XA; break; 1518c2ecf20Sopenharmony_ci case EVFSSUB: ret = AB; break; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci case EFDABS: ret = XA; break; 1548c2ecf20Sopenharmony_ci case EFDADD: ret = AB; break; 1558c2ecf20Sopenharmony_ci case EFDCFS: ret = XB; break; 1568c2ecf20Sopenharmony_ci case EFDCMPEQ: ret = XCR; break; 1578c2ecf20Sopenharmony_ci case EFDCMPGT: ret = XCR; break; 1588c2ecf20Sopenharmony_ci case EFDCMPLT: ret = XCR; break; 1598c2ecf20Sopenharmony_ci case EFDCTSF: ret = XB; break; 1608c2ecf20Sopenharmony_ci case EFDCTSI: ret = XB; break; 1618c2ecf20Sopenharmony_ci case EFDCTSIDZ: ret = XB; break; 1628c2ecf20Sopenharmony_ci case EFDCTSIZ: ret = XB; break; 1638c2ecf20Sopenharmony_ci case EFDCTUF: ret = XB; break; 1648c2ecf20Sopenharmony_ci case EFDCTUI: ret = XB; break; 1658c2ecf20Sopenharmony_ci case EFDCTUIDZ: ret = XB; break; 1668c2ecf20Sopenharmony_ci case EFDCTUIZ: ret = XB; break; 1678c2ecf20Sopenharmony_ci case EFDDIV: ret = AB; break; 1688c2ecf20Sopenharmony_ci case EFDMUL: ret = AB; break; 1698c2ecf20Sopenharmony_ci case EFDNABS: ret = XA; break; 1708c2ecf20Sopenharmony_ci case EFDNEG: ret = XA; break; 1718c2ecf20Sopenharmony_ci case EFDSUB: ret = AB; break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return ret; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciint do_spe_mathemu(struct pt_regs *regs) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci FP_DECL_EX; 1808c2ecf20Sopenharmony_ci int IR, cmp; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci unsigned long type, func, fc, fa, fb, src, speinsn; 1838c2ecf20Sopenharmony_ci union dw_union vc, va, vb; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (get_user(speinsn, (unsigned int __user *) regs->nip)) 1868c2ecf20Sopenharmony_ci return -EFAULT; 1878c2ecf20Sopenharmony_ci if ((speinsn >> 26) != EFAPU) 1888c2ecf20Sopenharmony_ci return -EINVAL; /* not an spe instruction */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci type = insn_type(speinsn); 1918c2ecf20Sopenharmony_ci if (type == NOTYPE) 1928c2ecf20Sopenharmony_ci goto illegal; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci func = speinsn & 0x7ff; 1958c2ecf20Sopenharmony_ci fc = (speinsn >> 21) & 0x1f; 1968c2ecf20Sopenharmony_ci fa = (speinsn >> 16) & 0x1f; 1978c2ecf20Sopenharmony_ci fb = (speinsn >> 11) & 0x1f; 1988c2ecf20Sopenharmony_ci src = (speinsn >> 5) & 0x7; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci vc.wp[0] = current->thread.evr[fc]; 2018c2ecf20Sopenharmony_ci vc.wp[1] = regs->gpr[fc]; 2028c2ecf20Sopenharmony_ci va.wp[0] = current->thread.evr[fa]; 2038c2ecf20Sopenharmony_ci va.wp[1] = regs->gpr[fa]; 2048c2ecf20Sopenharmony_ci vb.wp[0] = current->thread.evr[fb]; 2058c2ecf20Sopenharmony_ci vb.wp[1] = regs->gpr[fb]; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci __FPU_FPSCR = mfspr(SPRN_SPEFSCR); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR); 2108c2ecf20Sopenharmony_ci pr_debug("vc: %08x %08x\n", vc.wp[0], vc.wp[1]); 2118c2ecf20Sopenharmony_ci pr_debug("va: %08x %08x\n", va.wp[0], va.wp[1]); 2128c2ecf20Sopenharmony_ci pr_debug("vb: %08x %08x\n", vb.wp[0], vb.wp[1]); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci switch (src) { 2158c2ecf20Sopenharmony_ci case SPFP: { 2168c2ecf20Sopenharmony_ci FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci switch (type) { 2198c2ecf20Sopenharmony_ci case AB: 2208c2ecf20Sopenharmony_ci case XCR: 2218c2ecf20Sopenharmony_ci FP_UNPACK_SP(SA, va.wp + 1); 2228c2ecf20Sopenharmony_ci case XB: 2238c2ecf20Sopenharmony_ci FP_UNPACK_SP(SB, vb.wp + 1); 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci case XA: 2268c2ecf20Sopenharmony_ci FP_UNPACK_SP(SA, va.wp + 1); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci pr_debug("SA: %ld %08lx %ld (%ld)\n", SA_s, SA_f, SA_e, SA_c); 2318c2ecf20Sopenharmony_ci pr_debug("SB: %ld %08lx %ld (%ld)\n", SB_s, SB_f, SB_e, SB_c); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci switch (func) { 2348c2ecf20Sopenharmony_ci case EFSABS: 2358c2ecf20Sopenharmony_ci vc.wp[1] = va.wp[1] & ~SIGN_BIT_S; 2368c2ecf20Sopenharmony_ci goto update_regs; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci case EFSNABS: 2398c2ecf20Sopenharmony_ci vc.wp[1] = va.wp[1] | SIGN_BIT_S; 2408c2ecf20Sopenharmony_ci goto update_regs; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci case EFSNEG: 2438c2ecf20Sopenharmony_ci vc.wp[1] = va.wp[1] ^ SIGN_BIT_S; 2448c2ecf20Sopenharmony_ci goto update_regs; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci case EFSADD: 2478c2ecf20Sopenharmony_ci FP_ADD_S(SR, SA, SB); 2488c2ecf20Sopenharmony_ci goto pack_s; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci case EFSSUB: 2518c2ecf20Sopenharmony_ci FP_SUB_S(SR, SA, SB); 2528c2ecf20Sopenharmony_ci goto pack_s; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci case EFSMUL: 2558c2ecf20Sopenharmony_ci FP_MUL_S(SR, SA, SB); 2568c2ecf20Sopenharmony_ci goto pack_s; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci case EFSDIV: 2598c2ecf20Sopenharmony_ci FP_DIV_S(SR, SA, SB); 2608c2ecf20Sopenharmony_ci goto pack_s; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci case EFSCMPEQ: 2638c2ecf20Sopenharmony_ci cmp = 0; 2648c2ecf20Sopenharmony_ci goto cmp_s; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci case EFSCMPGT: 2678c2ecf20Sopenharmony_ci cmp = 1; 2688c2ecf20Sopenharmony_ci goto cmp_s; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci case EFSCMPLT: 2718c2ecf20Sopenharmony_ci cmp = -1; 2728c2ecf20Sopenharmony_ci goto cmp_s; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci case EFSCTSF: 2758c2ecf20Sopenharmony_ci case EFSCTUF: 2768c2ecf20Sopenharmony_ci if (SB_c == FP_CLS_NAN) { 2778c2ecf20Sopenharmony_ci vc.wp[1] = 0; 2788c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci SB_e += (func == EFSCTSF ? 31 : 32); 2818c2ecf20Sopenharmony_ci FP_TO_INT_ROUND_S(vc.wp[1], SB, 32, 2828c2ecf20Sopenharmony_ci (func == EFSCTSF)); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci goto update_regs; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci case EFSCFD: { 2878c2ecf20Sopenharmony_ci FP_DECL_D(DB); 2888c2ecf20Sopenharmony_ci FP_CLEAR_EXCEPTIONS; 2898c2ecf20Sopenharmony_ci FP_UNPACK_DP(DB, vb.dp); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci pr_debug("DB: %ld %08lx %08lx %ld (%ld)\n", 2928c2ecf20Sopenharmony_ci DB_s, DB_f1, DB_f0, DB_e, DB_c); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci FP_CONV(S, D, 1, 2, SR, DB); 2958c2ecf20Sopenharmony_ci goto pack_s; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci case EFSCTSI: 2998c2ecf20Sopenharmony_ci case EFSCTUI: 3008c2ecf20Sopenharmony_ci if (SB_c == FP_CLS_NAN) { 3018c2ecf20Sopenharmony_ci vc.wp[1] = 0; 3028c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 3038c2ecf20Sopenharmony_ci } else { 3048c2ecf20Sopenharmony_ci FP_TO_INT_ROUND_S(vc.wp[1], SB, 32, 3058c2ecf20Sopenharmony_ci ((func & 0x3) != 0)); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci goto update_regs; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci case EFSCTSIZ: 3108c2ecf20Sopenharmony_ci case EFSCTUIZ: 3118c2ecf20Sopenharmony_ci if (SB_c == FP_CLS_NAN) { 3128c2ecf20Sopenharmony_ci vc.wp[1] = 0; 3138c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 3148c2ecf20Sopenharmony_ci } else { 3158c2ecf20Sopenharmony_ci FP_TO_INT_S(vc.wp[1], SB, 32, 3168c2ecf20Sopenharmony_ci ((func & 0x3) != 0)); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci goto update_regs; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci default: 3218c2ecf20Sopenharmony_ci goto illegal; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cipack_s: 3268c2ecf20Sopenharmony_ci pr_debug("SR: %ld %08lx %ld (%ld)\n", SR_s, SR_f, SR_e, SR_c); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci FP_PACK_SP(vc.wp + 1, SR); 3298c2ecf20Sopenharmony_ci goto update_regs; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cicmp_s: 3328c2ecf20Sopenharmony_ci FP_CMP_S(IR, SA, SB, 3); 3338c2ecf20Sopenharmony_ci if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB))) 3348c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 3358c2ecf20Sopenharmony_ci if (IR == cmp) { 3368c2ecf20Sopenharmony_ci IR = 0x4; 3378c2ecf20Sopenharmony_ci } else { 3388c2ecf20Sopenharmony_ci IR = 0; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci goto update_ccr; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci case DPFP: { 3448c2ecf20Sopenharmony_ci FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci switch (type) { 3478c2ecf20Sopenharmony_ci case AB: 3488c2ecf20Sopenharmony_ci case XCR: 3498c2ecf20Sopenharmony_ci FP_UNPACK_DP(DA, va.dp); 3508c2ecf20Sopenharmony_ci case XB: 3518c2ecf20Sopenharmony_ci FP_UNPACK_DP(DB, vb.dp); 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci case XA: 3548c2ecf20Sopenharmony_ci FP_UNPACK_DP(DA, va.dp); 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci pr_debug("DA: %ld %08lx %08lx %ld (%ld)\n", 3598c2ecf20Sopenharmony_ci DA_s, DA_f1, DA_f0, DA_e, DA_c); 3608c2ecf20Sopenharmony_ci pr_debug("DB: %ld %08lx %08lx %ld (%ld)\n", 3618c2ecf20Sopenharmony_ci DB_s, DB_f1, DB_f0, DB_e, DB_c); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci switch (func) { 3648c2ecf20Sopenharmony_ci case EFDABS: 3658c2ecf20Sopenharmony_ci vc.dp[0] = va.dp[0] & ~SIGN_BIT_D; 3668c2ecf20Sopenharmony_ci goto update_regs; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci case EFDNABS: 3698c2ecf20Sopenharmony_ci vc.dp[0] = va.dp[0] | SIGN_BIT_D; 3708c2ecf20Sopenharmony_ci goto update_regs; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci case EFDNEG: 3738c2ecf20Sopenharmony_ci vc.dp[0] = va.dp[0] ^ SIGN_BIT_D; 3748c2ecf20Sopenharmony_ci goto update_regs; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci case EFDADD: 3778c2ecf20Sopenharmony_ci FP_ADD_D(DR, DA, DB); 3788c2ecf20Sopenharmony_ci goto pack_d; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci case EFDSUB: 3818c2ecf20Sopenharmony_ci FP_SUB_D(DR, DA, DB); 3828c2ecf20Sopenharmony_ci goto pack_d; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci case EFDMUL: 3858c2ecf20Sopenharmony_ci FP_MUL_D(DR, DA, DB); 3868c2ecf20Sopenharmony_ci goto pack_d; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci case EFDDIV: 3898c2ecf20Sopenharmony_ci FP_DIV_D(DR, DA, DB); 3908c2ecf20Sopenharmony_ci goto pack_d; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci case EFDCMPEQ: 3938c2ecf20Sopenharmony_ci cmp = 0; 3948c2ecf20Sopenharmony_ci goto cmp_d; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci case EFDCMPGT: 3978c2ecf20Sopenharmony_ci cmp = 1; 3988c2ecf20Sopenharmony_ci goto cmp_d; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci case EFDCMPLT: 4018c2ecf20Sopenharmony_ci cmp = -1; 4028c2ecf20Sopenharmony_ci goto cmp_d; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci case EFDCTSF: 4058c2ecf20Sopenharmony_ci case EFDCTUF: 4068c2ecf20Sopenharmony_ci if (DB_c == FP_CLS_NAN) { 4078c2ecf20Sopenharmony_ci vc.wp[1] = 0; 4088c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 4098c2ecf20Sopenharmony_ci } else { 4108c2ecf20Sopenharmony_ci DB_e += (func == EFDCTSF ? 31 : 32); 4118c2ecf20Sopenharmony_ci FP_TO_INT_ROUND_D(vc.wp[1], DB, 32, 4128c2ecf20Sopenharmony_ci (func == EFDCTSF)); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci goto update_regs; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci case EFDCFS: { 4178c2ecf20Sopenharmony_ci FP_DECL_S(SB); 4188c2ecf20Sopenharmony_ci FP_CLEAR_EXCEPTIONS; 4198c2ecf20Sopenharmony_ci FP_UNPACK_SP(SB, vb.wp + 1); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci pr_debug("SB: %ld %08lx %ld (%ld)\n", 4228c2ecf20Sopenharmony_ci SB_s, SB_f, SB_e, SB_c); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci FP_CONV(D, S, 2, 1, DR, SB); 4258c2ecf20Sopenharmony_ci goto pack_d; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci case EFDCTUIDZ: 4298c2ecf20Sopenharmony_ci case EFDCTSIDZ: 4308c2ecf20Sopenharmony_ci if (DB_c == FP_CLS_NAN) { 4318c2ecf20Sopenharmony_ci vc.dp[0] = 0; 4328c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 4338c2ecf20Sopenharmony_ci } else { 4348c2ecf20Sopenharmony_ci FP_TO_INT_D(vc.dp[0], DB, 64, 4358c2ecf20Sopenharmony_ci ((func & 0x1) == 0)); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci goto update_regs; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci case EFDCTUI: 4408c2ecf20Sopenharmony_ci case EFDCTSI: 4418c2ecf20Sopenharmony_ci if (DB_c == FP_CLS_NAN) { 4428c2ecf20Sopenharmony_ci vc.wp[1] = 0; 4438c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci FP_TO_INT_ROUND_D(vc.wp[1], DB, 32, 4468c2ecf20Sopenharmony_ci ((func & 0x3) != 0)); 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci goto update_regs; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci case EFDCTUIZ: 4518c2ecf20Sopenharmony_ci case EFDCTSIZ: 4528c2ecf20Sopenharmony_ci if (DB_c == FP_CLS_NAN) { 4538c2ecf20Sopenharmony_ci vc.wp[1] = 0; 4548c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 4558c2ecf20Sopenharmony_ci } else { 4568c2ecf20Sopenharmony_ci FP_TO_INT_D(vc.wp[1], DB, 32, 4578c2ecf20Sopenharmony_ci ((func & 0x3) != 0)); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci goto update_regs; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci default: 4628c2ecf20Sopenharmony_ci goto illegal; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cipack_d: 4678c2ecf20Sopenharmony_ci pr_debug("DR: %ld %08lx %08lx %ld (%ld)\n", 4688c2ecf20Sopenharmony_ci DR_s, DR_f1, DR_f0, DR_e, DR_c); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci FP_PACK_DP(vc.dp, DR); 4718c2ecf20Sopenharmony_ci goto update_regs; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cicmp_d: 4748c2ecf20Sopenharmony_ci FP_CMP_D(IR, DA, DB, 3); 4758c2ecf20Sopenharmony_ci if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB))) 4768c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 4778c2ecf20Sopenharmony_ci if (IR == cmp) { 4788c2ecf20Sopenharmony_ci IR = 0x4; 4798c2ecf20Sopenharmony_ci } else { 4808c2ecf20Sopenharmony_ci IR = 0; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci goto update_ccr; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci case VCT: { 4878c2ecf20Sopenharmony_ci FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0); 4888c2ecf20Sopenharmony_ci FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1); 4898c2ecf20Sopenharmony_ci int IR0, IR1; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci switch (type) { 4928c2ecf20Sopenharmony_ci case AB: 4938c2ecf20Sopenharmony_ci case XCR: 4948c2ecf20Sopenharmony_ci FP_UNPACK_SP(SA0, va.wp); 4958c2ecf20Sopenharmony_ci FP_UNPACK_SP(SA1, va.wp + 1); 4968c2ecf20Sopenharmony_ci case XB: 4978c2ecf20Sopenharmony_ci FP_UNPACK_SP(SB0, vb.wp); 4988c2ecf20Sopenharmony_ci FP_UNPACK_SP(SB1, vb.wp + 1); 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci case XA: 5018c2ecf20Sopenharmony_ci FP_UNPACK_SP(SA0, va.wp); 5028c2ecf20Sopenharmony_ci FP_UNPACK_SP(SA1, va.wp + 1); 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci pr_debug("SA0: %ld %08lx %ld (%ld)\n", 5078c2ecf20Sopenharmony_ci SA0_s, SA0_f, SA0_e, SA0_c); 5088c2ecf20Sopenharmony_ci pr_debug("SA1: %ld %08lx %ld (%ld)\n", 5098c2ecf20Sopenharmony_ci SA1_s, SA1_f, SA1_e, SA1_c); 5108c2ecf20Sopenharmony_ci pr_debug("SB0: %ld %08lx %ld (%ld)\n", 5118c2ecf20Sopenharmony_ci SB0_s, SB0_f, SB0_e, SB0_c); 5128c2ecf20Sopenharmony_ci pr_debug("SB1: %ld %08lx %ld (%ld)\n", 5138c2ecf20Sopenharmony_ci SB1_s, SB1_f, SB1_e, SB1_c); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci switch (func) { 5168c2ecf20Sopenharmony_ci case EVFSABS: 5178c2ecf20Sopenharmony_ci vc.wp[0] = va.wp[0] & ~SIGN_BIT_S; 5188c2ecf20Sopenharmony_ci vc.wp[1] = va.wp[1] & ~SIGN_BIT_S; 5198c2ecf20Sopenharmony_ci goto update_regs; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci case EVFSNABS: 5228c2ecf20Sopenharmony_ci vc.wp[0] = va.wp[0] | SIGN_BIT_S; 5238c2ecf20Sopenharmony_ci vc.wp[1] = va.wp[1] | SIGN_BIT_S; 5248c2ecf20Sopenharmony_ci goto update_regs; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci case EVFSNEG: 5278c2ecf20Sopenharmony_ci vc.wp[0] = va.wp[0] ^ SIGN_BIT_S; 5288c2ecf20Sopenharmony_ci vc.wp[1] = va.wp[1] ^ SIGN_BIT_S; 5298c2ecf20Sopenharmony_ci goto update_regs; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci case EVFSADD: 5328c2ecf20Sopenharmony_ci FP_ADD_S(SR0, SA0, SB0); 5338c2ecf20Sopenharmony_ci FP_ADD_S(SR1, SA1, SB1); 5348c2ecf20Sopenharmony_ci goto pack_vs; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci case EVFSSUB: 5378c2ecf20Sopenharmony_ci FP_SUB_S(SR0, SA0, SB0); 5388c2ecf20Sopenharmony_ci FP_SUB_S(SR1, SA1, SB1); 5398c2ecf20Sopenharmony_ci goto pack_vs; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci case EVFSMUL: 5428c2ecf20Sopenharmony_ci FP_MUL_S(SR0, SA0, SB0); 5438c2ecf20Sopenharmony_ci FP_MUL_S(SR1, SA1, SB1); 5448c2ecf20Sopenharmony_ci goto pack_vs; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci case EVFSDIV: 5478c2ecf20Sopenharmony_ci FP_DIV_S(SR0, SA0, SB0); 5488c2ecf20Sopenharmony_ci FP_DIV_S(SR1, SA1, SB1); 5498c2ecf20Sopenharmony_ci goto pack_vs; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci case EVFSCMPEQ: 5528c2ecf20Sopenharmony_ci cmp = 0; 5538c2ecf20Sopenharmony_ci goto cmp_vs; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci case EVFSCMPGT: 5568c2ecf20Sopenharmony_ci cmp = 1; 5578c2ecf20Sopenharmony_ci goto cmp_vs; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci case EVFSCMPLT: 5608c2ecf20Sopenharmony_ci cmp = -1; 5618c2ecf20Sopenharmony_ci goto cmp_vs; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci case EVFSCTUF: 5648c2ecf20Sopenharmony_ci case EVFSCTSF: 5658c2ecf20Sopenharmony_ci if (SB0_c == FP_CLS_NAN) { 5668c2ecf20Sopenharmony_ci vc.wp[0] = 0; 5678c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 5688c2ecf20Sopenharmony_ci } else { 5698c2ecf20Sopenharmony_ci SB0_e += (func == EVFSCTSF ? 31 : 32); 5708c2ecf20Sopenharmony_ci FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32, 5718c2ecf20Sopenharmony_ci (func == EVFSCTSF)); 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci if (SB1_c == FP_CLS_NAN) { 5748c2ecf20Sopenharmony_ci vc.wp[1] = 0; 5758c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 5768c2ecf20Sopenharmony_ci } else { 5778c2ecf20Sopenharmony_ci SB1_e += (func == EVFSCTSF ? 31 : 32); 5788c2ecf20Sopenharmony_ci FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32, 5798c2ecf20Sopenharmony_ci (func == EVFSCTSF)); 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci goto update_regs; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci case EVFSCTUI: 5848c2ecf20Sopenharmony_ci case EVFSCTSI: 5858c2ecf20Sopenharmony_ci if (SB0_c == FP_CLS_NAN) { 5868c2ecf20Sopenharmony_ci vc.wp[0] = 0; 5878c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 5888c2ecf20Sopenharmony_ci } else { 5898c2ecf20Sopenharmony_ci FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32, 5908c2ecf20Sopenharmony_ci ((func & 0x3) != 0)); 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci if (SB1_c == FP_CLS_NAN) { 5938c2ecf20Sopenharmony_ci vc.wp[1] = 0; 5948c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 5958c2ecf20Sopenharmony_ci } else { 5968c2ecf20Sopenharmony_ci FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32, 5978c2ecf20Sopenharmony_ci ((func & 0x3) != 0)); 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci goto update_regs; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci case EVFSCTUIZ: 6028c2ecf20Sopenharmony_ci case EVFSCTSIZ: 6038c2ecf20Sopenharmony_ci if (SB0_c == FP_CLS_NAN) { 6048c2ecf20Sopenharmony_ci vc.wp[0] = 0; 6058c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 6068c2ecf20Sopenharmony_ci } else { 6078c2ecf20Sopenharmony_ci FP_TO_INT_S(vc.wp[0], SB0, 32, 6088c2ecf20Sopenharmony_ci ((func & 0x3) != 0)); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci if (SB1_c == FP_CLS_NAN) { 6118c2ecf20Sopenharmony_ci vc.wp[1] = 0; 6128c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 6138c2ecf20Sopenharmony_ci } else { 6148c2ecf20Sopenharmony_ci FP_TO_INT_S(vc.wp[1], SB1, 32, 6158c2ecf20Sopenharmony_ci ((func & 0x3) != 0)); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci goto update_regs; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci default: 6208c2ecf20Sopenharmony_ci goto illegal; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci break; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cipack_vs: 6258c2ecf20Sopenharmony_ci pr_debug("SR0: %ld %08lx %ld (%ld)\n", 6268c2ecf20Sopenharmony_ci SR0_s, SR0_f, SR0_e, SR0_c); 6278c2ecf20Sopenharmony_ci pr_debug("SR1: %ld %08lx %ld (%ld)\n", 6288c2ecf20Sopenharmony_ci SR1_s, SR1_f, SR1_e, SR1_c); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci FP_PACK_SP(vc.wp, SR0); 6318c2ecf20Sopenharmony_ci FP_PACK_SP(vc.wp + 1, SR1); 6328c2ecf20Sopenharmony_ci goto update_regs; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cicmp_vs: 6358c2ecf20Sopenharmony_ci { 6368c2ecf20Sopenharmony_ci int ch, cl; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci FP_CMP_S(IR0, SA0, SB0, 3); 6398c2ecf20Sopenharmony_ci FP_CMP_S(IR1, SA1, SB1, 3); 6408c2ecf20Sopenharmony_ci if (IR0 == 3 && (FP_ISSIGNAN_S(SA0) || FP_ISSIGNAN_S(SB0))) 6418c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 6428c2ecf20Sopenharmony_ci if (IR1 == 3 && (FP_ISSIGNAN_S(SA1) || FP_ISSIGNAN_S(SB1))) 6438c2ecf20Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); 6448c2ecf20Sopenharmony_ci ch = (IR0 == cmp) ? 1 : 0; 6458c2ecf20Sopenharmony_ci cl = (IR1 == cmp) ? 1 : 0; 6468c2ecf20Sopenharmony_ci IR = (ch << 3) | (cl << 2) | ((ch | cl) << 1) | 6478c2ecf20Sopenharmony_ci ((ch & cl) << 0); 6488c2ecf20Sopenharmony_ci goto update_ccr; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci default: 6528c2ecf20Sopenharmony_ci return -EINVAL; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ciupdate_ccr: 6568c2ecf20Sopenharmony_ci regs->ccr &= ~(15 << ((7 - ((speinsn >> 23) & 0x7)) << 2)); 6578c2ecf20Sopenharmony_ci regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2)); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ciupdate_regs: 6608c2ecf20Sopenharmony_ci /* 6618c2ecf20Sopenharmony_ci * If the "invalid" exception sticky bit was set by the 6628c2ecf20Sopenharmony_ci * processor for non-finite input, but was not set before the 6638c2ecf20Sopenharmony_ci * instruction being emulated, clear it. Likewise for the 6648c2ecf20Sopenharmony_ci * "underflow" bit, which may have been set by the processor 6658c2ecf20Sopenharmony_ci * for exact underflow, not just inexact underflow when the 6668c2ecf20Sopenharmony_ci * flag should be set for IEEE 754 semantics. Other sticky 6678c2ecf20Sopenharmony_ci * exceptions will only be set by the processor when they are 6688c2ecf20Sopenharmony_ci * correct according to IEEE 754 semantics, and we must not 6698c2ecf20Sopenharmony_ci * clear sticky bits that were already set before the emulated 6708c2ecf20Sopenharmony_ci * instruction as they represent the user-visible sticky 6718c2ecf20Sopenharmony_ci * exception status. "inexact" traps to kernel are not 6728c2ecf20Sopenharmony_ci * required for IEEE semantics and are not enabled by default, 6738c2ecf20Sopenharmony_ci * so the "inexact" sticky bit may have been set by a previous 6748c2ecf20Sopenharmony_ci * instruction without the kernel being aware of it. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci __FPU_FPSCR 6778c2ecf20Sopenharmony_ci &= ~(FP_EX_INVALID | FP_EX_UNDERFLOW) | current->thread.spefscr_last; 6788c2ecf20Sopenharmony_ci __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK); 6798c2ecf20Sopenharmony_ci mtspr(SPRN_SPEFSCR, __FPU_FPSCR); 6808c2ecf20Sopenharmony_ci current->thread.spefscr_last = __FPU_FPSCR; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci current->thread.evr[fc] = vc.wp[0]; 6838c2ecf20Sopenharmony_ci regs->gpr[fc] = vc.wp[1]; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci pr_debug("ccr = %08lx\n", regs->ccr); 6868c2ecf20Sopenharmony_ci pr_debug("cur exceptions = %08x spefscr = %08lx\n", 6878c2ecf20Sopenharmony_ci FP_CUR_EXCEPTIONS, __FPU_FPSCR); 6888c2ecf20Sopenharmony_ci pr_debug("vc: %08x %08x\n", vc.wp[0], vc.wp[1]); 6898c2ecf20Sopenharmony_ci pr_debug("va: %08x %08x\n", va.wp[0], va.wp[1]); 6908c2ecf20Sopenharmony_ci pr_debug("vb: %08x %08x\n", vb.wp[0], vb.wp[1]); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) { 6938c2ecf20Sopenharmony_ci if ((FP_CUR_EXCEPTIONS & FP_EX_DIVZERO) 6948c2ecf20Sopenharmony_ci && (current->thread.fpexc_mode & PR_FP_EXC_DIV)) 6958c2ecf20Sopenharmony_ci return 1; 6968c2ecf20Sopenharmony_ci if ((FP_CUR_EXCEPTIONS & FP_EX_OVERFLOW) 6978c2ecf20Sopenharmony_ci && (current->thread.fpexc_mode & PR_FP_EXC_OVF)) 6988c2ecf20Sopenharmony_ci return 1; 6998c2ecf20Sopenharmony_ci if ((FP_CUR_EXCEPTIONS & FP_EX_UNDERFLOW) 7008c2ecf20Sopenharmony_ci && (current->thread.fpexc_mode & PR_FP_EXC_UND)) 7018c2ecf20Sopenharmony_ci return 1; 7028c2ecf20Sopenharmony_ci if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) 7038c2ecf20Sopenharmony_ci && (current->thread.fpexc_mode & PR_FP_EXC_RES)) 7048c2ecf20Sopenharmony_ci return 1; 7058c2ecf20Sopenharmony_ci if ((FP_CUR_EXCEPTIONS & FP_EX_INVALID) 7068c2ecf20Sopenharmony_ci && (current->thread.fpexc_mode & PR_FP_EXC_INV)) 7078c2ecf20Sopenharmony_ci return 1; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ciillegal: 7128c2ecf20Sopenharmony_ci if (have_e500_cpu_a005_erratum) { 7138c2ecf20Sopenharmony_ci /* according to e500 cpu a005 erratum, reissue efp inst */ 7148c2ecf20Sopenharmony_ci regs->nip -= 4; 7158c2ecf20Sopenharmony_ci pr_debug("re-issue efp inst: %08lx\n", speinsn); 7168c2ecf20Sopenharmony_ci return 0; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn); 7208c2ecf20Sopenharmony_ci return -ENOSYS; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ciint speround_handler(struct pt_regs *regs) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci union dw_union fgpr; 7268c2ecf20Sopenharmony_ci int s_lo, s_hi; 7278c2ecf20Sopenharmony_ci int lo_inexact, hi_inexact; 7288c2ecf20Sopenharmony_ci int fp_result; 7298c2ecf20Sopenharmony_ci unsigned long speinsn, type, fb, fc, fptype, func; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (get_user(speinsn, (unsigned int __user *) regs->nip)) 7328c2ecf20Sopenharmony_ci return -EFAULT; 7338c2ecf20Sopenharmony_ci if ((speinsn >> 26) != 4) 7348c2ecf20Sopenharmony_ci return -EINVAL; /* not an spe instruction */ 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci func = speinsn & 0x7ff; 7378c2ecf20Sopenharmony_ci type = insn_type(func); 7388c2ecf20Sopenharmony_ci if (type == XCR) return -ENOSYS; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci __FPU_FPSCR = mfspr(SPRN_SPEFSCR); 7418c2ecf20Sopenharmony_ci pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci fptype = (speinsn >> 5) & 0x7; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* No need to round if the result is exact */ 7468c2ecf20Sopenharmony_ci lo_inexact = __FPU_FPSCR & (SPEFSCR_FG | SPEFSCR_FX); 7478c2ecf20Sopenharmony_ci hi_inexact = __FPU_FPSCR & (SPEFSCR_FGH | SPEFSCR_FXH); 7488c2ecf20Sopenharmony_ci if (!(lo_inexact || (hi_inexact && fptype == VCT))) 7498c2ecf20Sopenharmony_ci return 0; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci fc = (speinsn >> 21) & 0x1f; 7528c2ecf20Sopenharmony_ci s_lo = regs->gpr[fc] & SIGN_BIT_S; 7538c2ecf20Sopenharmony_ci s_hi = current->thread.evr[fc] & SIGN_BIT_S; 7548c2ecf20Sopenharmony_ci fgpr.wp[0] = current->thread.evr[fc]; 7558c2ecf20Sopenharmony_ci fgpr.wp[1] = regs->gpr[fc]; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci fb = (speinsn >> 11) & 0x1f; 7588c2ecf20Sopenharmony_ci switch (func) { 7598c2ecf20Sopenharmony_ci case EFSCTUIZ: 7608c2ecf20Sopenharmony_ci case EFSCTSIZ: 7618c2ecf20Sopenharmony_ci case EVFSCTUIZ: 7628c2ecf20Sopenharmony_ci case EVFSCTSIZ: 7638c2ecf20Sopenharmony_ci case EFDCTUIDZ: 7648c2ecf20Sopenharmony_ci case EFDCTSIDZ: 7658c2ecf20Sopenharmony_ci case EFDCTUIZ: 7668c2ecf20Sopenharmony_ci case EFDCTSIZ: 7678c2ecf20Sopenharmony_ci /* 7688c2ecf20Sopenharmony_ci * These instructions always round to zero, 7698c2ecf20Sopenharmony_ci * independent of the rounding mode. 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci case EFSCTUI: 7748c2ecf20Sopenharmony_ci case EFSCTUF: 7758c2ecf20Sopenharmony_ci case EVFSCTUI: 7768c2ecf20Sopenharmony_ci case EVFSCTUF: 7778c2ecf20Sopenharmony_ci case EFDCTUI: 7788c2ecf20Sopenharmony_ci case EFDCTUF: 7798c2ecf20Sopenharmony_ci fp_result = 0; 7808c2ecf20Sopenharmony_ci s_lo = 0; 7818c2ecf20Sopenharmony_ci s_hi = 0; 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci case EFSCTSI: 7858c2ecf20Sopenharmony_ci case EFSCTSF: 7868c2ecf20Sopenharmony_ci fp_result = 0; 7878c2ecf20Sopenharmony_ci /* Recover the sign of a zero result if possible. */ 7888c2ecf20Sopenharmony_ci if (fgpr.wp[1] == 0) 7898c2ecf20Sopenharmony_ci s_lo = regs->gpr[fb] & SIGN_BIT_S; 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci case EVFSCTSI: 7938c2ecf20Sopenharmony_ci case EVFSCTSF: 7948c2ecf20Sopenharmony_ci fp_result = 0; 7958c2ecf20Sopenharmony_ci /* Recover the sign of a zero result if possible. */ 7968c2ecf20Sopenharmony_ci if (fgpr.wp[1] == 0) 7978c2ecf20Sopenharmony_ci s_lo = regs->gpr[fb] & SIGN_BIT_S; 7988c2ecf20Sopenharmony_ci if (fgpr.wp[0] == 0) 7998c2ecf20Sopenharmony_ci s_hi = current->thread.evr[fb] & SIGN_BIT_S; 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci case EFDCTSI: 8038c2ecf20Sopenharmony_ci case EFDCTSF: 8048c2ecf20Sopenharmony_ci fp_result = 0; 8058c2ecf20Sopenharmony_ci s_hi = s_lo; 8068c2ecf20Sopenharmony_ci /* Recover the sign of a zero result if possible. */ 8078c2ecf20Sopenharmony_ci if (fgpr.wp[1] == 0) 8088c2ecf20Sopenharmony_ci s_hi = current->thread.evr[fb] & SIGN_BIT_S; 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci default: 8128c2ecf20Sopenharmony_ci fp_result = 1; 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci pr_debug("round fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci switch (fptype) { 8198c2ecf20Sopenharmony_ci /* Since SPE instructions on E500 core can handle round to nearest 8208c2ecf20Sopenharmony_ci * and round toward zero with IEEE-754 complied, we just need 8218c2ecf20Sopenharmony_ci * to handle round toward +Inf and round toward -Inf by software. 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ci case SPFP: 8248c2ecf20Sopenharmony_ci if ((FP_ROUNDMODE) == FP_RND_PINF) { 8258c2ecf20Sopenharmony_ci if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */ 8268c2ecf20Sopenharmony_ci } else { /* round to -Inf */ 8278c2ecf20Sopenharmony_ci if (s_lo) { 8288c2ecf20Sopenharmony_ci if (fp_result) 8298c2ecf20Sopenharmony_ci fgpr.wp[1]++; /* Z < 0, choose Z2 */ 8308c2ecf20Sopenharmony_ci else 8318c2ecf20Sopenharmony_ci fgpr.wp[1]--; /* Z < 0, choose Z2 */ 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci break; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci case DPFP: 8378c2ecf20Sopenharmony_ci if (FP_ROUNDMODE == FP_RND_PINF) { 8388c2ecf20Sopenharmony_ci if (!s_hi) { 8398c2ecf20Sopenharmony_ci if (fp_result) 8408c2ecf20Sopenharmony_ci fgpr.dp[0]++; /* Z > 0, choose Z1 */ 8418c2ecf20Sopenharmony_ci else 8428c2ecf20Sopenharmony_ci fgpr.wp[1]++; /* Z > 0, choose Z1 */ 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci } else { /* round to -Inf */ 8458c2ecf20Sopenharmony_ci if (s_hi) { 8468c2ecf20Sopenharmony_ci if (fp_result) 8478c2ecf20Sopenharmony_ci fgpr.dp[0]++; /* Z < 0, choose Z2 */ 8488c2ecf20Sopenharmony_ci else 8498c2ecf20Sopenharmony_ci fgpr.wp[1]--; /* Z < 0, choose Z2 */ 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci break; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci case VCT: 8558c2ecf20Sopenharmony_ci if (FP_ROUNDMODE == FP_RND_PINF) { 8568c2ecf20Sopenharmony_ci if (lo_inexact && !s_lo) 8578c2ecf20Sopenharmony_ci fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ 8588c2ecf20Sopenharmony_ci if (hi_inexact && !s_hi) 8598c2ecf20Sopenharmony_ci fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */ 8608c2ecf20Sopenharmony_ci } else { /* round to -Inf */ 8618c2ecf20Sopenharmony_ci if (lo_inexact && s_lo) { 8628c2ecf20Sopenharmony_ci if (fp_result) 8638c2ecf20Sopenharmony_ci fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ 8648c2ecf20Sopenharmony_ci else 8658c2ecf20Sopenharmony_ci fgpr.wp[1]--; /* Z_low < 0, choose Z2 */ 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci if (hi_inexact && s_hi) { 8688c2ecf20Sopenharmony_ci if (fp_result) 8698c2ecf20Sopenharmony_ci fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ 8708c2ecf20Sopenharmony_ci else 8718c2ecf20Sopenharmony_ci fgpr.wp[0]--; /* Z_high < 0, choose Z2 */ 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci break; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci default: 8778c2ecf20Sopenharmony_ci return -EINVAL; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci current->thread.evr[fc] = fgpr.wp[0]; 8818c2ecf20Sopenharmony_ci regs->gpr[fc] = fgpr.wp[1]; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci pr_debug(" to fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) 8868c2ecf20Sopenharmony_ci return (current->thread.fpexc_mode & PR_FP_EXC_RES) ? 1 : 0; 8878c2ecf20Sopenharmony_ci return 0; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ciint __init spe_mathemu_init(void) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci u32 pvr, maj, min; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci pvr = mfspr(SPRN_PVR); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if ((PVR_VER(pvr) == PVR_VER_E500V1) || 8978c2ecf20Sopenharmony_ci (PVR_VER(pvr) == PVR_VER_E500V2)) { 8988c2ecf20Sopenharmony_ci maj = PVR_MAJ(pvr); 8998c2ecf20Sopenharmony_ci min = PVR_MIN(pvr); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* 9028c2ecf20Sopenharmony_ci * E500 revision below 1.1, 2.3, 3.1, 4.1, 5.1 9038c2ecf20Sopenharmony_ci * need cpu a005 errata workaround 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_ci switch (maj) { 9068c2ecf20Sopenharmony_ci case 1: 9078c2ecf20Sopenharmony_ci if (min < 1) 9088c2ecf20Sopenharmony_ci have_e500_cpu_a005_erratum = 1; 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci case 2: 9118c2ecf20Sopenharmony_ci if (min < 3) 9128c2ecf20Sopenharmony_ci have_e500_cpu_a005_erratum = 1; 9138c2ecf20Sopenharmony_ci break; 9148c2ecf20Sopenharmony_ci case 3: 9158c2ecf20Sopenharmony_ci case 4: 9168c2ecf20Sopenharmony_ci case 5: 9178c2ecf20Sopenharmony_ci if (min < 1) 9188c2ecf20Sopenharmony_ci have_e500_cpu_a005_erratum = 1; 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci default: 9218c2ecf20Sopenharmony_ci break; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return 0; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cimodule_init(spe_mathemu_init); 929