1 /* Copyright (c) 2017  SiFive Inc. All rights reserved.
2 
3    This copyrighted material is made available to anyone wishing to use,
4    modify, copy, or redistribute it subject to the terms and conditions
5    of the FreeBSD License.   This program is distributed in the hope that
6    it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
7    including the implied warranties of MERCHANTABILITY or FITNESS FOR
8    A PARTICULAR PURPOSE.  A copy of this license is available at
9    http://www.opensource.org/licenses.
10 */
11 
12 #include <ieeefp.h>
13 
14 #if defined(__riscv_flen) || defined (__riscv_zfinx)
15 static void
fssr(unsigned value)16 fssr(unsigned value)
17 {
18   __asm__ volatile ("fscsr %0" :: "r"(value));
19 }
20 
21 static unsigned
frsr(void)22 frsr(void)
23 {
24   unsigned value;
25   __asm__ volatile ("frcsr %0" : "=r" (value));
26   return value;
27 }
28 
29 static fp_rnd
frm_fp_rnd(unsigned frm)30 frm_fp_rnd (unsigned frm)
31 {
32   switch (frm)
33     {
34     case 0: return FP_RN;
35     case 1: return FP_RZ;
36     case 2: return FP_RM;
37     case 3: return FP_RP;
38     /* 4 ~ 7 is invalid value, so just retun FP_RP.  */
39     default:return FP_RP;
40     }
41 }
42 
43 static fp_except
frm_fp_except(unsigned except)44 frm_fp_except (unsigned except)
45 {
46   fp_except fp = 0;
47   if (except & (1 << 0))
48     fp |= FP_X_IMP;
49   if (except & (1 << 1))
50     fp |= FP_X_UFL;
51   if (except & (1 << 2))
52     fp |= FP_X_OFL;
53   if (except & (1 << 3))
54     fp |= FP_X_DX;
55   if (except & (1 << 4))
56     fp |= FP_X_INV;
57   return fp;
58 }
59 
60 static unsigned
frm_except(fp_except fp)61 frm_except(fp_except fp)
62 {
63   unsigned except = 0;
64   if (fp & FP_X_IMP)
65     except |= (1 << 0);
66   if (fp & FP_X_UFL)
67     except |= (1 << 1);
68   if (fp & FP_X_OFL)
69     except |= (1 << 2);
70   if (fp & FP_X_DX)
71     except |= (1 << 3);
72   if (fp & FP_X_INV)
73     except |= (1 << 4);
74   return except;
75 }
76 
77 #endif /* __riscv_flen */
78 
79 fp_except
fpgetmask(void)80 fpgetmask(void)
81 {
82   return 0;
83 }
84 
85 fp_rnd
fpgetround(void)86 fpgetround(void)
87 {
88 #if defined(__riscv_flen) || defined (__riscv_zfinx)
89   unsigned rm = (frsr () >> 5) & 0x7;
90   return frm_fp_rnd (rm);
91 #else
92   return FP_RZ;
93 #endif /* __riscv_flen */
94 }
95 
96 fp_except
fpgetsticky(void)97 fpgetsticky(void)
98 {
99 #if defined(__riscv_flen) || defined (__riscv_zfinx)
100   return frm_fp_except(frsr ());
101 #else
102   return 0;
103 #endif /* __riscv_flen */
104 }
105 
106 fp_except
fpsetmask(fp_except mask)107 fpsetmask(fp_except mask)
108 {
109   (void) mask;
110   return -1;
111 }
112 
113 fp_rnd
fpsetround(fp_rnd rnd_dir)114 fpsetround(fp_rnd rnd_dir)
115 {
116 #if defined(__riscv_flen) || defined (__riscv_zfinx)
117   unsigned fsr = frsr ();
118   unsigned rm = (fsr >> 5) & 0x7;
119   unsigned new_rm;
120   switch (rnd_dir)
121     {
122     case FP_RN: new_rm = 0; break;
123     case FP_RZ: new_rm = 1; break;
124     case FP_RM: new_rm = 2; break;
125     case FP_RP: new_rm = 3; break;
126     default:    return -1;
127     }
128   fssr (new_rm << 5 | (fsr & 0x1f));
129   return frm_fp_rnd (rm);
130 #else
131   (void) rnd_dir;
132   return -1;
133 #endif /* __riscv_flen */
134 }
135 
136 fp_except
fpsetsticky(fp_except sticky)137 fpsetsticky(fp_except sticky)
138 {
139 #if defined(__riscv_flen) || defined (__riscv_zfinx)
140   unsigned fsr = frsr ();
141   fssr (frm_except(sticky) | (fsr & ~0x1f));
142   return frm_fp_except(fsr);
143 #else
144   (void) sticky;
145   return -1;
146 #endif /* __riscv_flen */
147 }
148 
fpgetroundtoi(void)149 fp_rdi fpgetroundtoi (void)
150 {
151   return 0;
152 }
153 
fpsetroundtoi(fp_rdi rdi)154 fp_rdi fpsetroundtoi (fp_rdi rdi)
155 {
156   (void) rdi;
157   return -1;
158 }
159