xref: /openbmc/qemu/target/riscv/fpu_helper.c (revision e1a29bbd)
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 == RISCV_FRM_DYN) {
59         rm = env->frm;
60     }
61     switch (rm) {
62     case RISCV_FRM_RNE:
63         softrm = float_round_nearest_even;
64         break;
65     case RISCV_FRM_RTZ:
66         softrm = float_round_to_zero;
67         break;
68     case RISCV_FRM_RDN:
69         softrm = float_round_down;
70         break;
71     case RISCV_FRM_RUP:
72         softrm = float_round_up;
73         break;
74     case RISCV_FRM_RMM:
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 void helper_set_rod_rounding_mode(CPURISCVState *env)
85 {
86     set_float_rounding_mode(float_round_to_odd, &env->fp_status);
87 }
88 
89 static uint64_t do_fmadd_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2,
90                            uint64_t rs3, int flags)
91 {
92     float16 frs1 = check_nanbox_h(rs1);
93     float16 frs2 = check_nanbox_h(rs2);
94     float16 frs3 = check_nanbox_h(rs3);
95     return nanbox_h(float16_muladd(frs1, frs2, frs3, flags, &env->fp_status));
96 }
97 
98 static uint64_t do_fmadd_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2,
99                            uint64_t rs3, int flags)
100 {
101     float32 frs1 = check_nanbox_s(env, rs1);
102     float32 frs2 = check_nanbox_s(env, rs2);
103     float32 frs3 = check_nanbox_s(env, rs3);
104     return nanbox_s(env, float32_muladd(frs1, frs2, frs3, flags,
105                                         &env->fp_status));
106 }
107 
108 uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
109                         uint64_t frs3)
110 {
111     return do_fmadd_s(env, frs1, frs2, frs3, 0);
112 }
113 
114 uint64_t helper_fmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
115                         uint64_t frs3)
116 {
117     return float64_muladd(frs1, frs2, frs3, 0, &env->fp_status);
118 }
119 
120 uint64_t helper_fmadd_h(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
121                         uint64_t frs3)
122 {
123     return do_fmadd_h(env, frs1, frs2, frs3, 0);
124 }
125 
126 uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
127                         uint64_t frs3)
128 {
129     return do_fmadd_s(env, frs1, frs2, frs3, float_muladd_negate_c);
130 }
131 
132 uint64_t helper_fmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
133                         uint64_t frs3)
134 {
135     return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c,
136                           &env->fp_status);
137 }
138 
139 uint64_t helper_fmsub_h(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
140                         uint64_t frs3)
141 {
142     return do_fmadd_h(env, frs1, frs2, frs3, float_muladd_negate_c);
143 }
144 
145 uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
146                          uint64_t frs3)
147 {
148     return do_fmadd_s(env, frs1, frs2, frs3, float_muladd_negate_product);
149 }
150 
151 uint64_t helper_fnmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
152                          uint64_t frs3)
153 {
154     return float64_muladd(frs1, frs2, frs3, float_muladd_negate_product,
155                           &env->fp_status);
156 }
157 
158 uint64_t helper_fnmsub_h(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
159                          uint64_t frs3)
160 {
161     return do_fmadd_h(env, frs1, frs2, frs3, float_muladd_negate_product);
162 }
163 
164 uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
165                          uint64_t frs3)
166 {
167     return do_fmadd_s(env, frs1, frs2, frs3,
168                       float_muladd_negate_c | float_muladd_negate_product);
169 }
170 
171 uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
172                          uint64_t frs3)
173 {
174     return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c |
175                           float_muladd_negate_product, &env->fp_status);
176 }
177 
178 uint64_t helper_fnmadd_h(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
179                          uint64_t frs3)
180 {
181     return do_fmadd_h(env, frs1, frs2, frs3,
182                       float_muladd_negate_c | float_muladd_negate_product);
183 }
184 
185 uint64_t helper_fadd_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
186 {
187     float32 frs1 = check_nanbox_s(env, rs1);
188     float32 frs2 = check_nanbox_s(env, rs2);
189     return nanbox_s(env, float32_add(frs1, frs2, &env->fp_status));
190 }
191 
192 uint64_t helper_fsub_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
193 {
194     float32 frs1 = check_nanbox_s(env, rs1);
195     float32 frs2 = check_nanbox_s(env, rs2);
196     return nanbox_s(env, float32_sub(frs1, frs2, &env->fp_status));
197 }
198 
199 uint64_t helper_fmul_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
200 {
201     float32 frs1 = check_nanbox_s(env, rs1);
202     float32 frs2 = check_nanbox_s(env, rs2);
203     return nanbox_s(env, float32_mul(frs1, frs2, &env->fp_status));
204 }
205 
206 uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
207 {
208     float32 frs1 = check_nanbox_s(env, rs1);
209     float32 frs2 = check_nanbox_s(env, rs2);
210     return nanbox_s(env, float32_div(frs1, frs2, &env->fp_status));
211 }
212 
213 uint64_t helper_fmin_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
214 {
215     float32 frs1 = check_nanbox_s(env, rs1);
216     float32 frs2 = check_nanbox_s(env, rs2);
217     return nanbox_s(env, env->priv_ver < PRIV_VERSION_1_11_0 ?
218                     float32_minnum(frs1, frs2, &env->fp_status) :
219                     float32_minimum_number(frs1, frs2, &env->fp_status));
220 }
221 
222 uint64_t helper_fmax_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
223 {
224     float32 frs1 = check_nanbox_s(env, rs1);
225     float32 frs2 = check_nanbox_s(env, rs2);
226     return nanbox_s(env, env->priv_ver < PRIV_VERSION_1_11_0 ?
227                     float32_maxnum(frs1, frs2, &env->fp_status) :
228                     float32_maximum_number(frs1, frs2, &env->fp_status));
229 }
230 
231 uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t rs1)
232 {
233     float32 frs1 = check_nanbox_s(env, rs1);
234     return nanbox_s(env, float32_sqrt(frs1, &env->fp_status));
235 }
236 
237 target_ulong helper_fle_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
238 {
239     float32 frs1 = check_nanbox_s(env, rs1);
240     float32 frs2 = check_nanbox_s(env, rs2);
241     return float32_le(frs1, frs2, &env->fp_status);
242 }
243 
244 target_ulong helper_flt_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
245 {
246     float32 frs1 = check_nanbox_s(env, rs1);
247     float32 frs2 = check_nanbox_s(env, rs2);
248     return float32_lt(frs1, frs2, &env->fp_status);
249 }
250 
251 target_ulong helper_feq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
252 {
253     float32 frs1 = check_nanbox_s(env, rs1);
254     float32 frs2 = check_nanbox_s(env, rs2);
255     return float32_eq_quiet(frs1, frs2, &env->fp_status);
256 }
257 
258 target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t rs1)
259 {
260     float32 frs1 = check_nanbox_s(env, rs1);
261     return float32_to_int32(frs1, &env->fp_status);
262 }
263 
264 target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1)
265 {
266     float32 frs1 = check_nanbox_s(env, rs1);
267     return (int32_t)float32_to_uint32(frs1, &env->fp_status);
268 }
269 
270 target_ulong helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1)
271 {
272     float32 frs1 = check_nanbox_s(env, rs1);
273     return float32_to_int64(frs1, &env->fp_status);
274 }
275 
276 target_ulong helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1)
277 {
278     float32 frs1 = check_nanbox_s(env, rs1);
279     return float32_to_uint64(frs1, &env->fp_status);
280 }
281 
282 uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1)
283 {
284     return nanbox_s(env, int32_to_float32((int32_t)rs1, &env->fp_status));
285 }
286 
287 uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1)
288 {
289     return nanbox_s(env, uint32_to_float32((uint32_t)rs1, &env->fp_status));
290 }
291 
292 uint64_t helper_fcvt_s_l(CPURISCVState *env, target_ulong rs1)
293 {
294     return nanbox_s(env, int64_to_float32(rs1, &env->fp_status));
295 }
296 
297 uint64_t helper_fcvt_s_lu(CPURISCVState *env, target_ulong rs1)
298 {
299     return nanbox_s(env, uint64_to_float32(rs1, &env->fp_status));
300 }
301 
302 target_ulong helper_fclass_s(CPURISCVState *env, uint64_t rs1)
303 {
304     float32 frs1 = check_nanbox_s(env, rs1);
305     return fclass_s(frs1);
306 }
307 
308 uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
309 {
310     return float64_add(frs1, frs2, &env->fp_status);
311 }
312 
313 uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
314 {
315     return float64_sub(frs1, frs2, &env->fp_status);
316 }
317 
318 uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
319 {
320     return float64_mul(frs1, frs2, &env->fp_status);
321 }
322 
323 uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
324 {
325     return float64_div(frs1, frs2, &env->fp_status);
326 }
327 
328 uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
329 {
330     return env->priv_ver < PRIV_VERSION_1_11_0 ?
331             float64_minnum(frs1, frs2, &env->fp_status) :
332             float64_minimum_number(frs1, frs2, &env->fp_status);
333 }
334 
335 uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
336 {
337     return env->priv_ver < PRIV_VERSION_1_11_0 ?
338             float64_maxnum(frs1, frs2, &env->fp_status) :
339             float64_maximum_number(frs1, frs2, &env->fp_status);
340 }
341 
342 uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1)
343 {
344     return nanbox_s(env, float64_to_float32(rs1, &env->fp_status));
345 }
346 
347 uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1)
348 {
349     float32 frs1 = check_nanbox_s(env, rs1);
350     return float32_to_float64(frs1, &env->fp_status);
351 }
352 
353 uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)
354 {
355     return float64_sqrt(frs1, &env->fp_status);
356 }
357 
358 target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
359 {
360     return float64_le(frs1, frs2, &env->fp_status);
361 }
362 
363 target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
364 {
365     return float64_lt(frs1, frs2, &env->fp_status);
366 }
367 
368 target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
369 {
370     return float64_eq_quiet(frs1, frs2, &env->fp_status);
371 }
372 
373 target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1)
374 {
375     return float64_to_int32(frs1, &env->fp_status);
376 }
377 
378 target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1)
379 {
380     return (int32_t)float64_to_uint32(frs1, &env->fp_status);
381 }
382 
383 target_ulong helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
384 {
385     return float64_to_int64(frs1, &env->fp_status);
386 }
387 
388 target_ulong helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
389 {
390     return float64_to_uint64(frs1, &env->fp_status);
391 }
392 
393 uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1)
394 {
395     return int32_to_float64((int32_t)rs1, &env->fp_status);
396 }
397 
398 uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1)
399 {
400     return uint32_to_float64((uint32_t)rs1, &env->fp_status);
401 }
402 
403 uint64_t helper_fcvt_d_l(CPURISCVState *env, target_ulong rs1)
404 {
405     return int64_to_float64(rs1, &env->fp_status);
406 }
407 
408 uint64_t helper_fcvt_d_lu(CPURISCVState *env, target_ulong rs1)
409 {
410     return uint64_to_float64(rs1, &env->fp_status);
411 }
412 
413 target_ulong helper_fclass_d(uint64_t frs1)
414 {
415     return fclass_d(frs1);
416 }
417 
418 uint64_t helper_fadd_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
419 {
420     float16 frs1 = check_nanbox_h(rs1);
421     float16 frs2 = check_nanbox_h(rs2);
422     return nanbox_h(float16_add(frs1, frs2, &env->fp_status));
423 }
424 
425 uint64_t helper_fsub_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
426 {
427     float16 frs1 = check_nanbox_h(rs1);
428     float16 frs2 = check_nanbox_h(rs2);
429     return nanbox_h(float16_sub(frs1, frs2, &env->fp_status));
430 }
431 
432 uint64_t helper_fmul_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
433 {
434     float16 frs1 = check_nanbox_h(rs1);
435     float16 frs2 = check_nanbox_h(rs2);
436     return nanbox_h(float16_mul(frs1, frs2, &env->fp_status));
437 }
438 
439 uint64_t helper_fdiv_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
440 {
441     float16 frs1 = check_nanbox_h(rs1);
442     float16 frs2 = check_nanbox_h(rs2);
443     return nanbox_h(float16_div(frs1, frs2, &env->fp_status));
444 }
445 
446 uint64_t helper_fmin_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
447 {
448     float16 frs1 = check_nanbox_h(rs1);
449     float16 frs2 = check_nanbox_h(rs2);
450     return nanbox_h(env->priv_ver < PRIV_VERSION_1_11_0 ?
451                     float16_minnum(frs1, frs2, &env->fp_status) :
452                     float16_minimum_number(frs1, frs2, &env->fp_status));
453 }
454 
455 uint64_t helper_fmax_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
456 {
457     float16 frs1 = check_nanbox_h(rs1);
458     float16 frs2 = check_nanbox_h(rs2);
459     return nanbox_h(env->priv_ver < PRIV_VERSION_1_11_0 ?
460                     float16_maxnum(frs1, frs2, &env->fp_status) :
461                     float16_maximum_number(frs1, frs2, &env->fp_status));
462 }
463 
464 uint64_t helper_fsqrt_h(CPURISCVState *env, uint64_t rs1)
465 {
466     float16 frs1 = check_nanbox_h(rs1);
467     return nanbox_h(float16_sqrt(frs1, &env->fp_status));
468 }
469 
470 target_ulong helper_fle_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
471 {
472     float16 frs1 = check_nanbox_h(rs1);
473     float16 frs2 = check_nanbox_h(rs2);
474     return float16_le(frs1, frs2, &env->fp_status);
475 }
476 
477 target_ulong helper_flt_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
478 {
479     float16 frs1 = check_nanbox_h(rs1);
480     float16 frs2 = check_nanbox_h(rs2);
481     return float16_lt(frs1, frs2, &env->fp_status);
482 }
483 
484 target_ulong helper_feq_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
485 {
486     float16 frs1 = check_nanbox_h(rs1);
487     float16 frs2 = check_nanbox_h(rs2);
488     return float16_eq_quiet(frs1, frs2, &env->fp_status);
489 }
490 
491 target_ulong helper_fclass_h(uint64_t rs1)
492 {
493     float16 frs1 = check_nanbox_h(rs1);
494     return fclass_h(frs1);
495 }
496 
497 target_ulong helper_fcvt_w_h(CPURISCVState *env, uint64_t rs1)
498 {
499     float16 frs1 = check_nanbox_h(rs1);
500     return float16_to_int32(frs1, &env->fp_status);
501 }
502 
503 target_ulong helper_fcvt_wu_h(CPURISCVState *env, uint64_t rs1)
504 {
505     float16 frs1 = check_nanbox_h(rs1);
506     return (int32_t)float16_to_uint32(frs1, &env->fp_status);
507 }
508 
509 target_ulong helper_fcvt_l_h(CPURISCVState *env, uint64_t rs1)
510 {
511     float16 frs1 = check_nanbox_h(rs1);
512     return float16_to_int64(frs1, &env->fp_status);
513 }
514 
515 target_ulong helper_fcvt_lu_h(CPURISCVState *env, uint64_t rs1)
516 {
517     float16 frs1 = check_nanbox_h(rs1);
518     return float16_to_uint64(frs1, &env->fp_status);
519 }
520 
521 uint64_t helper_fcvt_h_w(CPURISCVState *env, target_ulong rs1)
522 {
523     return nanbox_h(int32_to_float16((int32_t)rs1, &env->fp_status));
524 }
525 
526 uint64_t helper_fcvt_h_wu(CPURISCVState *env, target_ulong rs1)
527 {
528     return nanbox_h(uint32_to_float16((uint32_t)rs1, &env->fp_status));
529 }
530 
531 uint64_t helper_fcvt_h_l(CPURISCVState *env, target_ulong rs1)
532 {
533     return nanbox_h(int64_to_float16(rs1, &env->fp_status));
534 }
535 
536 uint64_t helper_fcvt_h_lu(CPURISCVState *env, target_ulong rs1)
537 {
538     return nanbox_h(uint64_to_float16(rs1, &env->fp_status));
539 }
540 
541 uint64_t helper_fcvt_h_s(CPURISCVState *env, uint64_t rs1)
542 {
543     float32 frs1 = check_nanbox_s(env, rs1);
544     return nanbox_h(float32_to_float16(frs1, true, &env->fp_status));
545 }
546 
547 uint64_t helper_fcvt_s_h(CPURISCVState *env, uint64_t rs1)
548 {
549     float16 frs1 = check_nanbox_h(rs1);
550     return nanbox_s(env, float16_to_float32(frs1, true, &env->fp_status));
551 }
552 
553 uint64_t helper_fcvt_h_d(CPURISCVState *env, uint64_t rs1)
554 {
555     return nanbox_h(float64_to_float16(rs1, true, &env->fp_status));
556 }
557 
558 uint64_t helper_fcvt_d_h(CPURISCVState *env, uint64_t rs1)
559 {
560     float16 frs1 = check_nanbox_h(rs1);
561     return float16_to_float64(frs1, true, &env->fp_status);
562 }
563