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 #define _BSD_SOURCE
13 #include <picolibc.h>
14 #include <ieeefp.h>
15 
16 #if defined(__riscv_flen) || defined (__riscv_zfinx)
17 static void
fssr(unsigned value)18 fssr(unsigned value)
19 {
20   __asm__ volatile ("fscsr %0" :: "r"(value));
21 }
22 
23 static unsigned
frsr(void)24 frsr(void)
25 {
26   unsigned value;
27   __asm__ volatile ("frcsr %0" : "=r" (value));
28   return value;
29 }
30 
31 static fp_rnd
frm_fp_rnd(unsigned frm)32 frm_fp_rnd (unsigned frm)
33 {
34   switch (frm)
35     {
36     case 0: return FP_RN;
37     case 1: return FP_RZ;
38     case 2: return FP_RM;
39     case 3: return FP_RP;
40     /* 4 ~ 7 is invalid value, so just retun FP_RP.  */
41     default:return FP_RP;
42     }
43 }
44 
45 static fp_except
frm_fp_except(unsigned except)46 frm_fp_except (unsigned except)
47 {
48   fp_except fp = 0;
49   if (except & (1 << 0))
50     fp |= FP_X_IMP;
51   if (except & (1 << 1))
52     fp |= FP_X_UFL;
53   if (except & (1 << 2))
54     fp |= FP_X_OFL;
55   if (except & (1 << 3))
56     fp |= FP_X_DX;
57   if (except & (1 << 4))
58     fp |= FP_X_INV;
59   return fp;
60 }
61 
62 static unsigned
frm_except(fp_except fp)63 frm_except(fp_except fp)
64 {
65   unsigned except = 0;
66   if (fp & FP_X_IMP)
67     except |= (1 << 0);
68   if (fp & FP_X_UFL)
69     except |= (1 << 1);
70   if (fp & FP_X_OFL)
71     except |= (1 << 2);
72   if (fp & FP_X_DX)
73     except |= (1 << 3);
74   if (fp & FP_X_INV)
75     except |= (1 << 4);
76   return except;
77 }
78 
79 #endif /* __riscv_flen */
80 
81 fp_except
fpgetmask(void)82 fpgetmask(void)
83 {
84   return 0;
85 }
86 
87 fp_rnd
fpgetround(void)88 fpgetround(void)
89 {
90 #if defined(__riscv_flen) || defined (__riscv_zfinx)
91   unsigned rm = (frsr () >> 5) & 0x7;
92   return frm_fp_rnd (rm);
93 #else
94   return FP_RZ;
95 #endif /* __riscv_flen */
96 }
97 
98 fp_except
fpgetsticky(void)99 fpgetsticky(void)
100 {
101 #if defined(__riscv_flen) || defined (__riscv_zfinx)
102   return frm_fp_except(frsr ());
103 #else
104   return 0;
105 #endif /* __riscv_flen */
106 }
107 
108 fp_except
fpsetmask(fp_except mask)109 fpsetmask(fp_except mask)
110 {
111   (void) mask;
112   return -1;
113 }
114 
115 fp_rnd
fpsetround(fp_rnd rnd_dir)116 fpsetround(fp_rnd rnd_dir)
117 {
118 #if defined(__riscv_flen) || defined (__riscv_zfinx)
119   unsigned fsr = frsr ();
120   unsigned rm = (fsr >> 5) & 0x7;
121   unsigned new_rm;
122   switch (rnd_dir)
123     {
124     case FP_RN: new_rm = 0; break;
125     case FP_RZ: new_rm = 1; break;
126     case FP_RM: new_rm = 2; break;
127     case FP_RP: new_rm = 3; break;
128     default:    return -1;
129     }
130   fssr (new_rm << 5 | (fsr & 0x1f));
131   return frm_fp_rnd (rm);
132 #else
133   (void) rnd_dir;
134   return -1;
135 #endif /* __riscv_flen */
136 }
137 
138 fp_except
fpsetsticky(fp_except sticky)139 fpsetsticky(fp_except sticky)
140 {
141 #if defined(__riscv_flen) || defined (__riscv_zfinx)
142   unsigned fsr = frsr ();
143   fssr (frm_except(sticky) | (fsr & ~0x1f));
144   return frm_fp_except(fsr);
145 #else
146   (void) sticky;
147   return -1;
148 #endif /* __riscv_flen */
149 }
150 
fpgetroundtoi(void)151 fp_rdi fpgetroundtoi (void)
152 {
153   return 0;
154 }
155 
fpsetroundtoi(fp_rdi rdi)156 fp_rdi fpsetroundtoi (fp_rdi rdi)
157 {
158   (void) rdi;
159   return -1;
160 }
161