2 * Helpers for HPPA FPU instructions.
4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
22 #include "exec/exec-all.h"
23 #include "exec/helper-proto.h"
24 #include "fpu/softfloat.h"
26 void HELPER(loaded_fr0
)(CPUHPPAState
*env
)
28 uint32_t shadow
= env
->fr
[0] >> 32;
31 env
->fr0_shadow
= shadow
;
33 switch (extract32(shadow
, 9, 2)) {
35 rm
= float_round_nearest_even
;
38 rm
= float_round_to_zero
;
44 rm
= float_round_down
;
47 set_float_rounding_mode(rm
, &env
->fp_status
);
49 d
= extract32(shadow
, 5, 1);
50 set_flush_to_zero(d
, &env
->fp_status
);
51 set_flush_inputs_to_zero(d
, &env
->fp_status
);
54 void cpu_hppa_loaded_fr0(CPUHPPAState
*env
)
56 helper_loaded_fr0(env
);
59 #define CONVERT_BIT(X, SRC, DST) \
61 ? (X) / ((SRC) / (DST)) & (DST) \
62 : ((X) & (SRC)) * ((DST) / (SRC)))
64 static void update_fr0_op(CPUHPPAState
*env
, uintptr_t ra
)
66 uint32_t soft_exp
= get_float_exception_flags(&env
->fp_status
);
67 uint32_t hard_exp
= 0;
68 uint32_t shadow
= env
->fr0_shadow
;
70 if (likely(soft_exp
== 0)) {
71 env
->fr
[0] = (uint64_t)shadow
<< 32;
74 set_float_exception_flags(0, &env
->fp_status
);
76 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_inexact
, 1u << 0);
77 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_underflow
, 1u << 1);
78 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_overflow
, 1u << 2);
79 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_divbyzero
, 1u << 3);
80 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_invalid
, 1u << 4);
81 shadow
|= hard_exp
<< (32 - 5);
82 env
->fr0_shadow
= shadow
;
83 env
->fr
[0] = (uint64_t)shadow
<< 32;
85 if (hard_exp
& shadow
) {
86 hppa_dynamic_excp(env
, EXCP_ASSIST
, ra
);
90 float32
HELPER(fsqrt_s
)(CPUHPPAState
*env
, float32 arg
)
92 float32 ret
= float32_sqrt(arg
, &env
->fp_status
);
93 update_fr0_op(env
, GETPC());
97 float32
HELPER(frnd_s
)(CPUHPPAState
*env
, float32 arg
)
99 float32 ret
= float32_round_to_int(arg
, &env
->fp_status
);
100 update_fr0_op(env
, GETPC());
104 float32
HELPER(fadd_s
)(CPUHPPAState
*env
, float32 a
, float32 b
)
106 float32 ret
= float32_add(a
, b
, &env
->fp_status
);
107 update_fr0_op(env
, GETPC());
111 float32
HELPER(fsub_s
)(CPUHPPAState
*env
, float32 a
, float32 b
)
113 float32 ret
= float32_sub(a
, b
, &env
->fp_status
);
114 update_fr0_op(env
, GETPC());
118 float32
HELPER(fmpy_s
)(CPUHPPAState
*env
, float32 a
, float32 b
)
120 float32 ret
= float32_mul(a
, b
, &env
->fp_status
);
121 update_fr0_op(env
, GETPC());
125 float32
HELPER(fdiv_s
)(CPUHPPAState
*env
, float32 a
, float32 b
)
127 float32 ret
= float32_div(a
, b
, &env
->fp_status
);
128 update_fr0_op(env
, GETPC());
132 float64
HELPER(fsqrt_d
)(CPUHPPAState
*env
, float64 arg
)
134 float64 ret
= float64_sqrt(arg
, &env
->fp_status
);
135 update_fr0_op(env
, GETPC());
139 float64
HELPER(frnd_d
)(CPUHPPAState
*env
, float64 arg
)
141 float64 ret
= float64_round_to_int(arg
, &env
->fp_status
);
142 update_fr0_op(env
, GETPC());
146 float64
HELPER(fadd_d
)(CPUHPPAState
*env
, float64 a
, float64 b
)
148 float64 ret
= float64_add(a
, b
, &env
->fp_status
);
149 update_fr0_op(env
, GETPC());
153 float64
HELPER(fsub_d
)(CPUHPPAState
*env
, float64 a
, float64 b
)
155 float64 ret
= float64_sub(a
, b
, &env
->fp_status
);
156 update_fr0_op(env
, GETPC());
160 float64
HELPER(fmpy_d
)(CPUHPPAState
*env
, float64 a
, float64 b
)
162 float64 ret
= float64_mul(a
, b
, &env
->fp_status
);
163 update_fr0_op(env
, GETPC());
167 float64
HELPER(fdiv_d
)(CPUHPPAState
*env
, float64 a
, float64 b
)
169 float64 ret
= float64_div(a
, b
, &env
->fp_status
);
170 update_fr0_op(env
, GETPC());
174 float64
HELPER(fcnv_s_d
)(CPUHPPAState
*env
, float32 arg
)
176 float64 ret
= float32_to_float64(arg
, &env
->fp_status
);
177 update_fr0_op(env
, GETPC());
181 float32
HELPER(fcnv_d_s
)(CPUHPPAState
*env
, float64 arg
)
183 float32 ret
= float64_to_float32(arg
, &env
->fp_status
);
184 update_fr0_op(env
, GETPC());
188 float32
HELPER(fcnv_w_s
)(CPUHPPAState
*env
, int32_t arg
)
190 float32 ret
= int32_to_float32(arg
, &env
->fp_status
);
191 update_fr0_op(env
, GETPC());
195 float32
HELPER(fcnv_dw_s
)(CPUHPPAState
*env
, int64_t arg
)
197 float32 ret
= int64_to_float32(arg
, &env
->fp_status
);
198 update_fr0_op(env
, GETPC());
202 float64
HELPER(fcnv_w_d
)(CPUHPPAState
*env
, int32_t arg
)
204 float64 ret
= int32_to_float64(arg
, &env
->fp_status
);
205 update_fr0_op(env
, GETPC());
209 float64
HELPER(fcnv_dw_d
)(CPUHPPAState
*env
, int64_t arg
)
211 float64 ret
= int64_to_float64(arg
, &env
->fp_status
);
212 update_fr0_op(env
, GETPC());
216 int32_t HELPER(fcnv_s_w
)(CPUHPPAState
*env
, float32 arg
)
218 int32_t ret
= float32_to_int32(arg
, &env
->fp_status
);
219 update_fr0_op(env
, GETPC());
223 int32_t HELPER(fcnv_d_w
)(CPUHPPAState
*env
, float64 arg
)
225 int32_t ret
= float64_to_int32(arg
, &env
->fp_status
);
226 update_fr0_op(env
, GETPC());
230 int64_t HELPER(fcnv_s_dw
)(CPUHPPAState
*env
, float32 arg
)
232 int64_t ret
= float32_to_int64(arg
, &env
->fp_status
);
233 update_fr0_op(env
, GETPC());
237 int64_t HELPER(fcnv_d_dw
)(CPUHPPAState
*env
, float64 arg
)
239 int64_t ret
= float64_to_int64(arg
, &env
->fp_status
);
240 update_fr0_op(env
, GETPC());
244 int32_t HELPER(fcnv_t_s_w
)(CPUHPPAState
*env
, float32 arg
)
246 int32_t ret
= float32_to_int32_round_to_zero(arg
, &env
->fp_status
);
247 update_fr0_op(env
, GETPC());
251 int32_t HELPER(fcnv_t_d_w
)(CPUHPPAState
*env
, float64 arg
)
253 int32_t ret
= float64_to_int32_round_to_zero(arg
, &env
->fp_status
);
254 update_fr0_op(env
, GETPC());
258 int64_t HELPER(fcnv_t_s_dw
)(CPUHPPAState
*env
, float32 arg
)
260 int64_t ret
= float32_to_int64_round_to_zero(arg
, &env
->fp_status
);
261 update_fr0_op(env
, GETPC());
265 int64_t HELPER(fcnv_t_d_dw
)(CPUHPPAState
*env
, float64 arg
)
267 int64_t ret
= float64_to_int64_round_to_zero(arg
, &env
->fp_status
);
268 update_fr0_op(env
, GETPC());
272 float32
HELPER(fcnv_uw_s
)(CPUHPPAState
*env
, uint32_t arg
)
274 float32 ret
= uint32_to_float32(arg
, &env
->fp_status
);
275 update_fr0_op(env
, GETPC());
279 float32
HELPER(fcnv_udw_s
)(CPUHPPAState
*env
, uint64_t arg
)
281 float32 ret
= uint64_to_float32(arg
, &env
->fp_status
);
282 update_fr0_op(env
, GETPC());
286 float64
HELPER(fcnv_uw_d
)(CPUHPPAState
*env
, uint32_t arg
)
288 float64 ret
= uint32_to_float64(arg
, &env
->fp_status
);
289 update_fr0_op(env
, GETPC());
293 float64
HELPER(fcnv_udw_d
)(CPUHPPAState
*env
, uint64_t arg
)
295 float64 ret
= uint64_to_float64(arg
, &env
->fp_status
);
296 update_fr0_op(env
, GETPC());
300 uint32_t HELPER(fcnv_s_uw
)(CPUHPPAState
*env
, float32 arg
)
302 uint32_t ret
= float32_to_uint32(arg
, &env
->fp_status
);
303 update_fr0_op(env
, GETPC());
307 uint32_t HELPER(fcnv_d_uw
)(CPUHPPAState
*env
, float64 arg
)
309 uint32_t ret
= float64_to_uint32(arg
, &env
->fp_status
);
310 update_fr0_op(env
, GETPC());
314 uint64_t HELPER(fcnv_s_udw
)(CPUHPPAState
*env
, float32 arg
)
316 uint64_t ret
= float32_to_uint64(arg
, &env
->fp_status
);
317 update_fr0_op(env
, GETPC());
321 uint64_t HELPER(fcnv_d_udw
)(CPUHPPAState
*env
, float64 arg
)
323 uint64_t ret
= float64_to_uint64(arg
, &env
->fp_status
);
324 update_fr0_op(env
, GETPC());
328 uint32_t HELPER(fcnv_t_s_uw
)(CPUHPPAState
*env
, float32 arg
)
330 uint32_t ret
= float32_to_uint32_round_to_zero(arg
, &env
->fp_status
);
331 update_fr0_op(env
, GETPC());
335 uint32_t HELPER(fcnv_t_d_uw
)(CPUHPPAState
*env
, float64 arg
)
337 uint32_t ret
= float64_to_uint32_round_to_zero(arg
, &env
->fp_status
);
338 update_fr0_op(env
, GETPC());
342 uint64_t HELPER(fcnv_t_s_udw
)(CPUHPPAState
*env
, float32 arg
)
344 uint64_t ret
= float32_to_uint64_round_to_zero(arg
, &env
->fp_status
);
345 update_fr0_op(env
, GETPC());
349 uint64_t HELPER(fcnv_t_d_udw
)(CPUHPPAState
*env
, float64 arg
)
351 uint64_t ret
= float64_to_uint64_round_to_zero(arg
, &env
->fp_status
);
352 update_fr0_op(env
, GETPC());
356 static void update_fr0_cmp(CPUHPPAState
*env
, uint32_t y
,
357 uint32_t c
, FloatRelation r
)
359 uint32_t shadow
= env
->fr0_shadow
;
362 case float_relation_greater
:
363 c
= extract32(c
, 4, 1);
365 case float_relation_less
:
366 c
= extract32(c
, 3, 1);
368 case float_relation_equal
:
369 c
= extract32(c
, 2, 1);
371 case float_relation_unordered
:
372 c
= extract32(c
, 1, 1);
375 g_assert_not_reached();
379 /* targeted comparison */
380 /* set fpsr[ca[y - 1]] to current compare */
381 shadow
= deposit32(shadow
, 21 - (y
- 1), 1, c
);
383 /* queued comparison */
384 /* shift cq right by one place */
385 shadow
= deposit32(shadow
, 11, 10, extract32(shadow
, 12, 10));
386 /* move fpsr[c] to fpsr[cq[0]] */
387 shadow
= deposit32(shadow
, 21, 1, extract32(shadow
, 26, 1));
388 /* set fpsr[c] to current compare */
389 shadow
= deposit32(shadow
, 26, 1, c
);
392 env
->fr0_shadow
= shadow
;
393 env
->fr
[0] = (uint64_t)shadow
<< 32;
396 void HELPER(fcmp_s
)(CPUHPPAState
*env
, float32 a
, float32 b
,
397 uint32_t y
, uint32_t c
)
401 r
= float32_compare(a
, b
, &env
->fp_status
);
403 r
= float32_compare_quiet(a
, b
, &env
->fp_status
);
405 update_fr0_op(env
, GETPC());
406 update_fr0_cmp(env
, y
, c
, r
);
409 void HELPER(fcmp_d
)(CPUHPPAState
*env
, float64 a
, float64 b
,
410 uint32_t y
, uint32_t c
)
414 r
= float64_compare(a
, b
, &env
->fp_status
);
416 r
= float64_compare_quiet(a
, b
, &env
->fp_status
);
418 update_fr0_op(env
, GETPC());
419 update_fr0_cmp(env
, y
, c
, r
);
422 float32
HELPER(fmpyfadd_s
)(CPUHPPAState
*env
, float32 a
, float32 b
, float32 c
)
424 float32 ret
= float32_muladd(a
, b
, c
, 0, &env
->fp_status
);
425 update_fr0_op(env
, GETPC());
429 float32
HELPER(fmpynfadd_s
)(CPUHPPAState
*env
, float32 a
, float32 b
, float32 c
)
431 float32 ret
= float32_muladd(a
, b
, c
, float_muladd_negate_product
,
433 update_fr0_op(env
, GETPC());
437 float64
HELPER(fmpyfadd_d
)(CPUHPPAState
*env
, float64 a
, float64 b
, float64 c
)
439 float64 ret
= float64_muladd(a
, b
, c
, 0, &env
->fp_status
);
440 update_fr0_op(env
, GETPC());
444 float64
HELPER(fmpynfadd_d
)(CPUHPPAState
*env
, float64 a
, float64 b
, float64 c
)
446 float64 ret
= float64_muladd(a
, b
, c
, float_muladd_negate_product
,
448 update_fr0_op(env
, GETPC());