xref: /openbmc/qemu/target/hppa/fpu_helper.c (revision f15f7273ea55472d5904c53566c82369d81214c1)
1  /*
2   * Helpers for HPPA FPU instructions.
3   *
4   * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
5   *
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.
10   *
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.
15   *
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/>.
18   */
19  
20  #include "qemu/osdep.h"
21  #include "cpu.h"
22  #include "exec/exec-all.h"
23  #include "exec/helper-proto.h"
24  #include "fpu/softfloat.h"
25  
HELPER(loaded_fr0)26  void HELPER(loaded_fr0)(CPUHPPAState *env)
27  {
28      uint32_t shadow = env->fr[0] >> 32;
29      int rm, d;
30  
31      env->fr0_shadow = shadow;
32  
33      switch (FIELD_EX32(shadow, FPSR, RM)) {
34      default:
35          rm = float_round_nearest_even;
36          break;
37      case 1:
38          rm = float_round_to_zero;
39          break;
40      case 2:
41          rm = float_round_up;
42          break;
43      case 3:
44          rm = float_round_down;
45          break;
46      }
47      set_float_rounding_mode(rm, &env->fp_status);
48  
49      d = FIELD_EX32(shadow, FPSR, D);
50      set_flush_to_zero(d, &env->fp_status);
51      set_flush_inputs_to_zero(d, &env->fp_status);
52  
53      /*
54       * TODO: we only need to do this at CPU reset, but currently
55       * HPPA does note implement a CPU reset method at all...
56       */
57      set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
58  }
59  
cpu_hppa_loaded_fr0(CPUHPPAState * env)60  void cpu_hppa_loaded_fr0(CPUHPPAState *env)
61  {
62      helper_loaded_fr0(env);
63  }
64  
65  #define CONVERT_BIT(X, SRC, DST)        \
66      ((unsigned)(SRC) > (unsigned)(DST)  \
67       ? (X) / ((SRC) / (DST)) & (DST)    \
68       : ((X) & (SRC)) * ((DST) / (SRC)))
69  
update_fr0_op(CPUHPPAState * env,uintptr_t ra)70  static void update_fr0_op(CPUHPPAState *env, uintptr_t ra)
71  {
72      uint32_t soft_exp = get_float_exception_flags(&env->fp_status);
73      uint32_t hard_exp = 0;
74      uint32_t shadow = env->fr0_shadow;
75  
76      if (likely(soft_exp == 0)) {
77          env->fr[0] = (uint64_t)shadow << 32;
78          return;
79      }
80      set_float_exception_flags(0, &env->fp_status);
81  
82      hard_exp |= CONVERT_BIT(soft_exp, float_flag_inexact,   R_FPSR_ENA_I_MASK);
83      hard_exp |= CONVERT_BIT(soft_exp, float_flag_underflow, R_FPSR_ENA_U_MASK);
84      hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow,  R_FPSR_ENA_O_MASK);
85      hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, R_FPSR_ENA_Z_MASK);
86      hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid,   R_FPSR_ENA_V_MASK);
87      shadow |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT);
88      env->fr0_shadow = shadow;
89      env->fr[0] = (uint64_t)shadow << 32;
90  
91      if (hard_exp & shadow) {
92          hppa_dynamic_excp(env, EXCP_ASSIST, ra);
93      }
94  }
95  
HELPER(fsqrt_s)96  float32 HELPER(fsqrt_s)(CPUHPPAState *env, float32 arg)
97  {
98      float32 ret = float32_sqrt(arg, &env->fp_status);
99      update_fr0_op(env, GETPC());
100      return ret;
101  }
102  
HELPER(frnd_s)103  float32 HELPER(frnd_s)(CPUHPPAState *env, float32 arg)
104  {
105      float32 ret = float32_round_to_int(arg, &env->fp_status);
106      update_fr0_op(env, GETPC());
107      return ret;
108  }
109  
HELPER(fadd_s)110  float32 HELPER(fadd_s)(CPUHPPAState *env, float32 a, float32 b)
111  {
112      float32 ret = float32_add(a, b, &env->fp_status);
113      update_fr0_op(env, GETPC());
114      return ret;
115  }
116  
HELPER(fsub_s)117  float32 HELPER(fsub_s)(CPUHPPAState *env, float32 a, float32 b)
118  {
119      float32 ret = float32_sub(a, b, &env->fp_status);
120      update_fr0_op(env, GETPC());
121      return ret;
122  }
123  
HELPER(fmpy_s)124  float32 HELPER(fmpy_s)(CPUHPPAState *env, float32 a, float32 b)
125  {
126      float32 ret = float32_mul(a, b, &env->fp_status);
127      update_fr0_op(env, GETPC());
128      return ret;
129  }
130  
HELPER(fdiv_s)131  float32 HELPER(fdiv_s)(CPUHPPAState *env, float32 a, float32 b)
132  {
133      float32 ret = float32_div(a, b, &env->fp_status);
134      update_fr0_op(env, GETPC());
135      return ret;
136  }
137  
HELPER(fsqrt_d)138  float64 HELPER(fsqrt_d)(CPUHPPAState *env, float64 arg)
139  {
140      float64 ret = float64_sqrt(arg, &env->fp_status);
141      update_fr0_op(env, GETPC());
142      return ret;
143  }
144  
HELPER(frnd_d)145  float64 HELPER(frnd_d)(CPUHPPAState *env, float64 arg)
146  {
147      float64 ret = float64_round_to_int(arg, &env->fp_status);
148      update_fr0_op(env, GETPC());
149      return ret;
150  }
151  
HELPER(fadd_d)152  float64 HELPER(fadd_d)(CPUHPPAState *env, float64 a, float64 b)
153  {
154      float64 ret = float64_add(a, b, &env->fp_status);
155      update_fr0_op(env, GETPC());
156      return ret;
157  }
158  
HELPER(fsub_d)159  float64 HELPER(fsub_d)(CPUHPPAState *env, float64 a, float64 b)
160  {
161      float64 ret = float64_sub(a, b, &env->fp_status);
162      update_fr0_op(env, GETPC());
163      return ret;
164  }
165  
HELPER(fmpy_d)166  float64 HELPER(fmpy_d)(CPUHPPAState *env, float64 a, float64 b)
167  {
168      float64 ret = float64_mul(a, b, &env->fp_status);
169      update_fr0_op(env, GETPC());
170      return ret;
171  }
172  
HELPER(fdiv_d)173  float64 HELPER(fdiv_d)(CPUHPPAState *env, float64 a, float64 b)
174  {
175      float64 ret = float64_div(a, b, &env->fp_status);
176      update_fr0_op(env, GETPC());
177      return ret;
178  }
179  
HELPER(fcnv_s_d)180  float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg)
181  {
182      float64 ret = float32_to_float64(arg, &env->fp_status);
183      update_fr0_op(env, GETPC());
184      return ret;
185  }
186  
HELPER(fcnv_d_s)187  float32 HELPER(fcnv_d_s)(CPUHPPAState *env, float64 arg)
188  {
189      float32 ret = float64_to_float32(arg, &env->fp_status);
190      update_fr0_op(env, GETPC());
191      return ret;
192  }
193  
HELPER(fcnv_w_s)194  float32 HELPER(fcnv_w_s)(CPUHPPAState *env, int32_t arg)
195  {
196      float32 ret = int32_to_float32(arg, &env->fp_status);
197      update_fr0_op(env, GETPC());
198      return ret;
199  }
200  
HELPER(fcnv_dw_s)201  float32 HELPER(fcnv_dw_s)(CPUHPPAState *env, int64_t arg)
202  {
203      float32 ret = int64_to_float32(arg, &env->fp_status);
204      update_fr0_op(env, GETPC());
205      return ret;
206  }
207  
HELPER(fcnv_w_d)208  float64 HELPER(fcnv_w_d)(CPUHPPAState *env, int32_t arg)
209  {
210      float64 ret = int32_to_float64(arg, &env->fp_status);
211      update_fr0_op(env, GETPC());
212      return ret;
213  }
214  
HELPER(fcnv_dw_d)215  float64 HELPER(fcnv_dw_d)(CPUHPPAState *env, int64_t arg)
216  {
217      float64 ret = int64_to_float64(arg, &env->fp_status);
218      update_fr0_op(env, GETPC());
219      return ret;
220  }
221  
HELPER(fcnv_s_w)222  int32_t HELPER(fcnv_s_w)(CPUHPPAState *env, float32 arg)
223  {
224      int32_t ret = float32_to_int32(arg, &env->fp_status);
225      update_fr0_op(env, GETPC());
226      return ret;
227  }
228  
HELPER(fcnv_d_w)229  int32_t HELPER(fcnv_d_w)(CPUHPPAState *env, float64 arg)
230  {
231      int32_t ret = float64_to_int32(arg, &env->fp_status);
232      update_fr0_op(env, GETPC());
233      return ret;
234  }
235  
HELPER(fcnv_s_dw)236  int64_t HELPER(fcnv_s_dw)(CPUHPPAState *env, float32 arg)
237  {
238      int64_t ret = float32_to_int64(arg, &env->fp_status);
239      update_fr0_op(env, GETPC());
240      return ret;
241  }
242  
HELPER(fcnv_d_dw)243  int64_t HELPER(fcnv_d_dw)(CPUHPPAState *env, float64 arg)
244  {
245      int64_t ret = float64_to_int64(arg, &env->fp_status);
246      update_fr0_op(env, GETPC());
247      return ret;
248  }
249  
HELPER(fcnv_t_s_w)250  int32_t HELPER(fcnv_t_s_w)(CPUHPPAState *env, float32 arg)
251  {
252      int32_t ret = float32_to_int32_round_to_zero(arg, &env->fp_status);
253      update_fr0_op(env, GETPC());
254      return ret;
255  }
256  
HELPER(fcnv_t_d_w)257  int32_t HELPER(fcnv_t_d_w)(CPUHPPAState *env, float64 arg)
258  {
259      int32_t ret = float64_to_int32_round_to_zero(arg, &env->fp_status);
260      update_fr0_op(env, GETPC());
261      return ret;
262  }
263  
HELPER(fcnv_t_s_dw)264  int64_t HELPER(fcnv_t_s_dw)(CPUHPPAState *env, float32 arg)
265  {
266      int64_t ret = float32_to_int64_round_to_zero(arg, &env->fp_status);
267      update_fr0_op(env, GETPC());
268      return ret;
269  }
270  
HELPER(fcnv_t_d_dw)271  int64_t HELPER(fcnv_t_d_dw)(CPUHPPAState *env, float64 arg)
272  {
273      int64_t ret = float64_to_int64_round_to_zero(arg, &env->fp_status);
274      update_fr0_op(env, GETPC());
275      return ret;
276  }
277  
HELPER(fcnv_uw_s)278  float32 HELPER(fcnv_uw_s)(CPUHPPAState *env, uint32_t arg)
279  {
280      float32 ret = uint32_to_float32(arg, &env->fp_status);
281      update_fr0_op(env, GETPC());
282      return ret;
283  }
284  
HELPER(fcnv_udw_s)285  float32 HELPER(fcnv_udw_s)(CPUHPPAState *env, uint64_t arg)
286  {
287      float32 ret = uint64_to_float32(arg, &env->fp_status);
288      update_fr0_op(env, GETPC());
289      return ret;
290  }
291  
HELPER(fcnv_uw_d)292  float64 HELPER(fcnv_uw_d)(CPUHPPAState *env, uint32_t arg)
293  {
294      float64 ret = uint32_to_float64(arg, &env->fp_status);
295      update_fr0_op(env, GETPC());
296      return ret;
297  }
298  
HELPER(fcnv_udw_d)299  float64 HELPER(fcnv_udw_d)(CPUHPPAState *env, uint64_t arg)
300  {
301      float64 ret = uint64_to_float64(arg, &env->fp_status);
302      update_fr0_op(env, GETPC());
303      return ret;
304  }
305  
HELPER(fcnv_s_uw)306  uint32_t HELPER(fcnv_s_uw)(CPUHPPAState *env, float32 arg)
307  {
308      uint32_t ret = float32_to_uint32(arg, &env->fp_status);
309      update_fr0_op(env, GETPC());
310      return ret;
311  }
312  
HELPER(fcnv_d_uw)313  uint32_t HELPER(fcnv_d_uw)(CPUHPPAState *env, float64 arg)
314  {
315      uint32_t ret = float64_to_uint32(arg, &env->fp_status);
316      update_fr0_op(env, GETPC());
317      return ret;
318  }
319  
HELPER(fcnv_s_udw)320  uint64_t HELPER(fcnv_s_udw)(CPUHPPAState *env, float32 arg)
321  {
322      uint64_t ret = float32_to_uint64(arg, &env->fp_status);
323      update_fr0_op(env, GETPC());
324      return ret;
325  }
326  
HELPER(fcnv_d_udw)327  uint64_t HELPER(fcnv_d_udw)(CPUHPPAState *env, float64 arg)
328  {
329      uint64_t ret = float64_to_uint64(arg, &env->fp_status);
330      update_fr0_op(env, GETPC());
331      return ret;
332  }
333  
HELPER(fcnv_t_s_uw)334  uint32_t HELPER(fcnv_t_s_uw)(CPUHPPAState *env, float32 arg)
335  {
336      uint32_t ret = float32_to_uint32_round_to_zero(arg, &env->fp_status);
337      update_fr0_op(env, GETPC());
338      return ret;
339  }
340  
HELPER(fcnv_t_d_uw)341  uint32_t HELPER(fcnv_t_d_uw)(CPUHPPAState *env, float64 arg)
342  {
343      uint32_t ret = float64_to_uint32_round_to_zero(arg, &env->fp_status);
344      update_fr0_op(env, GETPC());
345      return ret;
346  }
347  
HELPER(fcnv_t_s_udw)348  uint64_t HELPER(fcnv_t_s_udw)(CPUHPPAState *env, float32 arg)
349  {
350      uint64_t ret = float32_to_uint64_round_to_zero(arg, &env->fp_status);
351      update_fr0_op(env, GETPC());
352      return ret;
353  }
354  
HELPER(fcnv_t_d_udw)355  uint64_t HELPER(fcnv_t_d_udw)(CPUHPPAState *env, float64 arg)
356  {
357      uint64_t ret = float64_to_uint64_round_to_zero(arg, &env->fp_status);
358      update_fr0_op(env, GETPC());
359      return ret;
360  }
361  
update_fr0_cmp(CPUHPPAState * env,uint32_t y,uint32_t c,FloatRelation r)362  static void update_fr0_cmp(CPUHPPAState *env, uint32_t y,
363                             uint32_t c, FloatRelation r)
364  {
365      uint32_t shadow = env->fr0_shadow;
366  
367      switch (r) {
368      case float_relation_greater:
369          c = extract32(c, 4, 1);
370          break;
371      case float_relation_less:
372          c = extract32(c, 3, 1);
373          break;
374      case float_relation_equal:
375          c = extract32(c, 2, 1);
376          break;
377      case float_relation_unordered:
378          c = extract32(c, 1, 1);
379          break;
380      default:
381          g_assert_not_reached();
382      }
383  
384      if (y) {
385          /* targeted comparison */
386          /* set fpsr[ca[y - 1]] to current compare */
387          shadow = deposit32(shadow, R_FPSR_CA0_SHIFT - (y - 1), 1, c);
388      } else {
389          /* queued comparison */
390          /* shift cq right by one place */
391          shadow = (shadow & ~R_FPSR_CQ_MASK) | ((shadow >> 1) & R_FPSR_CQ_MASK);
392          /* move fpsr[c] to fpsr[cq[0]] */
393          shadow = FIELD_DP32(shadow, FPSR, CQ0, FIELD_EX32(shadow, FPSR, C));
394          /* set fpsr[c] to current compare */
395          shadow = FIELD_DP32(shadow, FPSR, C, c);
396      }
397  
398      env->fr0_shadow = shadow;
399      env->fr[0] = (uint64_t)shadow << 32;
400  }
401  
HELPER(fcmp_s)402  void HELPER(fcmp_s)(CPUHPPAState *env, float32 a, float32 b,
403                      uint32_t y, uint32_t c)
404  {
405      FloatRelation r;
406      if (c & 1) {
407          r = float32_compare(a, b, &env->fp_status);
408      } else {
409          r = float32_compare_quiet(a, b, &env->fp_status);
410      }
411      update_fr0_op(env, GETPC());
412      update_fr0_cmp(env, y, c, r);
413  }
414  
HELPER(fcmp_d)415  void HELPER(fcmp_d)(CPUHPPAState *env, float64 a, float64 b,
416                      uint32_t y, uint32_t c)
417  {
418      FloatRelation r;
419      if (c & 1) {
420          r = float64_compare(a, b, &env->fp_status);
421      } else {
422          r = float64_compare_quiet(a, b, &env->fp_status);
423      }
424      update_fr0_op(env, GETPC());
425      update_fr0_cmp(env, y, c, r);
426  }
427  
HELPER(fmpyfadd_s)428  float32 HELPER(fmpyfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c)
429  {
430      float32 ret = float32_muladd(a, b, c, 0, &env->fp_status);
431      update_fr0_op(env, GETPC());
432      return ret;
433  }
434  
HELPER(fmpynfadd_s)435  float32 HELPER(fmpynfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c)
436  {
437      float32 ret = float32_muladd(a, b, c, float_muladd_negate_product,
438                                   &env->fp_status);
439      update_fr0_op(env, GETPC());
440      return ret;
441  }
442  
HELPER(fmpyfadd_d)443  float64 HELPER(fmpyfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c)
444  {
445      float64 ret = float64_muladd(a, b, c, 0, &env->fp_status);
446      update_fr0_op(env, GETPC());
447      return ret;
448  }
449  
HELPER(fmpynfadd_d)450  float64 HELPER(fmpynfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c)
451  {
452      float64 ret = float64_muladd(a, b, c, float_muladd_negate_product,
453                                   &env->fp_status);
454      update_fr0_op(env, GETPC());
455      return ret;
456  }
457