2 * Helpers for HPPA 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 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 "exec/cpu_ldst.h"
26 void QEMU_NORETURN
HELPER(excp
)(CPUHPPAState
*env
, int excp
)
28 HPPACPU
*cpu
= hppa_env_get_cpu(env
);
29 CPUState
*cs
= CPU(cpu
);
31 cs
->exception_index
= excp
;
35 static void QEMU_NORETURN
dynexcp(CPUHPPAState
*env
, int excp
, uintptr_t ra
)
37 HPPACPU
*cpu
= hppa_env_get_cpu(env
);
38 CPUState
*cs
= CPU(cpu
);
40 cs
->exception_index
= excp
;
41 cpu_loop_exit_restore(cs
, ra
);
44 void HELPER(tsv
)(CPUHPPAState
*env
, target_ulong cond
)
46 if (unlikely((target_long
)cond
< 0)) {
47 dynexcp(env
, EXCP_SIGFPE
, GETPC());
51 void HELPER(tcond
)(CPUHPPAState
*env
, target_ulong cond
)
54 dynexcp(env
, EXCP_SIGFPE
, GETPC());
58 static void atomic_store_3(CPUHPPAState
*env
, target_ulong addr
, uint32_t val
,
59 uint32_t mask
, uintptr_t ra
)
61 uint32_t old
, new, cmp
;
63 #ifdef CONFIG_USER_ONLY
64 uint32_t *haddr
= g2h(addr
- 1);
67 new = (old
& ~mask
) | (val
& mask
);
68 cmp
= atomic_cmpxchg(haddr
, old
, new);
75 #error "Not implemented."
79 static void do_stby_b(CPUHPPAState
*env
, target_ulong addr
, target_ulong val
,
82 uintptr_t ra
= GETPC();
86 cpu_stb_data_ra(env
, addr
, val
, ra
);
89 cpu_stw_data_ra(env
, addr
, val
, ra
);
92 /* The 3 byte store must appear atomic. */
94 atomic_store_3(env
, addr
, val
, 0x00ffffffu
, ra
);
96 cpu_stb_data_ra(env
, addr
, val
>> 16, ra
);
97 cpu_stw_data_ra(env
, addr
+ 1, val
, ra
);
101 cpu_stl_data_ra(env
, addr
, val
, ra
);
106 void HELPER(stby_b
)(CPUHPPAState
*env
, target_ulong addr
, target_ulong val
)
108 do_stby_b(env
, addr
, val
, false);
111 void HELPER(stby_b_parallel
)(CPUHPPAState
*env
, target_ulong addr
,
114 do_stby_b(env
, addr
, val
, true);
117 static void do_stby_e(CPUHPPAState
*env
, target_ulong addr
, target_ulong val
,
120 uintptr_t ra
= GETPC();
124 /* The 3 byte store must appear atomic. */
126 atomic_store_3(env
, addr
- 3, val
, 0xffffff00u
, ra
);
128 cpu_stw_data_ra(env
, addr
- 3, val
>> 16, ra
);
129 cpu_stb_data_ra(env
, addr
- 1, val
>> 8, ra
);
133 cpu_stw_data_ra(env
, addr
- 2, val
>> 16, ra
);
136 cpu_stb_data_ra(env
, addr
- 1, val
>> 24, ra
);
139 /* Nothing is stored, but protection is checked and the
140 cacheline is marked dirty. */
141 #ifndef CONFIG_USER_ONLY
142 probe_write(env
, addr
, cpu_mmu_index(env
, 0), ra
);
148 void HELPER(stby_e
)(CPUHPPAState
*env
, target_ulong addr
, target_ulong val
)
150 do_stby_e(env
, addr
, val
, false);
153 void HELPER(stby_e_parallel
)(CPUHPPAState
*env
, target_ulong addr
,
156 do_stby_e(env
, addr
, val
, true);
159 target_ulong
HELPER(probe_r
)(target_ulong addr
)
161 return page_check_range(addr
, 1, PAGE_READ
);
164 target_ulong
HELPER(probe_w
)(target_ulong addr
)
166 return page_check_range(addr
, 1, PAGE_WRITE
);
169 void HELPER(loaded_fr0
)(CPUHPPAState
*env
)
171 uint32_t shadow
= env
->fr
[0] >> 32;
174 env
->fr0_shadow
= shadow
;
176 switch (extract32(shadow
, 9, 2)) {
178 rm
= float_round_nearest_even
;
181 rm
= float_round_to_zero
;
187 rm
= float_round_down
;
190 set_float_rounding_mode(rm
, &env
->fp_status
);
192 d
= extract32(shadow
, 5, 1);
193 set_flush_to_zero(d
, &env
->fp_status
);
194 set_flush_inputs_to_zero(d
, &env
->fp_status
);
197 void cpu_hppa_loaded_fr0(CPUHPPAState
*env
)
199 helper_loaded_fr0(env
);
202 #define CONVERT_BIT(X, SRC, DST) \
204 ? (X) / ((SRC) / (DST)) & (DST) \
205 : ((X) & (SRC)) * ((DST) / (SRC)))
207 static void update_fr0_op(CPUHPPAState
*env
, uintptr_t ra
)
209 uint32_t soft_exp
= get_float_exception_flags(&env
->fp_status
);
210 uint32_t hard_exp
= 0;
211 uint32_t shadow
= env
->fr0_shadow
;
213 if (likely(soft_exp
== 0)) {
214 env
->fr
[0] = (uint64_t)shadow
<< 32;
217 set_float_exception_flags(0, &env
->fp_status
);
219 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_inexact
, 1u << 0);
220 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_underflow
, 1u << 1);
221 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_overflow
, 1u << 2);
222 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_divbyzero
, 1u << 3);
223 hard_exp
|= CONVERT_BIT(soft_exp
, float_flag_invalid
, 1u << 4);
224 shadow
|= hard_exp
<< (32 - 5);
225 env
->fr0_shadow
= shadow
;
226 env
->fr
[0] = (uint64_t)shadow
<< 32;
228 if (hard_exp
& shadow
) {
229 dynexcp(env
, EXCP_SIGFPE
, ra
);
233 float32
HELPER(fsqrt_s
)(CPUHPPAState
*env
, float32 arg
)
235 float32 ret
= float32_sqrt(arg
, &env
->fp_status
);
236 update_fr0_op(env
, GETPC());
240 float32
HELPER(frnd_s
)(CPUHPPAState
*env
, float32 arg
)
242 float32 ret
= float32_round_to_int(arg
, &env
->fp_status
);
243 update_fr0_op(env
, GETPC());
247 float32
HELPER(fadd_s
)(CPUHPPAState
*env
, float32 a
, float32 b
)
249 float32 ret
= float32_add(a
, b
, &env
->fp_status
);
250 update_fr0_op(env
, GETPC());
254 float32
HELPER(fsub_s
)(CPUHPPAState
*env
, float32 a
, float32 b
)
256 float32 ret
= float32_sub(a
, b
, &env
->fp_status
);
257 update_fr0_op(env
, GETPC());
261 float32
HELPER(fmpy_s
)(CPUHPPAState
*env
, float32 a
, float32 b
)
263 float32 ret
= float32_mul(a
, b
, &env
->fp_status
);
264 update_fr0_op(env
, GETPC());
268 float32
HELPER(fdiv_s
)(CPUHPPAState
*env
, float32 a
, float32 b
)
270 float32 ret
= float32_div(a
, b
, &env
->fp_status
);
271 update_fr0_op(env
, GETPC());
275 float64
HELPER(fsqrt_d
)(CPUHPPAState
*env
, float64 arg
)
277 float64 ret
= float64_sqrt(arg
, &env
->fp_status
);
278 update_fr0_op(env
, GETPC());
282 float64
HELPER(frnd_d
)(CPUHPPAState
*env
, float64 arg
)
284 float64 ret
= float64_round_to_int(arg
, &env
->fp_status
);
285 update_fr0_op(env
, GETPC());
289 float64
HELPER(fadd_d
)(CPUHPPAState
*env
, float64 a
, float64 b
)
291 float64 ret
= float64_add(a
, b
, &env
->fp_status
);
292 update_fr0_op(env
, GETPC());
296 float64
HELPER(fsub_d
)(CPUHPPAState
*env
, float64 a
, float64 b
)
298 float64 ret
= float64_sub(a
, b
, &env
->fp_status
);
299 update_fr0_op(env
, GETPC());
303 float64
HELPER(fmpy_d
)(CPUHPPAState
*env
, float64 a
, float64 b
)
305 float64 ret
= float64_mul(a
, b
, &env
->fp_status
);
306 update_fr0_op(env
, GETPC());
310 float64
HELPER(fdiv_d
)(CPUHPPAState
*env
, float64 a
, float64 b
)
312 float64 ret
= float64_div(a
, b
, &env
->fp_status
);
313 update_fr0_op(env
, GETPC());
317 float64
HELPER(fcnv_s_d
)(CPUHPPAState
*env
, float32 arg
)
319 float64 ret
= float32_to_float64(arg
, &env
->fp_status
);
320 ret
= float64_maybe_silence_nan(ret
, &env
->fp_status
);
321 update_fr0_op(env
, GETPC());
325 float32
HELPER(fcnv_d_s
)(CPUHPPAState
*env
, float64 arg
)
327 float32 ret
= float64_to_float32(arg
, &env
->fp_status
);
328 ret
= float32_maybe_silence_nan(ret
, &env
->fp_status
);
329 update_fr0_op(env
, GETPC());
333 float32
HELPER(fcnv_w_s
)(CPUHPPAState
*env
, int32_t arg
)
335 float32 ret
= int32_to_float32(arg
, &env
->fp_status
);
336 update_fr0_op(env
, GETPC());
340 float32
HELPER(fcnv_dw_s
)(CPUHPPAState
*env
, int64_t arg
)
342 float32 ret
= int64_to_float32(arg
, &env
->fp_status
);
343 update_fr0_op(env
, GETPC());
347 float64
HELPER(fcnv_w_d
)(CPUHPPAState
*env
, int32_t arg
)
349 float64 ret
= int32_to_float64(arg
, &env
->fp_status
);
350 update_fr0_op(env
, GETPC());
354 float64
HELPER(fcnv_dw_d
)(CPUHPPAState
*env
, int64_t arg
)
356 float64 ret
= int64_to_float64(arg
, &env
->fp_status
);
357 update_fr0_op(env
, GETPC());
361 int32_t HELPER(fcnv_s_w
)(CPUHPPAState
*env
, float32 arg
)
363 int32_t ret
= float32_to_int32(arg
, &env
->fp_status
);
364 update_fr0_op(env
, GETPC());
368 int32_t HELPER(fcnv_d_w
)(CPUHPPAState
*env
, float64 arg
)
370 int32_t ret
= float64_to_int32(arg
, &env
->fp_status
);
371 update_fr0_op(env
, GETPC());
375 int64_t HELPER(fcnv_s_dw
)(CPUHPPAState
*env
, float32 arg
)
377 int64_t ret
= float32_to_int64(arg
, &env
->fp_status
);
378 update_fr0_op(env
, GETPC());
382 int64_t HELPER(fcnv_d_dw
)(CPUHPPAState
*env
, float64 arg
)
384 int64_t ret
= float64_to_int64(arg
, &env
->fp_status
);
385 update_fr0_op(env
, GETPC());
389 int32_t HELPER(fcnv_t_s_w
)(CPUHPPAState
*env
, float32 arg
)
391 int32_t ret
= float32_to_int32_round_to_zero(arg
, &env
->fp_status
);
392 update_fr0_op(env
, GETPC());
396 int32_t HELPER(fcnv_t_d_w
)(CPUHPPAState
*env
, float64 arg
)
398 int32_t ret
= float64_to_int32_round_to_zero(arg
, &env
->fp_status
);
399 update_fr0_op(env
, GETPC());
403 int64_t HELPER(fcnv_t_s_dw
)(CPUHPPAState
*env
, float32 arg
)
405 int64_t ret
= float32_to_int64_round_to_zero(arg
, &env
->fp_status
);
406 update_fr0_op(env
, GETPC());
410 int64_t HELPER(fcnv_t_d_dw
)(CPUHPPAState
*env
, float64 arg
)
412 int64_t ret
= float64_to_int64_round_to_zero(arg
, &env
->fp_status
);
413 update_fr0_op(env
, GETPC());
417 float32
HELPER(fcnv_uw_s
)(CPUHPPAState
*env
, uint32_t arg
)
419 float32 ret
= uint32_to_float32(arg
, &env
->fp_status
);
420 update_fr0_op(env
, GETPC());
424 float32
HELPER(fcnv_udw_s
)(CPUHPPAState
*env
, uint64_t arg
)
426 float32 ret
= uint64_to_float32(arg
, &env
->fp_status
);
427 update_fr0_op(env
, GETPC());
431 float64
HELPER(fcnv_uw_d
)(CPUHPPAState
*env
, uint32_t arg
)
433 float64 ret
= uint32_to_float64(arg
, &env
->fp_status
);
434 update_fr0_op(env
, GETPC());
438 float64
HELPER(fcnv_udw_d
)(CPUHPPAState
*env
, uint64_t arg
)
440 float64 ret
= uint64_to_float64(arg
, &env
->fp_status
);
441 update_fr0_op(env
, GETPC());
445 uint32_t HELPER(fcnv_s_uw
)(CPUHPPAState
*env
, float32 arg
)
447 uint32_t ret
= float32_to_uint32(arg
, &env
->fp_status
);
448 update_fr0_op(env
, GETPC());
452 uint32_t HELPER(fcnv_d_uw
)(CPUHPPAState
*env
, float64 arg
)
454 uint32_t ret
= float64_to_uint32(arg
, &env
->fp_status
);
455 update_fr0_op(env
, GETPC());
459 uint64_t HELPER(fcnv_s_udw
)(CPUHPPAState
*env
, float32 arg
)
461 uint64_t ret
= float32_to_uint64(arg
, &env
->fp_status
);
462 update_fr0_op(env
, GETPC());
466 uint64_t HELPER(fcnv_d_udw
)(CPUHPPAState
*env
, float64 arg
)
468 uint64_t ret
= float64_to_uint64(arg
, &env
->fp_status
);
469 update_fr0_op(env
, GETPC());
473 uint32_t HELPER(fcnv_t_s_uw
)(CPUHPPAState
*env
, float32 arg
)
475 uint32_t ret
= float32_to_uint32_round_to_zero(arg
, &env
->fp_status
);
476 update_fr0_op(env
, GETPC());
480 uint32_t HELPER(fcnv_t_d_uw
)(CPUHPPAState
*env
, float64 arg
)
482 uint32_t ret
= float64_to_uint32_round_to_zero(arg
, &env
->fp_status
);
483 update_fr0_op(env
, GETPC());
487 uint64_t HELPER(fcnv_t_s_udw
)(CPUHPPAState
*env
, float32 arg
)
489 uint64_t ret
= float32_to_uint64_round_to_zero(arg
, &env
->fp_status
);
490 update_fr0_op(env
, GETPC());
494 uint64_t HELPER(fcnv_t_d_udw
)(CPUHPPAState
*env
, float64 arg
)
496 uint64_t ret
= float64_to_uint64_round_to_zero(arg
, &env
->fp_status
);
497 update_fr0_op(env
, GETPC());
501 static void update_fr0_cmp(CPUHPPAState
*env
, uint32_t y
, uint32_t c
, int r
)
503 uint32_t shadow
= env
->fr0_shadow
;
506 case float_relation_greater
:
507 c
= extract32(c
, 4, 1);
509 case float_relation_less
:
510 c
= extract32(c
, 3, 1);
512 case float_relation_equal
:
513 c
= extract32(c
, 2, 1);
515 case float_relation_unordered
:
516 c
= extract32(c
, 1, 1);
519 g_assert_not_reached();
523 /* targeted comparison */
524 /* set fpsr[ca[y - 1]] to current compare */
525 shadow
= deposit32(shadow
, 21 - (y
- 1), 1, c
);
527 /* queued comparison */
528 /* shift cq right by one place */
529 shadow
= deposit32(shadow
, 11, 10, extract32(shadow
, 12, 10));
530 /* move fpsr[c] to fpsr[cq[0]] */
531 shadow
= deposit32(shadow
, 21, 1, extract32(shadow
, 26, 1));
532 /* set fpsr[c] to current compare */
533 shadow
= deposit32(shadow
, 26, 1, c
);
536 env
->fr0_shadow
= shadow
;
537 env
->fr
[0] = (uint64_t)shadow
<< 32;
540 void HELPER(fcmp_s
)(CPUHPPAState
*env
, float32 a
, float32 b
,
541 uint32_t y
, uint32_t c
)
545 r
= float32_compare(a
, b
, &env
->fp_status
);
547 r
= float32_compare_quiet(a
, b
, &env
->fp_status
);
549 update_fr0_op(env
, GETPC());
550 update_fr0_cmp(env
, y
, c
, r
);
553 void HELPER(fcmp_d
)(CPUHPPAState
*env
, float64 a
, float64 b
,
554 uint32_t y
, uint32_t c
)
558 r
= float64_compare(a
, b
, &env
->fp_status
);
560 r
= float64_compare_quiet(a
, b
, &env
->fp_status
);
562 update_fr0_op(env
, GETPC());
563 update_fr0_cmp(env
, y
, c
, r
);
566 float32
HELPER(fmpyfadd_s
)(CPUHPPAState
*env
, float32 a
, float32 b
, float32 c
)
568 float32 ret
= float32_muladd(a
, b
, c
, 0, &env
->fp_status
);
569 update_fr0_op(env
, GETPC());
573 float32
HELPER(fmpynfadd_s
)(CPUHPPAState
*env
, float32 a
, float32 b
, float32 c
)
575 float32 ret
= float32_muladd(a
, b
, c
, float_muladd_negate_product
,
577 update_fr0_op(env
, GETPC());
581 float64
HELPER(fmpyfadd_d
)(CPUHPPAState
*env
, float64 a
, float64 b
, float64 c
)
583 float64 ret
= float64_muladd(a
, b
, c
, 0, &env
->fp_status
);
584 update_fr0_op(env
, GETPC());
588 float64
HELPER(fmpynfadd_d
)(CPUHPPAState
*env
, float64 a
, float64 b
, float64 c
)
590 float64 ret
= float64_muladd(a
, b
, c
, float_muladd_negate_product
,
592 update_fr0_op(env
, GETPC());