diff options
Diffstat (limited to 'newlib/libc/machine/riscv/ieeefp.c')
-rw-r--r-- | newlib/libc/machine/riscv/ieeefp.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/newlib/libc/machine/riscv/ieeefp.c b/newlib/libc/machine/riscv/ieeefp.c new file mode 100644 index 000000000..5288877a6 --- /dev/null +++ b/newlib/libc/machine/riscv/ieeefp.c @@ -0,0 +1,110 @@ +/* Copyright (c) 2017 SiFive Inc. All rights reserved. + + This copyrighted material is made available to anyone wishing to use, + modify, copy, or redistribute it subject to the terms and conditions + of the BSD License. This program is distributed in the hope that + it will be useful, but WITHOUT ANY WARRANTY expressed or implied, + including the implied warranties of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. A copy of this license is available at + http://www.opensource.org/licenses. +*/ + +#include <ieeefp.h> + +#ifdef __riscv_flen +static void +fssr(unsigned value) +{ + asm volatile ("fssr %0" :: "r"(value)); +} + +static unsigned +frsr() +{ + unsigned value; + asm volatile ("frsr %0" : "=r" (value)); + return value; +} + +static fp_rnd +frm_fp_rnd (unsigned frm) +{ + switch (frm) + { + case 0: return FP_RN; + case 1: return FP_RZ; + case 2: return FP_RM; + case 3: return FP_RP; + /* 4 ~ 7 is invalid value, so just retun FP_RP. */ + default:return FP_RP; + } +} + +#endif /* __riscv_flen */ + +fp_except +fpgetmask(void) +{ + return 0; +} + +fp_rnd +fpgetround(void) +{ +#ifdef __riscv_flen + unsigned rm = (frsr () >> 5) & 0x7; + return frm_fp_rnd (rm); +#else + return FP_RZ; +#endif /* __riscv_flen */ +} + +fp_except +fpgetsticky(void) +{ +#ifdef __riscv_flen + return frsr () & 0x1f; +#else + return 0; +#endif /* __riscv_flen */ +} + +fp_except +fpsetmask(fp_except mask) +{ + return -1; +} + +fp_rnd +fpsetround(fp_rnd rnd_dir) +{ +#ifdef __riscv_flen + unsigned fsr = frsr (); + unsigned rm = (fsr >> 5) & 0x7; + unsigned new_rm; + switch (rnd_dir) + { + case FP_RN: new_rm = 0; + case FP_RZ: new_rm = 1; + case FP_RM: new_rm = 2; + case FP_RP: new_rm = 3; + default: return -1; + } + fssr (new_rm << 5 | fsr & 0x1f); + return frm_fp_rnd (rm); +#else + return -1; +#endif /* __riscv_flen */ +} + +fp_except +fpsetsticky(fp_except sticky) +{ +#ifdef __riscv_flen + unsigned fsr = frsr (); + fssr (sticky & 0x1f | fsr & ~0x1f); + return fsr & 0x1f; +#else + return -1; +#endif /* __riscv_flen */ +} |