xref: /openbmc/qemu/target/openrisc/fpu_helper.c (revision dc5bd18f)
1 /*
2  * OpenRISC float helper routines
3  *
4  * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5  *                         Feng Gao <gf91597@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/helper-proto.h"
24 #include "exception.h"
25 #include "fpu/softfloat.h"
26 
27 static inline uint32_t ieee_ex_to_openrisc(OpenRISCCPU *cpu, int fexcp)
28 {
29     int ret = 0;
30     if (fexcp) {
31         if (fexcp & float_flag_invalid) {
32             cpu->env.fpcsr |= FPCSR_IVF;
33             ret = 1;
34         }
35         if (fexcp & float_flag_overflow) {
36             cpu->env.fpcsr |= FPCSR_OVF;
37             ret = 1;
38         }
39         if (fexcp & float_flag_underflow) {
40             cpu->env.fpcsr |= FPCSR_UNF;
41             ret = 1;
42         }
43         if (fexcp & float_flag_divbyzero) {
44             cpu->env.fpcsr |= FPCSR_DZF;
45             ret = 1;
46         }
47         if (fexcp & float_flag_inexact) {
48             cpu->env.fpcsr |= FPCSR_IXF;
49             ret = 1;
50         }
51     }
52 
53     return ret;
54 }
55 
56 static inline void update_fpcsr(OpenRISCCPU *cpu)
57 {
58     int tmp = ieee_ex_to_openrisc(cpu,
59                               get_float_exception_flags(&cpu->env.fp_status));
60 
61     SET_FP_CAUSE(cpu->env.fpcsr, tmp);
62     if ((GET_FP_ENABLE(cpu->env.fpcsr) & tmp) &&
63         (cpu->env.fpcsr & FPCSR_FPEE)) {
64         helper_exception(&cpu->env, EXCP_FPE);
65     } else {
66         UPDATE_FP_FLAGS(cpu->env.fpcsr, tmp);
67     }
68 }
69 
70 uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val)
71 {
72     uint64_t itofd;
73     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
74 
75     set_float_exception_flags(0, &cpu->env.fp_status);
76     itofd = int32_to_float64(val, &cpu->env.fp_status);
77     update_fpcsr(cpu);
78 
79     return itofd;
80 }
81 
82 uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val)
83 {
84     uint32_t itofs;
85     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
86 
87     set_float_exception_flags(0, &cpu->env.fp_status);
88     itofs = int32_to_float32(val, &cpu->env.fp_status);
89     update_fpcsr(cpu);
90 
91     return itofs;
92 }
93 
94 uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val)
95 {
96     uint64_t ftoid;
97     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
98 
99     set_float_exception_flags(0, &cpu->env.fp_status);
100     ftoid = float32_to_int64(val, &cpu->env.fp_status);
101     update_fpcsr(cpu);
102 
103     return ftoid;
104 }
105 
106 uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val)
107 {
108     uint32_t ftois;
109     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
110 
111     set_float_exception_flags(0, &cpu->env.fp_status);
112     ftois = float32_to_int32(val, &cpu->env.fp_status);
113     update_fpcsr(cpu);
114 
115     return ftois;
116 }
117 
118 #define FLOAT_OP(name, p) void helper_float_##_##p(void)
119 
120 #define FLOAT_CALC(name)                                                  \
121 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
122                                      uint64_t fdt0, uint64_t fdt1)        \
123 {                                                                         \
124     uint64_t result;                                                      \
125     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
126     set_float_exception_flags(0, &cpu->env.fp_status);                    \
127     result = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status);           \
128     update_fpcsr(cpu);                                                    \
129     return result;                                                        \
130 }                                                                         \
131                                                                           \
132 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
133                                      uint32_t fdt0, uint32_t fdt1)        \
134 {                                                                         \
135     uint32_t result;                                                      \
136     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
137     set_float_exception_flags(0, &cpu->env.fp_status);                    \
138     result = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status);           \
139     update_fpcsr(cpu);                                                    \
140     return result;                                                        \
141 }                                                                         \
142 
143 FLOAT_CALC(add)
144 FLOAT_CALC(sub)
145 FLOAT_CALC(mul)
146 FLOAT_CALC(div)
147 FLOAT_CALC(rem)
148 #undef FLOAT_CALC
149 
150 
151 uint64_t helper_float_madd_d(CPUOpenRISCState *env, uint64_t a,
152                              uint64_t b, uint64_t c)
153 {
154     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
155     uint64_t result;
156     set_float_exception_flags(0, &cpu->env.fp_status);
157     /* Note that or1ksim doesn't use merged operation.  */
158     result = float64_mul(b, c, &cpu->env.fp_status);
159     result = float64_add(result, a, &cpu->env.fp_status);
160     update_fpcsr(cpu);
161     return result;
162 }
163 
164 uint32_t helper_float_madd_s(CPUOpenRISCState *env, uint32_t a,
165                              uint32_t b, uint32_t c)
166 {
167     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
168     uint32_t result;
169     set_float_exception_flags(0, &cpu->env.fp_status);
170     /* Note that or1ksim doesn't use merged operation.  */
171     result = float32_mul(b, c, &cpu->env.fp_status);
172     result = float32_add(result, a, &cpu->env.fp_status);
173     update_fpcsr(cpu);
174     return result;
175 }
176 
177 
178 #define FLOAT_CMP(name)                                                   \
179 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
180                                      uint64_t fdt0, uint64_t fdt1)        \
181 {                                                                         \
182     int res;                                                              \
183     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
184     set_float_exception_flags(0, &cpu->env.fp_status);                    \
185     res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status);              \
186     update_fpcsr(cpu);                                                    \
187     return res;                                                           \
188 }                                                                         \
189                                                                           \
190 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
191                                              uint32_t fdt0, uint32_t fdt1)\
192 {                                                                         \
193     int res;                                                              \
194     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
195     set_float_exception_flags(0, &cpu->env.fp_status);                    \
196     res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status);              \
197     update_fpcsr(cpu);                                                    \
198     return res;                                                           \
199 }
200 
201 FLOAT_CMP(le)
202 FLOAT_CMP(eq)
203 FLOAT_CMP(lt)
204 #undef FLOAT_CMP
205 
206 
207 #define FLOAT_CMPNE(name)                                                 \
208 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
209                                      uint64_t fdt0, uint64_t fdt1)        \
210 {                                                                         \
211     int res;                                                              \
212     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
213     set_float_exception_flags(0, &cpu->env.fp_status);                    \
214     res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status);             \
215     update_fpcsr(cpu);                                                    \
216     return res;                                                           \
217 }                                                                         \
218                                                                           \
219 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
220                                      uint32_t fdt0, uint32_t fdt1)        \
221 {                                                                         \
222     int res;                                                              \
223     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
224     set_float_exception_flags(0, &cpu->env.fp_status);                    \
225     res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status);             \
226     update_fpcsr(cpu);                                                    \
227     return res;                                                           \
228 }
229 
230 FLOAT_CMPNE(ne)
231 #undef FLOAT_CMPNE
232 
233 #define FLOAT_CMPGT(name)                                                 \
234 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
235                                      uint64_t fdt0, uint64_t fdt1)        \
236 {                                                                         \
237     int res;                                                              \
238     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
239     set_float_exception_flags(0, &cpu->env.fp_status);                    \
240     res = !float64_le(fdt0, fdt1, &cpu->env.fp_status);                   \
241     update_fpcsr(cpu);                                                    \
242     return res;                                                           \
243 }                                                                         \
244                                                                           \
245 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
246                                      uint32_t fdt0, uint32_t fdt1)        \
247 {                                                                         \
248     int res;                                                              \
249     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
250     set_float_exception_flags(0, &cpu->env.fp_status);                    \
251     res = !float32_le(fdt0, fdt1, &cpu->env.fp_status);                   \
252     update_fpcsr(cpu);                                                    \
253     return res;                                                           \
254 }
255 FLOAT_CMPGT(gt)
256 #undef FLOAT_CMPGT
257 
258 #define FLOAT_CMPGE(name)                                                 \
259 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
260                                      uint64_t fdt0, uint64_t fdt1)        \
261 {                                                                         \
262     int res;                                                              \
263     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
264     set_float_exception_flags(0, &cpu->env.fp_status);                    \
265     res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status);                   \
266     update_fpcsr(cpu);                                                    \
267     return res;                                                           \
268 }                                                                         \
269                                                                           \
270 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
271                                      uint32_t fdt0, uint32_t fdt1)        \
272 {                                                                         \
273     int res;                                                              \
274     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
275     set_float_exception_flags(0, &cpu->env.fp_status);                    \
276     res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status);                   \
277     update_fpcsr(cpu);                                                    \
278     return res;                                                           \
279 }
280 
281 FLOAT_CMPGE(ge)
282 #undef FLOAT_CMPGE
283