xref: /qemu/target/riscv/fpu_helper.c (revision 138ca49a)
1 /*
2  * RISC-V FPU Emulation Helpers for QEMU.
3  *
4  * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2 or later, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "qemu/osdep.h"
20 #include "cpu.h"
21 #include "qemu/host-utils.h"
22 #include "exec/exec-all.h"
23 #include "exec/helper-proto.h"
24 #include "fpu/softfloat.h"
25 #include "internals.h"
26 
27 target_ulong riscv_cpu_get_fflags(CPURISCVState *env)
28 {
29     int soft = get_float_exception_flags(&env->fp_status);
30     target_ulong hard = 0;
31 
32     hard |= (soft & float_flag_inexact) ? FPEXC_NX : 0;
33     hard |= (soft & float_flag_underflow) ? FPEXC_UF : 0;
34     hard |= (soft & float_flag_overflow) ? FPEXC_OF : 0;
35     hard |= (soft & float_flag_divbyzero) ? FPEXC_DZ : 0;
36     hard |= (soft & float_flag_invalid) ? FPEXC_NV : 0;
37 
38     return hard;
39 }
40 
41 void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong hard)
42 {
43     int soft = 0;
44 
45     soft |= (hard & FPEXC_NX) ? float_flag_inexact : 0;
46     soft |= (hard & FPEXC_UF) ? float_flag_underflow : 0;
47     soft |= (hard & FPEXC_OF) ? float_flag_overflow : 0;
48     soft |= (hard & FPEXC_DZ) ? float_flag_divbyzero : 0;
49     soft |= (hard & FPEXC_NV) ? float_flag_invalid : 0;
50 
51     set_float_exception_flags(soft, &env->fp_status);
52 }
53 
54 void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm)
55 {
56     int softrm;
57 
58     if (rm == 7) {
59         rm = env->frm;
60     }
61     switch (rm) {
62     case 0:
63         softrm = float_round_nearest_even;
64         break;
65     case 1:
66         softrm = float_round_to_zero;
67         break;
68     case 2:
69         softrm = float_round_down;
70         break;
71     case 3:
72         softrm = float_round_up;
73         break;
74     case 4:
75         softrm = float_round_ties_away;
76         break;
77     default:
78         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
79     }
80 
81     set_float_rounding_mode(softrm, &env->fp_status);
82 }
83 
84 static uint64_t do_fmadd_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2,
85                            uint64_t rs3, int flags)
86 {
87     float32 frs1 = check_nanbox_s(rs1);
88     float32 frs2 = check_nanbox_s(rs2);
89     float32 frs3 = check_nanbox_s(rs3);
90     return nanbox_s(float32_muladd(frs1, frs2, frs3, flags, &env->fp_status));
91 }
92 
93 uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
94                         uint64_t frs3)
95 {
96     return do_fmadd_s(env, frs1, frs2, frs3, 0);
97 }
98 
99 uint64_t helper_fmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
100                         uint64_t frs3)
101 {
102     return float64_muladd(frs1, frs2, frs3, 0, &env->fp_status);
103 }
104 
105 uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
106                         uint64_t frs3)
107 {
108     return do_fmadd_s(env, frs1, frs2, frs3, float_muladd_negate_c);
109 }
110 
111 uint64_t helper_fmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
112                         uint64_t frs3)
113 {
114     return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c,
115                           &env->fp_status);
116 }
117 
118 uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
119                          uint64_t frs3)
120 {
121     return do_fmadd_s(env, frs1, frs2, frs3, float_muladd_negate_product);
122 }
123 
124 uint64_t helper_fnmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
125                          uint64_t frs3)
126 {
127     return float64_muladd(frs1, frs2, frs3, float_muladd_negate_product,
128                           &env->fp_status);
129 }
130 
131 uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
132                          uint64_t frs3)
133 {
134     return do_fmadd_s(env, frs1, frs2, frs3,
135                       float_muladd_negate_c | float_muladd_negate_product);
136 }
137 
138 uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
139                          uint64_t frs3)
140 {
141     return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c |
142                           float_muladd_negate_product, &env->fp_status);
143 }
144 
145 uint64_t helper_fadd_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
146 {
147     float32 frs1 = check_nanbox_s(rs1);
148     float32 frs2 = check_nanbox_s(rs2);
149     return nanbox_s(float32_add(frs1, frs2, &env->fp_status));
150 }
151 
152 uint64_t helper_fsub_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
153 {
154     float32 frs1 = check_nanbox_s(rs1);
155     float32 frs2 = check_nanbox_s(rs2);
156     return nanbox_s(float32_sub(frs1, frs2, &env->fp_status));
157 }
158 
159 uint64_t helper_fmul_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
160 {
161     float32 frs1 = check_nanbox_s(rs1);
162     float32 frs2 = check_nanbox_s(rs2);
163     return nanbox_s(float32_mul(frs1, frs2, &env->fp_status));
164 }
165 
166 uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
167 {
168     float32 frs1 = check_nanbox_s(rs1);
169     float32 frs2 = check_nanbox_s(rs2);
170     return nanbox_s(float32_div(frs1, frs2, &env->fp_status));
171 }
172 
173 uint64_t helper_fmin_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
174 {
175     float32 frs1 = check_nanbox_s(rs1);
176     float32 frs2 = check_nanbox_s(rs2);
177     return nanbox_s(float32_minnum(frs1, frs2, &env->fp_status));
178 }
179 
180 uint64_t helper_fmax_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
181 {
182     float32 frs1 = check_nanbox_s(rs1);
183     float32 frs2 = check_nanbox_s(rs2);
184     return nanbox_s(float32_maxnum(frs1, frs2, &env->fp_status));
185 }
186 
187 uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t rs1)
188 {
189     float32 frs1 = check_nanbox_s(rs1);
190     return nanbox_s(float32_sqrt(frs1, &env->fp_status));
191 }
192 
193 target_ulong helper_fle_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
194 {
195     float32 frs1 = check_nanbox_s(rs1);
196     float32 frs2 = check_nanbox_s(rs2);
197     return float32_le(frs1, frs2, &env->fp_status);
198 }
199 
200 target_ulong helper_flt_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
201 {
202     float32 frs1 = check_nanbox_s(rs1);
203     float32 frs2 = check_nanbox_s(rs2);
204     return float32_lt(frs1, frs2, &env->fp_status);
205 }
206 
207 target_ulong helper_feq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
208 {
209     float32 frs1 = check_nanbox_s(rs1);
210     float32 frs2 = check_nanbox_s(rs2);
211     return float32_eq_quiet(frs1, frs2, &env->fp_status);
212 }
213 
214 target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t rs1)
215 {
216     float32 frs1 = check_nanbox_s(rs1);
217     return float32_to_int32(frs1, &env->fp_status);
218 }
219 
220 target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1)
221 {
222     float32 frs1 = check_nanbox_s(rs1);
223     return (int32_t)float32_to_uint32(frs1, &env->fp_status);
224 }
225 
226 uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1)
227 {
228     float32 frs1 = check_nanbox_s(rs1);
229     return float32_to_int64(frs1, &env->fp_status);
230 }
231 
232 uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1)
233 {
234     float32 frs1 = check_nanbox_s(rs1);
235     return float32_to_uint64(frs1, &env->fp_status);
236 }
237 
238 uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1)
239 {
240     return nanbox_s(int32_to_float32((int32_t)rs1, &env->fp_status));
241 }
242 
243 uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1)
244 {
245     return nanbox_s(uint32_to_float32((uint32_t)rs1, &env->fp_status));
246 }
247 
248 uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1)
249 {
250     return nanbox_s(int64_to_float32(rs1, &env->fp_status));
251 }
252 
253 uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1)
254 {
255     return nanbox_s(uint64_to_float32(rs1, &env->fp_status));
256 }
257 
258 target_ulong helper_fclass_s(uint64_t rs1)
259 {
260     float32 frs1 = check_nanbox_s(rs1);
261     return fclass_s(frs1);
262 }
263 
264 uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
265 {
266     return float64_add(frs1, frs2, &env->fp_status);
267 }
268 
269 uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
270 {
271     return float64_sub(frs1, frs2, &env->fp_status);
272 }
273 
274 uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
275 {
276     return float64_mul(frs1, frs2, &env->fp_status);
277 }
278 
279 uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
280 {
281     return float64_div(frs1, frs2, &env->fp_status);
282 }
283 
284 uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
285 {
286     return float64_minnum(frs1, frs2, &env->fp_status);
287 }
288 
289 uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
290 {
291     return float64_maxnum(frs1, frs2, &env->fp_status);
292 }
293 
294 uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1)
295 {
296     return nanbox_s(float64_to_float32(rs1, &env->fp_status));
297 }
298 
299 uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1)
300 {
301     float32 frs1 = check_nanbox_s(rs1);
302     return float32_to_float64(frs1, &env->fp_status);
303 }
304 
305 uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)
306 {
307     return float64_sqrt(frs1, &env->fp_status);
308 }
309 
310 target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
311 {
312     return float64_le(frs1, frs2, &env->fp_status);
313 }
314 
315 target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
316 {
317     return float64_lt(frs1, frs2, &env->fp_status);
318 }
319 
320 target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
321 {
322     return float64_eq_quiet(frs1, frs2, &env->fp_status);
323 }
324 
325 target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1)
326 {
327     return float64_to_int32(frs1, &env->fp_status);
328 }
329 
330 target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1)
331 {
332     return (int32_t)float64_to_uint32(frs1, &env->fp_status);
333 }
334 
335 uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
336 {
337     return float64_to_int64(frs1, &env->fp_status);
338 }
339 
340 uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
341 {
342     return float64_to_uint64(frs1, &env->fp_status);
343 }
344 
345 uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1)
346 {
347     return int32_to_float64((int32_t)rs1, &env->fp_status);
348 }
349 
350 uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1)
351 {
352     return uint32_to_float64((uint32_t)rs1, &env->fp_status);
353 }
354 
355 uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1)
356 {
357     return int64_to_float64(rs1, &env->fp_status);
358 }
359 
360 uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1)
361 {
362     return uint64_to_float64(rs1, &env->fp_status);
363 }
364 
365 target_ulong helper_fclass_d(uint64_t frs1)
366 {
367     return fclass_d(frs1);
368 }
369