|
|
dc2340 |
/**************************************************************************/
|
|
|
dc2340 |
/* mmglue: midipix architecture- and target-specific bits for musl libc */
|
|
|
dc2340 |
/* Copyright (C) 2013--2023 SysDeer Technologies, LLC */
|
|
|
dc2340 |
/* Released under the Standard MIT License; see COPYING.MMGLUE. */
|
|
|
dc2340 |
/**************************************************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
.file "fenv.S"
|
|
|
dc2340 |
|
|
|
dc2340 |
/* common exception bits */
|
|
|
dc2340 |
#define FE_INVALID (1 << 0)
|
|
|
dc2340 |
#define FE_DENORM (1 << 1)
|
|
|
dc2340 |
#define FE_DIVBYZERO (1 << 2)
|
|
|
dc2340 |
#define FE_OVERFLOW (1 << 3)
|
|
|
dc2340 |
#define FE_UNDERFLOW (1 << 4)
|
|
|
dc2340 |
#define FE_INEXACT (1 << 5)
|
|
|
dc2340 |
|
|
|
dc2340 |
#define FE_ALL_EXCEPT (0x3F)
|
|
|
dc2340 |
|
|
|
dc2340 |
/* X87 FPU rounding control bits */
|
|
|
dc2340 |
#define FPU_RC_TONEAREST (0x0 << 10)
|
|
|
dc2340 |
#define FPU_RC_DOWNWARD (0x1 << 10)
|
|
|
dc2340 |
#define FPU_RC_UPWARD (0x2 << 10)
|
|
|
dc2340 |
#define FPU_RC_TOWARDZERO (0x3 << 10)
|
|
|
dc2340 |
#define FPU_RC_MASK FPU_RC_TOWARDZERO
|
|
|
dc2340 |
|
|
|
dc2340 |
/* X87 FPU control word */
|
|
|
dc2340 |
#define FPU_CW_MASK (0xFFFF)
|
|
|
dc2340 |
#define FPU_CW_RC_MASK (FPU_CW_MASK ^ FPU_RC_MASK)
|
|
|
dc2340 |
|
|
|
dc2340 |
/* MXCSR rounding control bits */
|
|
|
dc2340 |
#define MXCSR_RC_TONEAREST (0X0 << 13)
|
|
|
dc2340 |
#define MXCSR_RC_DOWNWARD (0x1 << 13)
|
|
|
dc2340 |
#define MXCSR_RC_UPWARD (0x2 << 13)
|
|
|
dc2340 |
#define MXCSR_RC_TOWARDZERO (0x3 << 13)
|
|
|
dc2340 |
#define MXCSR_RC_MASK MXCSR_RC_TOWARDZERO
|
|
|
dc2340 |
|
|
|
dc2340 |
/* MXCSR control word */
|
|
|
dc2340 |
#define MXCSR_CW_MASK (0xFFFF)
|
|
|
dc2340 |
#define MXCSR_CW_RC_MASK (MXCSR_CW_MASK ^ MXCSR_RC_MASK)
|
|
|
dc2340 |
|
|
|
dc2340 |
/* fenv_At struct definition */
|
|
|
dc2340 |
#define FPUCW_MEMBER_OFFSET (0x0)
|
|
|
dc2340 |
#define MXCSR_MEMBER_OFFSET (0x1C)
|
|
|
dc2340 |
|
|
|
dc2340 |
/* user rounding control flags */
|
|
|
dc2340 |
#define FE_RC_TONEAREST FPU_RC_TONEAREST
|
|
|
dc2340 |
#define FE_RC_DOWNWARD FPU_RC_DOWNWARD
|
|
|
dc2340 |
#define FE_RC_UPWARD FPU_RC_UPWARD
|
|
|
dc2340 |
#define FE_RC_TOWARDZERO FPU_RC_TOWARDZERO
|
|
|
dc2340 |
#define FE_RC_MASK FPU_RC_MASK
|
|
|
dc2340 |
|
|
|
dc2340 |
/* user default float environment */
|
|
|
dc2340 |
#define FE_DFL_ENV (-1)
|
|
|
dc2340 |
|
|
|
dc2340 |
/******************************************************/
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* FSTCW: check for pending floating-point */
|
|
|
dc2340 |
/* exceptions, then store FPU control word. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* FNSTCW: store FPU control word without first */
|
|
|
dc2340 |
/* checking for pending floating-point */
|
|
|
dc2340 |
/* exceptions. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* FSTSW: check for pending floating-point */
|
|
|
dc2340 |
/* exceptions, then store FPU status word. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* FNSTSW: store FPU status word without first */
|
|
|
dc2340 |
/* checking for pending floating-point */
|
|
|
dc2340 |
/* exceptions. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* FCLEX: check for pending floating-point */
|
|
|
dc2340 |
/* exceptions, then clear FPU exception */
|
|
|
dc2340 |
/* flags. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* FNCLEX: clear FPU exception flags without first */
|
|
|
dc2340 |
/* checking for pending floating-point */
|
|
|
dc2340 |
/* exceptions. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* FLDCW: set the FPU Control Word from memory. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* FLDENV: set the FPU Environment from memory. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* STMXCSR: store the state of the MXCSR register; */
|
|
|
dc2340 |
/* the register's reserved bits are set to */
|
|
|
dc2340 |
/* zero in the destination. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* LDMXCSR: set the MXCSR environment from memory. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/******************************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
/* int fetestexcept(int exflags); */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* query which exception flags, as indicated */
|
|
|
dc2340 |
/* by the exflags mask, are currently set. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
.text
|
|
|
dc2340 |
.def fetestexcept; .scl 2; .type 32; .endef
|
|
|
dc2340 |
.global fetestexcept
|
|
|
dc2340 |
|
|
|
dc2340 |
.cfi_startproc;
|
|
|
dc2340 |
fetestexcept:
|
|
|
dc2340 |
and $FE_ALL_EXCEPT,%ecx /* normalize exflags */
|
|
|
dc2340 |
push %r10 /* temporary state var */
|
|
|
dc2340 |
stmxcsr (%rsp) /* store mxcsr state */
|
|
|
dc2340 |
pop %rdx /* copy state to rdx */
|
|
|
dc2340 |
fnstsw %ax /* store fpu state */
|
|
|
dc2340 |
or %edx,%eax /* fpu+mxcsr state */
|
|
|
dc2340 |
and %ecx,%eax /* desired flags only */
|
|
|
dc2340 |
ret
|
|
|
dc2340 |
.cfi_endproc
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
/* int feclearexcept(int exflags); */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* clear specific fpu exception flags, as */
|
|
|
dc2340 |
/* indicated by the exflags mask. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
.text
|
|
|
dc2340 |
.def feclearexcept; .scl 2; .type 32; .endef
|
|
|
dc2340 |
.global feclearexcept
|
|
|
dc2340 |
|
|
|
dc2340 |
.cfi_startproc;
|
|
|
dc2340 |
feclearexcept:
|
|
|
dc2340 |
fnstsw %ax /* store fpu state */
|
|
|
dc2340 |
and $FE_ALL_EXCEPT,%ecx /* normalize exflags */
|
|
|
dc2340 |
and $FE_ALL_EXCEPT,%eax /* normalize fpu state */
|
|
|
dc2340 |
test %ecx,%eax /* test exflags,state */
|
|
|
dc2340 |
jz 1f /* state already clear? */
|
|
|
dc2340 |
fnclex /* clear fpu state */
|
|
|
dc2340 |
1: push %rdx /* temporary state var */
|
|
|
dc2340 |
stmxcsr (%rsp) /* store mxcsr state */
|
|
|
dc2340 |
pop %rdx /* copy state to rdx */
|
|
|
dc2340 |
or %eax,%edx /* fpu+mxcsr state */
|
|
|
dc2340 |
test %ecx,%edx /* test exflags,state */
|
|
|
dc2340 |
jz 1f /* state already clear? */
|
|
|
dc2340 |
not %ecx /* clear desired flags- */
|
|
|
dc2340 |
and %ecx,%edx /* -from mxcsr state */
|
|
|
dc2340 |
push %rdx /* modified mxcsr var */
|
|
|
dc2340 |
ldmxcsr (%rsp) /* update mxcsr */
|
|
|
dc2340 |
pop %rdx /* dealloc mxcsr var */
|
|
|
dc2340 |
1: xor %eax,%eax /* ret zero either way */
|
|
|
dc2340 |
ret
|
|
|
dc2340 |
.cfi_endproc
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
/* int feraiseexcept(int exflags); */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* set specific fpu exception flags, as */
|
|
|
dc2340 |
/* indicated by the exflags mask. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* it is enough to set the flags only in */
|
|
|
dc2340 |
/* either mxcsr or the [legacy] x87 fpu, */
|
|
|
dc2340 |
/* specifically since fetestexcept() does */
|
|
|
dc2340 |
/* take both into account. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
.text
|
|
|
dc2340 |
.def feraiseexcept; .scl 2; .type 32; .endef
|
|
|
dc2340 |
.global feraiseexcept
|
|
|
dc2340 |
|
|
|
dc2340 |
.cfi_startproc;
|
|
|
dc2340 |
feraiseexcept:
|
|
|
dc2340 |
and $FE_ALL_EXCEPT,%ecx /* normalize exflags */
|
|
|
dc2340 |
stmxcsr -0x8(%rsp) /* store mxcsr state */
|
|
|
dc2340 |
or %ecx,-0x8(%rsp) /* set desired flags */
|
|
|
dc2340 |
ldmxcsr -0x8(%rsp) /* update mxcsr */
|
|
|
dc2340 |
xor %eax,%eax
|
|
|
dc2340 |
ret
|
|
|
dc2340 |
.cfi_endproc
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
/* int fegetround(void); */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* obtain the current rounding mode, which */
|
|
|
dc2340 |
/* should be one of: round-to-neareset, */
|
|
|
dc2340 |
/* round-downwards, round-upwards, or */
|
|
|
dc2340 |
/* round-toward-zero. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* when we set the rounding mode we set both */
|
|
|
dc2340 |
/* mxcsr and the [legacy] x87 fpu, and it */
|
|
|
dc2340 |
/* thus suffices to obtain the mode from */
|
|
|
dc2340 |
/* either, which is mxcsr in our case. */
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
.text
|
|
|
dc2340 |
.def fegetround; .scl 2; .type 32; .endef
|
|
|
dc2340 |
.global fegetround
|
|
|
dc2340 |
|
|
|
dc2340 |
.cfi_startproc;
|
|
|
dc2340 |
fegetround:
|
|
|
dc2340 |
push %rdx /* temporary state var */
|
|
|
dc2340 |
stmxcsr (%rsp) /* store mxcsr state */
|
|
|
dc2340 |
pop %rax /* copy state to rax */
|
|
|
dc2340 |
and $MXCSR_RC_MASK,%rax /* MXCSR RC bits only */
|
|
|
dc2340 |
shr $0x3,%rax /* MXCSR --> FE bits */
|
|
|
dc2340 |
ret
|
|
|
dc2340 |
.cfi_endproc
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
/* int fesetround(int rcmode); */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* set the current rounding mode, which */
|
|
|
dc2340 |
/* should be one of: round-to-neareset, */
|
|
|
dc2340 |
/* round-downwards, round-upwards, or */
|
|
|
dc2340 |
/* round-toward-zero. */
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
.text
|
|
|
dc2340 |
.def __fesetround; .scl 2; .type 32; .endef
|
|
|
dc2340 |
.global __fesetround
|
|
|
dc2340 |
|
|
|
dc2340 |
.cfi_startproc;
|
|
|
dc2340 |
__fesetround:
|
|
|
dc2340 |
push %rdx /* alloc control var */
|
|
|
dc2340 |
and $FE_RC_MASK,%ecx /* normalize rcarg */
|
|
|
dc2340 |
fnstcw (%rsp) /* current control word */
|
|
|
dc2340 |
andw $FPU_CW_RC_MASK,(%rsp) /* control word only */
|
|
|
dc2340 |
or %ecx,(%rsp) /* set rc bits to rcarg */
|
|
|
dc2340 |
fldcw (%rsp) /* set fpu control word */
|
|
|
dc2340 |
shl $0x3,%ecx /* rcarg: FPU --> MXCSR */
|
|
|
dc2340 |
stmxcsr (%rsp) /* current mxcsr reg */
|
|
|
dc2340 |
andw $MXCSR_CW_RC_MASK,(%rsp) /* control word only */
|
|
|
dc2340 |
or %ecx,(%rsp) /* set rc bits to rcarg */
|
|
|
dc2340 |
ldmxcsr (%rsp) /* set mxcsr ctrl word */
|
|
|
dc2340 |
pop %rdx /* dealloc control var */
|
|
|
dc2340 |
xor %eax,%eax
|
|
|
dc2340 |
ret
|
|
|
dc2340 |
.cfi_endproc
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
/* int fegetenv(fenv_t *); */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* popualte a structure of type fenv_t with */
|
|
|
dc2340 |
/* the current X87 FPU environmtnet (fnstenv) */
|
|
|
dc2340 |
/* as well as MXCSR environment (stmxcsr). */
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
.text
|
|
|
dc2340 |
.def fegetenv; .scl 2; .type 32; .endef
|
|
|
dc2340 |
.global fegetenv
|
|
|
dc2340 |
|
|
|
dc2340 |
.cfi_startproc;
|
|
|
dc2340 |
fegetenv:
|
|
|
dc2340 |
fnstenv FPUCW_MEMBER_OFFSET(%rcx)
|
|
|
dc2340 |
stmxcsr MXCSR_MEMBER_OFFSET(%rcx)
|
|
|
dc2340 |
xor %eax,%eax
|
|
|
dc2340 |
ret
|
|
|
dc2340 |
.cfi_endproc
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
/* int fesetenv(cont fenv_t *); */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* (re)initialize the X87 FPU and MXCSR */
|
|
|
dc2340 |
/* environments from a user structure of */
|
|
|
dc2340 |
/* type fenv_t. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* if the pointer to the fenv_t structure is */
|
|
|
dc2340 |
/* FE_DFL_ENV, reset the X87 FPU and MXCSR */
|
|
|
dc2340 |
/* environments to theit default values as */
|
|
|
dc2340 |
/* defined by the architecture. */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/* .__control_word = 0x037f, */
|
|
|
dc2340 |
/* .__unused1 = N/A, */
|
|
|
dc2340 |
/* .__status_word = 0x0, */
|
|
|
dc2340 |
/* .__unused2 = N/A, */
|
|
|
dc2340 |
/* .__tags = 0xffff, */
|
|
|
dc2340 |
/* .__unused3 = N/A, */
|
|
|
dc2340 |
/* .__eip = 0x0, */
|
|
|
dc2340 |
/* .__cs_selector = 0x0, */
|
|
|
dc2340 |
/* .__opcode = 0x0, */
|
|
|
dc2340 |
/* .__unused4 = N/A, */
|
|
|
dc2340 |
/* .__data_offset = 0x0, */
|
|
|
dc2340 |
/* .__data_selector = 0x0, */
|
|
|
dc2340 |
/* .__unused5 = N/A, */
|
|
|
dc2340 |
/* .__mxcsr = 0x1f80 */
|
|
|
dc2340 |
/* */
|
|
|
dc2340 |
/**********************************************/
|
|
|
dc2340 |
|
|
|
dc2340 |
.text
|
|
|
dc2340 |
.def fesetenv; .scl 2; .type 32; .endef
|
|
|
dc2340 |
.global fesetenv
|
|
|
dc2340 |
|
|
|
dc2340 |
.cfi_startproc;
|
|
|
dc2340 |
fesetenv:
|
|
|
dc2340 |
/* prolog */
|
|
|
dc2340 |
xor %eax,%eax
|
|
|
dc2340 |
|
|
|
dc2340 |
/* use fenv_t or reset to default values? */
|
|
|
dc2340 |
cmpq $FE_DFL_ENV,%rcx
|
|
|
dc2340 |
jz 1f
|
|
|
dc2340 |
|
|
|
dc2340 |
/* use the user-provided fenv_t */
|
|
|
dc2340 |
fldenv FPUCW_MEMBER_OFFSET(%rcx)
|
|
|
dc2340 |
ldmxcsr MXCSR_MEMBER_OFFSET(%rcx)
|
|
|
dc2340 |
ret
|
|
|
dc2340 |
|
|
|
dc2340 |
/* reset environments to the architecture-defined defaults */
|
|
|
dc2340 |
1: subq $0x20,%rsp
|
|
|
dc2340 |
|
|
|
dc2340 |
/* X87 FPU */
|
|
|
dc2340 |
movq $0x037f,(0x0)(%rsp)
|
|
|
dc2340 |
movq $0xffff,(0x8)(%rsp)
|
|
|
dc2340 |
movq $0x0,(0x10)(%rsp)
|
|
|
dc2340 |
movq $0x0,(0x18)(%rsp)
|
|
|
dc2340 |
fldenv (%rsp)
|
|
|
dc2340 |
|
|
|
dc2340 |
/* MXCSR */
|
|
|
dc2340 |
movq $0x1f80,(%rsp)
|
|
|
dc2340 |
ldmxcsr (%rsp)
|
|
|
dc2340 |
|
|
|
dc2340 |
/* all done */
|
|
|
dc2340 |
addq $0x20,%rsp
|
|
|
dc2340 |
ret
|
|
|
dc2340 |
.cfi_endproc
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
.section .got$fetestexcept
|
|
|
dc2340 |
.global __imp_fetestexcept
|
|
|
dc2340 |
__imp_fetestexcept:
|
|
|
dc2340 |
.quad fetestexcept
|
|
|
dc2340 |
.linkonce discard
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
.section .got$feclearexcept
|
|
|
dc2340 |
.global __imp_feclearexcept
|
|
|
dc2340 |
__imp_feclearexcept:
|
|
|
dc2340 |
.quad feclearexcept
|
|
|
dc2340 |
.linkonce discard
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
.section .got$feraiseexcept
|
|
|
dc2340 |
.global __imp_feraiseexcept
|
|
|
dc2340 |
__imp_feraiseexcept:
|
|
|
dc2340 |
.quad feraiseexcept
|
|
|
dc2340 |
.linkonce discard
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
.section .got$fegetround
|
|
|
dc2340 |
.global __imp_fegetround
|
|
|
dc2340 |
__imp_fegetround:
|
|
|
dc2340 |
.quad fegetround
|
|
|
dc2340 |
.linkonce discard
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
.section .got$__fesetround
|
|
|
dc2340 |
.global __imp___fesetround
|
|
|
dc2340 |
__imp___fesetround:
|
|
|
dc2340 |
.quad __fesetround
|
|
|
dc2340 |
.linkonce discard
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
.section .got$fegetenv
|
|
|
dc2340 |
.global __imp_fegetenv
|
|
|
dc2340 |
__imp_fegetenv:
|
|
|
dc2340 |
.quad fegetenv
|
|
|
dc2340 |
.linkonce discard
|
|
|
dc2340 |
|
|
|
dc2340 |
|
|
|
dc2340 |
.section .got$fesetenv
|
|
|
dc2340 |
.global __imp_fesetenv
|
|
|
dc2340 |
__imp_fesetenv:
|
|
|
dc2340 |
.quad fesetenv
|
|
|
dc2340 |
.linkonce discard
|