xref: /openbmc/qemu/target/hppa/fpu_helper.c (revision 2f95279a)
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