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