xref: /reactos/sdk/lib/crt/float/arm/_controlfp.c (revision 84344399)
1 /*
2  * PROJECT:     ReactOS CRT library
3  * LICENSE:     MIT (https://spdx.org/licenses/MIT)
4  * PURPOSE:     Implementation of _controlfp
5  * COPYRIGHT:   Copyright 2021 Roman Masanin <36927roma@gmail.com>
6  */
7 
8 #include <precomp.h>
9 #include "fpscr.h"
10 
11 unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask)
12 {
13     return _control87(newval, mask & ~_EM_DENORMAL);
14 }
15 
16 unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
17 {
18     ARM_FPSCR fpscr;
19     unsigned int flags = 0;
20 
21     TRACE("(%08x, %08x): Called\n", newval, mask);
22 
23     /* Get fp control word */
24     fpscr.raw = __getfp();
25 
26     TRACE("Control word before : %08x\n", fpscr.raw);
27 
28     /* Convert into mask constants */
29     if (!(fpscr.data.ex_control & ARM_CW_IM)) flags |= _EM_INVALID;
30     if (!(fpscr.data.ex_control & ARM_CW_ZM)) flags |= _EM_ZERODIVIDE;
31     if (!(fpscr.data.ex_control & ARM_CW_OM)) flags |= _EM_OVERFLOW;
32     if (!(fpscr.data.ex_control & ARM_CW_UM)) flags |= _EM_UNDERFLOW;
33     if (!(fpscr.data.ex_control & ARM_CW_PM)) flags |= _EM_INEXACT;
34     if (!(fpscr.data.ex_control & ARM_CW_DM)) flags |= _EM_DENORMAL;
35 
36     switch (fpscr.data.rounding_mode)
37     {
38         case ARM_CW_RC_ZERO: flags |= _RC_UP|_RC_DOWN; break;
39         case ARM_CW_RC_UP:   flags |= _RC_UP; break;
40         case ARM_CW_RC_DOWN: flags |= _RC_DOWN; break;
41     }
42 
43     /* Mask with parameters */
44     flags = (flags & ~mask) | (newval & mask);
45 
46     /* Convert (masked) value back to fp word */
47     fpscr.raw = 0;
48     if (!(flags & _EM_INVALID))    fpscr.data.ex_control |= ARM_CW_IM;
49     if (!(flags & _EM_ZERODIVIDE)) fpscr.data.ex_control |= ARM_CW_ZM;
50     if (!(flags & _EM_OVERFLOW))   fpscr.data.ex_control |= ARM_CW_OM;
51     if (!(flags & _EM_UNDERFLOW))  fpscr.data.ex_control |= ARM_CW_UM;
52     if (!(flags & _EM_INEXACT))    fpscr.data.ex_control |= ARM_CW_PM;
53     if (!(flags & _EM_DENORMAL))   fpscr.data.ex_control |= ARM_CW_DM;
54 
55     switch (flags & (_RC_UP | _RC_DOWN))
56     {
57         case _RC_UP|_RC_DOWN: fpscr.data.rounding_mode = ARM_CW_RC_ZERO; break;
58         case _RC_UP:          fpscr.data.rounding_mode = ARM_CW_RC_UP; break;
59         case _RC_DOWN:        fpscr.data.rounding_mode = ARM_CW_RC_DOWN; break;
60         case _RC_NEAR:        fpscr.data.rounding_mode = ARM_CW_RC_NEAREST; break;
61     }
62 
63     TRACE("Control word after  : %08x\n", fpscr.raw);
64 
65     /* Put fp control word */
66     __setfp(fpscr.raw);
67 
68     return flags;
69 }
70 
71