From 8183db10db6377ac58ad048a4c827425a614695c Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 27 May 2019 14:17:21 +0800 Subject: [PATCH 1/3] math-emu: Use statement expressions to fix Wshift-count-overflow warning To avoid "shift count >= width of type" warning, using statement expressions to implement the conditional controlling before constant shift The modification in op-2.h is taken from the glibc commit 'sysdeps/unix/sysv/lin ("fe0b1e854ad32")'. Signed-off-by: Vincent Chen Acked-by: Greentime Hu Signed-off-by: Greentime Hu --- include/math-emu/op-2.h | 17 +++++++---------- include/math-emu/op-common.h | 11 ++++++----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/include/math-emu/op-2.h b/include/math-emu/op-2.h index 13a374f51a22..244522b02076 100644 --- a/include/math-emu/op-2.h +++ b/include/math-emu/op-2.h @@ -567,16 +567,13 @@ */ #define _FP_FRAC_ASSEMBLE_2(r, X, rsize) \ - do { \ - if (rsize <= _FP_W_TYPE_SIZE) \ - r = X##_f0; \ - else \ - { \ - r = X##_f1; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f0; \ - } \ - } while (0) + (void) (((rsize) <= _FP_W_TYPE_SIZE) \ + ? ({ (r) = X##_f0; }) \ + : ({ \ + (r) = X##_f1; \ + (r) <<= _FP_W_TYPE_SIZE; \ + (r) += X##_f0; \ + })) #define _FP_FRAC_DISASSEMBLE_2(X, r, rsize) \ do { \ diff --git a/include/math-emu/op-common.h b/include/math-emu/op-common.h index 6bdf8c61d221..f37d12877754 100644 --- a/include/math-emu/op-common.h +++ b/include/math-emu/op-common.h @@ -795,11 +795,12 @@ do { \ ur_ = (unsigned rtype) -r; \ else \ ur_ = (unsigned rtype) r; \ - if (rsize <= _FP_W_TYPE_SIZE) \ - __FP_CLZ(X##_e, ur_); \ - else \ - __FP_CLZ_2(X##_e, (_FP_W_TYPE)(ur_ >> _FP_W_TYPE_SIZE), \ - (_FP_W_TYPE)ur_); \ + (void) (((rsize) <= _FP_W_TYPE_SIZE) \ + ? ({ __FP_CLZ(X##_e, ur_); }) \ + : ({ \ + __FP_CLZ_2(X##_e, (_FP_W_TYPE)(ur_ >> _FP_W_TYPE_SIZE), \ + (_FP_W_TYPE)ur_); \ + })); \ if (rsize < _FP_W_TYPE_SIZE) \ X##_e -= (_FP_W_TYPE_SIZE - rsize); \ X##_e = rsize - X##_e - 1; \ From ed32949e0acb73e7bc054bb02e0453d4d561ceda Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 20 May 2019 09:21:12 +0800 Subject: [PATCH 2/3] nds32: Avoid IEX status being incorrectly modified In order for kernel to capture each denormalized output, the UDF trapping enable bit is always raised in $fpcsr. Because underflow case will issue not an underflow exception but also an inexact exception, it causes that the IEX, IEX cumulative exception, flag in $fpcsr to be raised in each denormalized output handling. To make the emulation transparent to the user, the emulator needs to clear the IEX flag in $fpcsr if the result is a denormalized number. However, if the IEX flag has been raised before this floating point emulation, this cleanup may be incorrect. To avoid the IEX flags in $fpcsr be raised in each denormalized output handling, the IEX trap shall be always enabled. Signed-off-by: Vincent Chen Acked-by: Greentime Hu Signed-off-by: Greentime Hu --- arch/nds32/include/asm/bitfield.h | 2 +- arch/nds32/include/asm/fpu.h | 2 +- arch/nds32/include/asm/syscalls.h | 2 +- arch/nds32/include/uapi/asm/fp_udfiex_crtl.h | 16 ++++++++++++ arch/nds32/include/uapi/asm/sigcontext.h | 24 ++++++++++++------ arch/nds32/include/uapi/asm/udftrap.h | 13 ---------- arch/nds32/include/uapi/asm/unistd.h | 4 +-- arch/nds32/kernel/fpu.c | 15 +++++------ arch/nds32/kernel/sys_nds32.c | 26 +++++++++++--------- 9 files changed, 58 insertions(+), 46 deletions(-) create mode 100644 arch/nds32/include/uapi/asm/fp_udfiex_crtl.h delete mode 100644 arch/nds32/include/uapi/asm/udftrap.h diff --git a/arch/nds32/include/asm/bitfield.h b/arch/nds32/include/asm/bitfield.h index e75212c76b20..b02a58e71f80 100644 --- a/arch/nds32/include/asm/bitfield.h +++ b/arch/nds32/include/asm/bitfield.h @@ -937,7 +937,7 @@ #define FPCSR_mskDNIT ( 0x1 << FPCSR_offDNIT ) #define FPCSR_mskRIT ( 0x1 << FPCSR_offRIT ) #define FPCSR_mskALL (FPCSR_mskIVO | FPCSR_mskDBZ | FPCSR_mskOVF | FPCSR_mskUDF | FPCSR_mskIEX) -#define FPCSR_mskALLE_NO_UDFE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskIEXE) +#define FPCSR_mskALLE_NO_UDF_IEXE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE) #define FPCSR_mskALLE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskUDFE | FPCSR_mskIEXE) #define FPCSR_mskALLT (FPCSR_mskIVOT | FPCSR_mskDBZT | FPCSR_mskOVFT | FPCSR_mskUDFT | FPCSR_mskIEXT |FPCSR_mskDNIT | FPCSR_mskRIT) diff --git a/arch/nds32/include/asm/fpu.h b/arch/nds32/include/asm/fpu.h index 019f1bcfc5ee..8294ed4aaa2c 100644 --- a/arch/nds32/include/asm/fpu.h +++ b/arch/nds32/include/asm/fpu.h @@ -36,7 +36,7 @@ extern int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu); * enabled by default and kerenl will re-execute it by fpu emulator * when getting underflow exception. */ -#define FPCSR_INIT FPCSR_mskUDFE +#define FPCSR_INIT (FPCSR_mskUDFE | FPCSR_mskIEXE) #else #define FPCSR_INIT 0x0UL #endif diff --git a/arch/nds32/include/asm/syscalls.h b/arch/nds32/include/asm/syscalls.h index f3b16f602cb5..4e7216082a67 100644 --- a/arch/nds32/include/asm/syscalls.h +++ b/arch/nds32/include/asm/syscalls.h @@ -7,7 +7,7 @@ asmlinkage long sys_cacheflush(unsigned long addr, unsigned long len, unsigned int op); asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset, loff_t len); asmlinkage long sys_rt_sigreturn_wrapper(void); -asmlinkage long sys_udftrap(int option); +asmlinkage long sys_fp_udfiex_crtl(int cmd, int act); #include diff --git a/arch/nds32/include/uapi/asm/fp_udfiex_crtl.h b/arch/nds32/include/uapi/asm/fp_udfiex_crtl.h new file mode 100644 index 000000000000..d54a5d6c6538 --- /dev/null +++ b/arch/nds32/include/uapi/asm/fp_udfiex_crtl.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2005-2019 Andes Technology Corporation */ +#ifndef _FP_UDF_IEX_CRTL_H +#define _FP_UDF_IEX_CRTL_H + +/* + * The cmd list of sys_fp_udfiex_crtl() + */ +/* Disable UDF or IEX trap based on the content of parameter act */ +#define DISABLE_UDF_IEX_TRAP 0 +/* Enable UDF or IEX trap based on the content of parameter act */ +#define ENABLE_UDF_IEX_TRAP 1 +/* Get current status of UDF and IEX trap */ +#define GET_UDF_IEX_TRAP 2 + +#endif /* _FP_UDF_IEX_CRTL_H */ diff --git a/arch/nds32/include/uapi/asm/sigcontext.h b/arch/nds32/include/uapi/asm/sigcontext.h index 628ff6b75825..dc89af7ddcc3 100644 --- a/arch/nds32/include/uapi/asm/sigcontext.h +++ b/arch/nds32/include/uapi/asm/sigcontext.h @@ -13,14 +13,24 @@ struct fpu_struct { unsigned long long fd_regs[32]; unsigned long fpcsr; /* - * UDF_trap is used to recognize whether underflow trap is enabled - * or not. When UDF_trap == 1, this process will be traped and then - * get a SIGFPE signal when encountering an underflow exception. - * UDF_trap is only modified through setfputrap syscall. Therefore, - * UDF_trap needn't be saved or loaded to context in each context - * switch. + * When CONFIG_SUPPORT_DENORMAL_ARITHMETIC is defined, kernel prevents + * hardware from treating the denormalized output as an underflow case + * and rounding it to a normal number. Hence kernel enables the UDF and + * IEX trap in the fpcsr register to step in the calculation. + * However, the UDF and IEX trap enable bit in $fpcsr also lose + * their use. + * + * UDF_IEX_trap replaces the feature of UDF and IEX trap enable bit in + * $fpcsr to control the trap of underflow and inexact. The bit filed + * of UDF_IEX_trap is the same as $fpcsr, 10th bit is used to enable UDF + * exception trapping and 11th bit is used to enable IEX exception + * trapping. + * + * UDF_IEX_trap is only modified through fp_udfiex_crtl syscall. + * Therefore, UDF_IEX_trap needn't be saved and restored in each + * context switch. */ - unsigned long UDF_trap; + unsigned long UDF_IEX_trap; }; struct zol_struct { diff --git a/arch/nds32/include/uapi/asm/udftrap.h b/arch/nds32/include/uapi/asm/udftrap.h deleted file mode 100644 index 433f79d679c0..000000000000 --- a/arch/nds32/include/uapi/asm/udftrap.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2005-2018 Andes Technology Corporation */ -#ifndef _ASM_SETFPUTRAP -#define _ASM_SETFPUTRAP - -/* - * Options for setfputrap system call - */ -#define DISABLE_UDFTRAP 0 /* disable underflow exception trap */ -#define ENABLE_UDFTRAP 1 /* enable undeflos exception trap */ -#define GET_UDFTRAP 2 /* only get undeflos exception trap status */ - -#endif /* _ASM_CACHECTL */ diff --git a/arch/nds32/include/uapi/asm/unistd.h b/arch/nds32/include/uapi/asm/unistd.h index c691735017ed..a0b2f7b9c0f2 100644 --- a/arch/nds32/include/uapi/asm/unistd.h +++ b/arch/nds32/include/uapi/asm/unistd.h @@ -11,6 +11,6 @@ /* Additional NDS32 specific syscalls. */ #define __NR_cacheflush (__NR_arch_specific_syscall) -#define __NR_udftrap (__NR_arch_specific_syscall + 1) +#define __NR_fp_udfiex_crtl (__NR_arch_specific_syscall + 1) __SYSCALL(__NR_cacheflush, sys_cacheflush) -__SYSCALL(__NR_udftrap, sys_udftrap) +__SYSCALL(__NR_fp_udfiex_crtl, sys_fp_udfiex_crtl) diff --git a/arch/nds32/kernel/fpu.c b/arch/nds32/kernel/fpu.c index fddd40c7a16f..cf0b8760f261 100644 --- a/arch/nds32/kernel/fpu.c +++ b/arch/nds32/kernel/fpu.c @@ -14,7 +14,7 @@ const struct fpu_struct init_fpuregs = { .fd_regs = {[0 ... 31] = sNAN64}, .fpcsr = FPCSR_INIT, #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - .UDF_trap = 0 + .UDF_IEX_trap = 0 #endif }; @@ -178,7 +178,7 @@ inline void do_fpu_context_switch(struct pt_regs *regs) /* First time FPU user. */ load_fpu(&init_fpuregs); #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - current->thread.fpu.UDF_trap = init_fpuregs.UDF_trap; + current->thread.fpu.UDF_IEX_trap = init_fpuregs.UDF_IEX_trap; #endif set_used_math(); } @@ -206,7 +206,7 @@ inline void handle_fpu_exception(struct pt_regs *regs) unsigned int fpcsr; int si_code = 0, si_signo = SIGFPE; #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - unsigned long redo_except = FPCSR_mskDNIT|FPCSR_mskUDFT; + unsigned long redo_except = FPCSR_mskDNIT|FPCSR_mskUDFT|FPCSR_mskIEXT; #else unsigned long redo_except = FPCSR_mskDNIT; #endif @@ -215,21 +215,18 @@ inline void handle_fpu_exception(struct pt_regs *regs) fpcsr = current->thread.fpu.fpcsr; if (fpcsr & redo_except) { -#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - if (fpcsr & FPCSR_mskUDFT) - current->thread.fpu.fpcsr &= ~FPCSR_mskIEX; -#endif si_signo = do_fpuemu(regs, ¤t->thread.fpu); fpcsr = current->thread.fpu.fpcsr; - if (!si_signo) + if (!si_signo) { + current->thread.fpu.fpcsr &= ~(redo_except); goto done; + } } else if (fpcsr & FPCSR_mskRIT) { if (!user_mode(regs)) do_exit(SIGILL); si_signo = SIGILL; } - switch (si_signo) { case SIGFPE: fill_sigfpe_signo(fpcsr, &si_code); diff --git a/arch/nds32/kernel/sys_nds32.c b/arch/nds32/kernel/sys_nds32.c index 0835277636ce..cb2d1e219bb3 100644 --- a/arch/nds32/kernel/sys_nds32.c +++ b/arch/nds32/kernel/sys_nds32.c @@ -6,8 +6,8 @@ #include #include -#include #include +#include SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, unsigned long, prot, unsigned long, flags, @@ -51,31 +51,33 @@ SYSCALL_DEFINE3(cacheflush, unsigned int, start, unsigned int, end, int, cache) return 0; } -SYSCALL_DEFINE1(udftrap, int, option) +SYSCALL_DEFINE2(fp_udfiex_crtl, unsigned int, cmd, unsigned int, act) { #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - int old_udftrap; + int old_udf_iex; if (!used_math()) { load_fpu(&init_fpuregs); - current->thread.fpu.UDF_trap = init_fpuregs.UDF_trap; + current->thread.fpu.UDF_IEX_trap = init_fpuregs.UDF_IEX_trap; set_used_math(); } - old_udftrap = current->thread.fpu.UDF_trap; - switch (option) { - case DISABLE_UDFTRAP: - current->thread.fpu.UDF_trap = 0; + old_udf_iex = current->thread.fpu.UDF_IEX_trap; + act &= (FPCSR_mskUDFE | FPCSR_mskIEXE); + + switch (cmd) { + case DISABLE_UDF_IEX_TRAP: + current->thread.fpu.UDF_IEX_trap &= ~act; break; - case ENABLE_UDFTRAP: - current->thread.fpu.UDF_trap = FPCSR_mskUDFE; + case ENABLE_UDF_IEX_TRAP: + current->thread.fpu.UDF_IEX_trap |= act; break; - case GET_UDFTRAP: + case GET_UDF_IEX_TRAP: break; default: return -EINVAL; } - return old_udftrap; + return old_udf_iex; #else return -ENOTSUPP; #endif From 932296120543149e3397af252e7daee7af37eb05 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 20 May 2019 09:21:13 +0800 Subject: [PATCH 3/3] nds32: add new emulations for floating point instruction The existing floating point emulations is only available for floating instruction that possibly issue denormalized input and underflow exceptions. These existing FPU emulations are not sufficient when IEx Trap is enabled because some floating point instructions only issue inexact exception. This patch adds the emulations of such floating point instructions. Signed-off-by: Vincent Chen Acked-by: Greentime Hu Signed-off-by: Greentime Hu --- arch/nds32/include/asm/fpuemu.h | 12 +++++++ arch/nds32/math-emu/Makefile | 4 ++- arch/nds32/math-emu/fd2si.c | 30 +++++++++++++++++ arch/nds32/math-emu/fd2siz.c | 30 +++++++++++++++++ arch/nds32/math-emu/fd2ui.c | 30 +++++++++++++++++ arch/nds32/math-emu/fd2uiz.c | 30 +++++++++++++++++ arch/nds32/math-emu/fpuemu.c | 57 ++++++++++++++++++++++++++++++--- arch/nds32/math-emu/fs2si.c | 29 +++++++++++++++++ arch/nds32/math-emu/fs2siz.c | 29 +++++++++++++++++ arch/nds32/math-emu/fs2ui.c | 29 +++++++++++++++++ arch/nds32/math-emu/fs2uiz.c | 30 +++++++++++++++++ arch/nds32/math-emu/fsi2d.c | 22 +++++++++++++ arch/nds32/math-emu/fsi2s.c | 22 +++++++++++++ arch/nds32/math-emu/fui2d.c | 22 +++++++++++++ arch/nds32/math-emu/fui2s.c | 22 +++++++++++++ 15 files changed, 393 insertions(+), 5 deletions(-) create mode 100644 arch/nds32/math-emu/fd2si.c create mode 100644 arch/nds32/math-emu/fd2siz.c create mode 100644 arch/nds32/math-emu/fd2ui.c create mode 100644 arch/nds32/math-emu/fd2uiz.c create mode 100644 arch/nds32/math-emu/fs2si.c create mode 100644 arch/nds32/math-emu/fs2siz.c create mode 100644 arch/nds32/math-emu/fs2ui.c create mode 100644 arch/nds32/math-emu/fs2uiz.c create mode 100644 arch/nds32/math-emu/fsi2d.c create mode 100644 arch/nds32/math-emu/fsi2s.c create mode 100644 arch/nds32/math-emu/fui2d.c create mode 100644 arch/nds32/math-emu/fui2s.c diff --git a/arch/nds32/include/asm/fpuemu.h b/arch/nds32/include/asm/fpuemu.h index c4bd0c7faa75..63e7ef5f7969 100644 --- a/arch/nds32/include/asm/fpuemu.h +++ b/arch/nds32/include/asm/fpuemu.h @@ -13,6 +13,12 @@ void fsubs(void *ft, void *fa, void *fb); void fmuls(void *ft, void *fa, void *fb); void fdivs(void *ft, void *fa, void *fb); void fs2d(void *ft, void *fa); +void fs2si(void *ft, void *fa); +void fs2si_z(void *ft, void *fa); +void fs2ui(void *ft, void *fa); +void fs2ui_z(void *ft, void *fa); +void fsi2s(void *ft, void *fa); +void fui2s(void *ft, void *fa); void fsqrts(void *ft, void *fa); void fnegs(void *ft, void *fa); int fcmps(void *ft, void *fa, void *fb, int cop); @@ -26,6 +32,12 @@ void fmuld(void *ft, void *fa, void *fb); void fdivd(void *ft, void *fa, void *fb); void fsqrtd(void *ft, void *fa); void fd2s(void *ft, void *fa); +void fd2si(void *ft, void *fa); +void fd2si_z(void *ft, void *fa); +void fd2ui(void *ft, void *fa); +void fd2ui_z(void *ft, void *fa); +void fsi2d(void *ft, void *fa); +void fui2d(void *ft, void *fa); void fnegd(void *ft, void *fa); int fcmpd(void *ft, void *fa, void *fb, int cop); diff --git a/arch/nds32/math-emu/Makefile b/arch/nds32/math-emu/Makefile index 947fe0c3d52f..80932ac7ed53 100644 --- a/arch/nds32/math-emu/Makefile +++ b/arch/nds32/math-emu/Makefile @@ -4,4 +4,6 @@ obj-y := fpuemu.o \ fdivd.o fmuld.o fsubd.o faddd.o fs2d.o fsqrtd.o fcmpd.o fnegs.o \ - fdivs.o fmuls.o fsubs.o fadds.o fd2s.o fsqrts.o fcmps.o fnegd.o + fd2si.o fd2ui.o fd2siz.o fd2uiz.o fsi2d.o fui2d.o \ + fdivs.o fmuls.o fsubs.o fadds.o fd2s.o fsqrts.o fcmps.o fnegd.o \ + fs2si.o fs2ui.o fs2siz.o fs2uiz.o fsi2s.o fui2s.o diff --git a/arch/nds32/math-emu/fd2si.c b/arch/nds32/math-emu/fd2si.c new file mode 100644 index 000000000000..fae3e16a0a10 --- /dev/null +++ b/arch/nds32/math-emu/fd2si.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fd2si(void *ft, void *fa) +{ + int r; + + FP_DECL_D(A); + FP_DECL_EX; + + FP_UNPACK_DP(A, fa); + + if (A_c == FP_CLS_INF) { + *(int *)ft = (A_s == 0) ? 0x7fffffff : 0x80000000; + __FPU_FPCSR |= FP_EX_INVALID; + } else if (A_c == FP_CLS_NAN) { + *(int *)ft = 0xffffffff; + __FPU_FPCSR |= FP_EX_INVALID; + } else { + FP_TO_INT_ROUND_D(r, A, 32, 1); + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + *(int *)ft = r; + } + +} diff --git a/arch/nds32/math-emu/fd2siz.c b/arch/nds32/math-emu/fd2siz.c new file mode 100644 index 000000000000..92fe6774f112 --- /dev/null +++ b/arch/nds32/math-emu/fd2siz.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fd2si_z(void *ft, void *fa) +{ + int r; + + FP_DECL_D(A); + FP_DECL_EX; + + FP_UNPACK_DP(A, fa); + + if (A_c == FP_CLS_INF) { + *(int *)ft = (A_s == 0) ? 0x7fffffff : 0x80000000; + __FPU_FPCSR |= FP_EX_INVALID; + } else if (A_c == FP_CLS_NAN) { + *(int *)ft = 0xffffffff; + __FPU_FPCSR |= FP_EX_INVALID; + } else { + FP_TO_INT_D(r, A, 32, 1); + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + *(int *)ft = r; + } + +} diff --git a/arch/nds32/math-emu/fd2ui.c b/arch/nds32/math-emu/fd2ui.c new file mode 100644 index 000000000000..a0423b699aa4 --- /dev/null +++ b/arch/nds32/math-emu/fd2ui.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fd2ui(void *ft, void *fa) +{ + unsigned int r; + + FP_DECL_D(A); + FP_DECL_EX; + + FP_UNPACK_DP(A, fa); + + if (A_c == FP_CLS_INF) { + *(unsigned int *)ft = (A_s == 0) ? 0xffffffff : 0x00000000; + __FPU_FPCSR |= FP_EX_INVALID; + } else if (A_c == FP_CLS_NAN) { + *(unsigned int *)ft = 0xffffffff; + __FPU_FPCSR |= FP_EX_INVALID; + } else { + FP_TO_INT_ROUND_D(r, A, 32, 0); + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + *(unsigned int *)ft = r; + } + +} diff --git a/arch/nds32/math-emu/fd2uiz.c b/arch/nds32/math-emu/fd2uiz.c new file mode 100644 index 000000000000..8ae17cfce90d --- /dev/null +++ b/arch/nds32/math-emu/fd2uiz.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fd2ui_z(void *ft, void *fa) +{ + unsigned int r; + + FP_DECL_D(A); + FP_DECL_EX; + + FP_UNPACK_DP(A, fa); + + if (A_c == FP_CLS_INF) { + *(unsigned int *)ft = (A_s == 0) ? 0xffffffff : 0x00000000; + __FPU_FPCSR |= FP_EX_INVALID; + } else if (A_c == FP_CLS_NAN) { + *(unsigned int *)ft = 0xffffffff; + __FPU_FPCSR |= FP_EX_INVALID; + } else { + FP_TO_INT_D(r, A, 32, 0); + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + *(unsigned int *)ft = r; + } + +} diff --git a/arch/nds32/math-emu/fpuemu.c b/arch/nds32/math-emu/fpuemu.c index 75cf1643fa78..46558a15c0dc 100644 --- a/arch/nds32/math-emu/fpuemu.c +++ b/arch/nds32/math-emu/fpuemu.c @@ -113,6 +113,30 @@ static int fpu_emu(struct fpu_struct *fpu_reg, unsigned long insn) func.b = fs2d; ftype = S1D; break; + case fs2si_op: + func.b = fs2si; + ftype = S1S; + break; + case fs2si_z_op: + func.b = fs2si_z; + ftype = S1S; + break; + case fs2ui_op: + func.b = fs2ui; + ftype = S1S; + break; + case fs2ui_z_op: + func.b = fs2ui_z; + ftype = S1S; + break; + case fsi2s_op: + func.b = fsi2s; + ftype = S1S; + break; + case fui2s_op: + func.b = fui2s; + ftype = S1S; + break; case fsqrts_op: func.b = fsqrts; ftype = S1S; @@ -182,6 +206,30 @@ static int fpu_emu(struct fpu_struct *fpu_reg, unsigned long insn) func.b = fd2s; ftype = D1S; break; + case fd2si_op: + func.b = fd2si; + ftype = D1S; + break; + case fd2si_z_op: + func.b = fd2si_z; + ftype = D1S; + break; + case fd2ui_op: + func.b = fd2ui; + ftype = D1S; + break; + case fd2ui_z_op: + func.b = fd2ui_z; + ftype = D1S; + break; + case fsi2d_op: + func.b = fsi2d; + ftype = D1S; + break; + case fui2d_op: + func.b = fui2d; + ftype = D1S; + break; case fsqrtd_op: func.b = fsqrtd; ftype = D1D; @@ -305,16 +353,16 @@ static int fpu_emu(struct fpu_struct *fpu_reg, unsigned long insn) * If an exception is required, generate a tidy SIGFPE exception. */ #if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC) - if (((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE_NO_UDFE) || - ((fpu_reg->fpcsr & FPCSR_mskUDF) && (fpu_reg->UDF_trap))) + if (((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE_NO_UDF_IEXE) + || ((fpu_reg->fpcsr << 5) & (fpu_reg->UDF_IEX_trap))) { #else - if ((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE) + if ((fpu_reg->fpcsr << 5) & fpu_reg->fpcsr & FPCSR_mskALLE) { #endif return SIGFPE; + } return 0; } - int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu) { unsigned long insn = 0, addr = regs->ipc; @@ -336,6 +384,7 @@ int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu) if (NDS32Insn_OPCODE(insn) != cop0_op) return SIGILL; + switch (NDS32Insn_OPCODE_COP0(insn)) { case fs1_op: case fs2_op: diff --git a/arch/nds32/math-emu/fs2si.c b/arch/nds32/math-emu/fs2si.c new file mode 100644 index 000000000000..b4931d60980e --- /dev/null +++ b/arch/nds32/math-emu/fs2si.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fs2si(void *ft, void *fa) +{ + int r; + + FP_DECL_S(A); + FP_DECL_EX; + + FP_UNPACK_SP(A, fa); + + if (A_c == FP_CLS_INF) { + *(int *)ft = (A_s == 0) ? 0x7fffffff : 0x80000000; + __FPU_FPCSR |= FP_EX_INVALID; + } else if (A_c == FP_CLS_NAN) { + *(int *)ft = 0xffffffff; + __FPU_FPCSR |= FP_EX_INVALID; + } else { + FP_TO_INT_ROUND_S(r, A, 32, 1); + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + *(int *)ft = r; + } +} diff --git a/arch/nds32/math-emu/fs2siz.c b/arch/nds32/math-emu/fs2siz.c new file mode 100644 index 000000000000..1c2b99ce3e38 --- /dev/null +++ b/arch/nds32/math-emu/fs2siz.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fs2si_z(void *ft, void *fa) +{ + int r; + + FP_DECL_S(A); + FP_DECL_EX; + + FP_UNPACK_SP(A, fa); + + if (A_c == FP_CLS_INF) { + *(int *)ft = (A_s == 0) ? 0x7fffffff : 0x80000000; + __FPU_FPCSR |= FP_EX_INVALID; + } else if (A_c == FP_CLS_NAN) { + *(int *)ft = 0xffffffff; + __FPU_FPCSR |= FP_EX_INVALID; + } else { + FP_TO_INT_S(r, A, 32, 1); + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + *(int *)ft = r; + } +} diff --git a/arch/nds32/math-emu/fs2ui.c b/arch/nds32/math-emu/fs2ui.c new file mode 100644 index 000000000000..c337f0384d06 --- /dev/null +++ b/arch/nds32/math-emu/fs2ui.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fs2ui(void *ft, void *fa) +{ + unsigned int r; + + FP_DECL_S(A); + FP_DECL_EX; + + FP_UNPACK_SP(A, fa); + + if (A_c == FP_CLS_INF) { + *(unsigned int *)ft = (A_s == 0) ? 0xffffffff : 0x00000000; + __FPU_FPCSR |= FP_EX_INVALID; + } else if (A_c == FP_CLS_NAN) { + *(unsigned int *)ft = 0xffffffff; + __FPU_FPCSR |= FP_EX_INVALID; + } else { + FP_TO_INT_ROUND_S(r, A, 32, 0); + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + *(unsigned int *)ft = r; + } +} diff --git a/arch/nds32/math-emu/fs2uiz.c b/arch/nds32/math-emu/fs2uiz.c new file mode 100644 index 000000000000..22c5e4768044 --- /dev/null +++ b/arch/nds32/math-emu/fs2uiz.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fs2ui_z(void *ft, void *fa) +{ + unsigned int r; + + FP_DECL_S(A); + FP_DECL_EX; + + FP_UNPACK_SP(A, fa); + + if (A_c == FP_CLS_INF) { + *(unsigned int *)ft = (A_s == 0) ? 0xffffffff : 0x00000000; + __FPU_FPCSR |= FP_EX_INVALID; + } else if (A_c == FP_CLS_NAN) { + *(unsigned int *)ft = 0xffffffff; + __FPU_FPCSR |= FP_EX_INVALID; + } else { + FP_TO_INT_S(r, A, 32, 0); + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + *(unsigned int *)ft = r; + } + +} diff --git a/arch/nds32/math-emu/fsi2d.c b/arch/nds32/math-emu/fsi2d.c new file mode 100644 index 000000000000..6b04cec0c5c5 --- /dev/null +++ b/arch/nds32/math-emu/fsi2d.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fsi2d(void *ft, void *fa) +{ + int a = *(int *)fa; + + FP_DECL_D(R); + FP_DECL_EX; + + FP_FROM_INT_D(R, a, 32, int); + + FP_PACK_DP(ft, R); + + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + +} diff --git a/arch/nds32/math-emu/fsi2s.c b/arch/nds32/math-emu/fsi2s.c new file mode 100644 index 000000000000..689864a5df90 --- /dev/null +++ b/arch/nds32/math-emu/fsi2s.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fsi2s(void *ft, void *fa) +{ + int a = *(int *)fa; + + FP_DECL_S(R); + FP_DECL_EX; + + FP_FROM_INT_S(R, a, 32, int); + + FP_PACK_SP(ft, R); + + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + +} diff --git a/arch/nds32/math-emu/fui2d.c b/arch/nds32/math-emu/fui2d.c new file mode 100644 index 000000000000..9689d33a8d50 --- /dev/null +++ b/arch/nds32/math-emu/fui2d.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fui2d(void *ft, void *fa) +{ + unsigned int a = *(unsigned int *)fa; + + FP_DECL_D(R); + FP_DECL_EX; + + FP_FROM_INT_D(R, a, 32, int); + + FP_PACK_DP(ft, R); + + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + +} diff --git a/arch/nds32/math-emu/fui2s.c b/arch/nds32/math-emu/fui2s.c new file mode 100644 index 000000000000..f70f0762547d --- /dev/null +++ b/arch/nds32/math-emu/fui2s.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2005-2019 Andes Technology Corporation +#include + +#include +#include +#include + +void fui2s(void *ft, void *fa) +{ + unsigned int a = *(unsigned int *)fa; + + FP_DECL_S(R); + FP_DECL_EX; + + FP_FROM_INT_S(R, a, 32, int); + + FP_PACK_SP(ft, R); + + __FPU_FPCSR |= FP_CUR_EXCEPTIONS; + +}