From 5e0a80fa1ca971bd5740045902ae9cc3265a4d98 Mon Sep 17 00:00:00 2001 From: EnderIce2 Date: Wed, 5 Mar 2025 03:23:19 +0000 Subject: [PATCH] feat(userspace/libc): implementation header FIXME: testing required! Signed-off-by: EnderIce2 --- Userspace/libc/include/fenv.h | 51 +++++++++ Userspace/libc/src/std/fenv.c | 201 ++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 Userspace/libc/include/fenv.h create mode 100644 Userspace/libc/src/std/fenv.c diff --git a/Userspace/libc/include/fenv.h b/Userspace/libc/include/fenv.h new file mode 100644 index 00000000..d46a2370 --- /dev/null +++ b/Userspace/libc/include/fenv.h @@ -0,0 +1,51 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#ifndef _FENV_H +#define _FENV_H + +typedef int fenv_t; +typedef int fexcept_t; + +#define FE_DIVBYZERO 0x04 +#define FE_INEXACT 0x20 +#define FE_INVALID 0x01 +#define FE_OVERFLOW 0x08 +#define FE_UNDERFLOW 0x10 + +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +#define FE_DOWNWARD 0x400 +#define FE_TONEAREST 0x000 +#define FE_TOWARDZERO 0xC00 +#define FE_UPWARD 0x800 + +#define FE_DFL_ENV ((const fenv_t *)-1) + +int feclearexcept(int excepts); +int fegetenv(fenv_t *envp); +int fegetexceptflag(fexcept_t *flagp, int excepts); +int fegetround(void); +int feholdexcept(fenv_t *envp); +int feraiseexcept(int excepts); +int fesetenv(const fenv_t *envp); +int fesetexceptflag(const fexcept_t *flagp, int excepts); +int fesetround(int round); +int fetestexcept(int excepts); +int feupdateenv(const fenv_t *envp); + +#endif // _FENV_H diff --git a/Userspace/libc/src/std/fenv.c b/Userspace/libc/src/std/fenv.c new file mode 100644 index 00000000..794fc9ac --- /dev/null +++ b/Userspace/libc/src/std/fenv.c @@ -0,0 +1,201 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#include +#include + +export int feclearexcept(int excepts) +{ +#if defined(__amd64__) || defined(__i386__) + unsigned int status; + __asm__ __volatile__("fnstsw %0" : "=m"(*&status)); + status &= ~excepts; + __asm__ __volatile__("fldcw %0" : : "m"(*&status)); + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int fegetenv(fenv_t *envp) +{ +#if defined(__amd64__) || defined(__i386__) + __asm__ __volatile__("fnstenv %0" : "=m"(*envp)); + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int fegetexceptflag(fexcept_t *flagp, int excepts) +{ +#if defined(__amd64__) || defined(__i386__) + unsigned int status; + __asm__ __volatile__("fnstsw %0" : "=m"(*&status)); + *flagp = status & excepts; + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int fegetround(void) +{ +#if defined(__amd64__) || defined(__i386__) + unsigned int cw; + __asm__ __volatile__("fnstcw %0" : "=m"(*&cw)); + return cw & 0x0C00; +#elif defined(__arm__) + return FE_TONEAREST; +#elif defined(__aarch64__) + return FE_TONEAREST; +#else +#error "Unsupported architecture" +#endif +} + +export int feholdexcept(fenv_t *envp) +{ +#if defined(__amd64__) || defined(__i386__) + __asm__ __volatile__("fnstenv %0" : "=m"(*envp)); + unsigned int cw; + __asm__ __volatile__("fnclex"); + __asm__ __volatile__("fnstcw %0" : "=m"(*&cw)); + cw |= 0x3F; /* Set non-stop mode for all exceptions */ + __asm__ __volatile__("fldcw %0" : : "m"(*&cw)); + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int feraiseexcept(int excepts) +{ +#if defined(__amd64__) || defined(__i386__) + unsigned int status; + __asm__ __volatile__("fnstsw %0" : "=m"(*&status)); + status |= excepts; + __asm__ __volatile__("fldcw %0" : : "m"(*&status)); + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int fesetenv(const fenv_t *envp) +{ +#if defined(__amd64__) || defined(__i386__) + __asm__ __volatile__("fldenv %0" : : "m"(*envp)); + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int fesetexceptflag(const fexcept_t *flagp, int excepts) +{ +#if defined(__amd64__) || defined(__i386__) + unsigned int status; + __asm__ __volatile__("fnstsw %0" : "=m"(*&status)); + status &= ~excepts; + status |= *flagp & excepts; + __asm__ __volatile__("fldcw %0" : : "m"(*&status)); + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int fesetround(int round) +{ +#if defined(__amd64__) || defined(__i386__) + unsigned int cw; + if (round != FE_TONEAREST && round != FE_DOWNWARD && round != FE_UPWARD && round != FE_TOWARDZERO) + return -1; + __asm__ __volatile__("fnstcw %0" : "=m"(*&cw)); + cw &= ~0x0C00; + cw |= round; + __asm__ __volatile__("fldcw %0" : : "m"(*&cw)); + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int fetestexcept(int excepts) +{ +#if defined(__amd64__) || defined(__i386__) + unsigned int status; + __asm__ __volatile__("fnstsw %0" : "=m"(*&status)); + return status & excepts; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +} + +export int feupdateenv(const fenv_t *envp) +{ +#if defined(__amd64__) || defined(__i386__) + unsigned int status; + __asm__ __volatile__("fnstsw %0" : "=m"(*&status)); + __asm__ __volatile__("fldenv %0" : : "m"(*envp)); + __asm__ __volatile__("fldcw %0" : : "m"(*&status)); + return 0; +#elif defined(__arm__) + return 0; +#elif defined(__aarch64__) + return 0; +#else +#error "Unsupported architecture" +#endif +}