4 * Copyright (c) 2006-2007 CodeSourcery
5 * Written by Paul Brook
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
23 #include "exec/helper-proto.h"
24 #include "exec/exec-all.h"
25 #include "exec/cpu_ldst.h"
27 /* Undefined offsets may be different on various FPU.
28 * On 68040 they return 0.0 (floatx80_zero)
31 static const floatx80 fpu_rom
[128] = {
32 [0x00] = make_floatx80_init(0x4000, 0xc90fdaa22168c235ULL
), /* Pi */
33 [0x0b] = make_floatx80_init(0x3ffd, 0x9a209a84fbcff798ULL
), /* Log10(2) */
34 [0x0c] = make_floatx80_init(0x4000, 0xadf85458a2bb4a9aULL
), /* e */
35 [0x0d] = make_floatx80_init(0x3fff, 0xb8aa3b295c17f0bcULL
), /* Log2(e) */
36 [0x0e] = make_floatx80_init(0x3ffd, 0xde5bd8a937287195ULL
), /* Log10(e) */
37 [0x0f] = make_floatx80_init(0x0000, 0x0000000000000000ULL
), /* Zero */
38 [0x30] = make_floatx80_init(0x3ffe, 0xb17217f7d1cf79acULL
), /* ln(2) */
39 [0x31] = make_floatx80_init(0x4000, 0x935d8dddaaa8ac17ULL
), /* ln(10) */
40 [0x32] = make_floatx80_init(0x3fff, 0x8000000000000000ULL
), /* 10^0 */
41 [0x33] = make_floatx80_init(0x4002, 0xa000000000000000ULL
), /* 10^1 */
42 [0x34] = make_floatx80_init(0x4005, 0xc800000000000000ULL
), /* 10^2 */
43 [0x35] = make_floatx80_init(0x400c, 0x9c40000000000000ULL
), /* 10^4 */
44 [0x36] = make_floatx80_init(0x4019, 0xbebc200000000000ULL
), /* 10^8 */
45 [0x37] = make_floatx80_init(0x4034, 0x8e1bc9bf04000000ULL
), /* 10^16 */
46 [0x38] = make_floatx80_init(0x4069, 0x9dc5ada82b70b59eULL
), /* 10^32 */
47 [0x39] = make_floatx80_init(0x40d3, 0xc2781f49ffcfa6d5ULL
), /* 10^64 */
48 [0x3a] = make_floatx80_init(0x41a8, 0x93ba47c980e98ce0ULL
), /* 10^128 */
49 [0x3b] = make_floatx80_init(0x4351, 0xaa7eebfb9df9de8eULL
), /* 10^256 */
50 [0x3c] = make_floatx80_init(0x46a3, 0xe319a0aea60e91c7ULL
), /* 10^512 */
51 [0x3d] = make_floatx80_init(0x4d48, 0xc976758681750c17ULL
), /* 10^1024 */
52 [0x3e] = make_floatx80_init(0x5a92, 0x9e8b3b5dc53d5de5ULL
), /* 10^2048 */
53 [0x3f] = make_floatx80_init(0x7525, 0xc46052028a20979bULL
), /* 10^4096 */
56 int32_t HELPER(reds32
)(CPUM68KState
*env
, FPReg
*val
)
58 return floatx80_to_int32(val
->d
, &env
->fp_status
);
61 float32
HELPER(redf32
)(CPUM68KState
*env
, FPReg
*val
)
63 return floatx80_to_float32(val
->d
, &env
->fp_status
);
66 void HELPER(exts32
)(CPUM68KState
*env
, FPReg
*res
, int32_t val
)
68 res
->d
= int32_to_floatx80(val
, &env
->fp_status
);
71 void HELPER(extf32
)(CPUM68KState
*env
, FPReg
*res
, float32 val
)
73 res
->d
= float32_to_floatx80(val
, &env
->fp_status
);
76 void HELPER(extf64
)(CPUM68KState
*env
, FPReg
*res
, float64 val
)
78 res
->d
= float64_to_floatx80(val
, &env
->fp_status
);
81 float64
HELPER(redf64
)(CPUM68KState
*env
, FPReg
*val
)
83 return floatx80_to_float64(val
->d
, &env
->fp_status
);
86 void HELPER(firound
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
88 res
->d
= floatx80_round_to_int(val
->d
, &env
->fp_status
);
91 static void m68k_restore_precision_mode(CPUM68KState
*env
)
93 switch (env
->fpcr
& FPCR_PREC_MASK
) {
94 case FPCR_PREC_X
: /* extended */
95 set_floatx80_rounding_precision(80, &env
->fp_status
);
97 case FPCR_PREC_S
: /* single */
98 set_floatx80_rounding_precision(32, &env
->fp_status
);
100 case FPCR_PREC_D
: /* double */
101 set_floatx80_rounding_precision(64, &env
->fp_status
);
103 case FPCR_PREC_U
: /* undefined */
109 static void cf_restore_precision_mode(CPUM68KState
*env
)
111 if (env
->fpcr
& FPCR_PREC_S
) { /* single */
112 set_floatx80_rounding_precision(32, &env
->fp_status
);
113 } else { /* double */
114 set_floatx80_rounding_precision(64, &env
->fp_status
);
118 static void restore_rounding_mode(CPUM68KState
*env
)
120 switch (env
->fpcr
& FPCR_RND_MASK
) {
121 case FPCR_RND_N
: /* round to nearest */
122 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
124 case FPCR_RND_Z
: /* round to zero */
125 set_float_rounding_mode(float_round_to_zero
, &env
->fp_status
);
127 case FPCR_RND_M
: /* round toward minus infinity */
128 set_float_rounding_mode(float_round_down
, &env
->fp_status
);
130 case FPCR_RND_P
: /* round toward positive infinity */
131 set_float_rounding_mode(float_round_up
, &env
->fp_status
);
136 void cpu_m68k_set_fpcr(CPUM68KState
*env
, uint32_t val
)
138 env
->fpcr
= val
& 0xffff;
140 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
141 cf_restore_precision_mode(env
);
143 m68k_restore_precision_mode(env
);
145 restore_rounding_mode(env
);
148 void HELPER(fitrunc
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
150 int rounding_mode
= get_float_rounding_mode(&env
->fp_status
);
151 set_float_rounding_mode(float_round_to_zero
, &env
->fp_status
);
152 res
->d
= floatx80_round_to_int(val
->d
, &env
->fp_status
);
153 set_float_rounding_mode(rounding_mode
, &env
->fp_status
);
156 void HELPER(set_fpcr
)(CPUM68KState
*env
, uint32_t val
)
158 cpu_m68k_set_fpcr(env
, val
);
161 #define PREC_BEGIN(prec) \
164 old = get_floatx80_rounding_precision(&env->fp_status); \
165 set_floatx80_rounding_precision(prec, &env->fp_status) \
168 set_floatx80_rounding_precision(old, &env->fp_status); \
171 void HELPER(fsround
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
174 res
->d
= floatx80_round(val
->d
, &env
->fp_status
);
178 void HELPER(fdround
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
181 res
->d
= floatx80_round(val
->d
, &env
->fp_status
);
185 void HELPER(fsqrt
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
187 res
->d
= floatx80_sqrt(val
->d
, &env
->fp_status
);
190 void HELPER(fssqrt
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
193 res
->d
= floatx80_sqrt(val
->d
, &env
->fp_status
);
197 void HELPER(fdsqrt
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
200 res
->d
= floatx80_sqrt(val
->d
, &env
->fp_status
);
204 void HELPER(fabs
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
206 res
->d
= floatx80_round(floatx80_abs(val
->d
), &env
->fp_status
);
209 void HELPER(fsabs
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
212 res
->d
= floatx80_round(floatx80_abs(val
->d
), &env
->fp_status
);
216 void HELPER(fdabs
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
219 res
->d
= floatx80_round(floatx80_abs(val
->d
), &env
->fp_status
);
223 void HELPER(fneg
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
225 res
->d
= floatx80_round(floatx80_chs(val
->d
), &env
->fp_status
);
228 void HELPER(fsneg
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
231 res
->d
= floatx80_round(floatx80_chs(val
->d
), &env
->fp_status
);
235 void HELPER(fdneg
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val
)
238 res
->d
= floatx80_round(floatx80_chs(val
->d
), &env
->fp_status
);
242 void HELPER(fadd
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
244 res
->d
= floatx80_add(val0
->d
, val1
->d
, &env
->fp_status
);
247 void HELPER(fsadd
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
250 res
->d
= floatx80_add(val0
->d
, val1
->d
, &env
->fp_status
);
254 void HELPER(fdadd
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
257 res
->d
= floatx80_add(val0
->d
, val1
->d
, &env
->fp_status
);
261 void HELPER(fsub
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
263 res
->d
= floatx80_sub(val1
->d
, val0
->d
, &env
->fp_status
);
266 void HELPER(fssub
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
269 res
->d
= floatx80_sub(val1
->d
, val0
->d
, &env
->fp_status
);
273 void HELPER(fdsub
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
276 res
->d
= floatx80_sub(val1
->d
, val0
->d
, &env
->fp_status
);
280 void HELPER(fmul
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
282 res
->d
= floatx80_mul(val0
->d
, val1
->d
, &env
->fp_status
);
285 void HELPER(fsmul
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
288 res
->d
= floatx80_mul(val0
->d
, val1
->d
, &env
->fp_status
);
292 void HELPER(fdmul
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
295 res
->d
= floatx80_mul(val0
->d
, val1
->d
, &env
->fp_status
);
299 void HELPER(fsglmul
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
301 int rounding_mode
= get_float_rounding_mode(&env
->fp_status
);
305 set_float_rounding_mode(float_round_to_zero
, &env
->fp_status
);
306 a
= floatx80_round(val0
->d
, &env
->fp_status
);
307 b
= floatx80_round(val1
->d
, &env
->fp_status
);
308 set_float_rounding_mode(rounding_mode
, &env
->fp_status
);
309 res
->d
= floatx80_mul(a
, b
, &env
->fp_status
);
313 void HELPER(fdiv
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
315 res
->d
= floatx80_div(val1
->d
, val0
->d
, &env
->fp_status
);
318 void HELPER(fsdiv
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
321 res
->d
= floatx80_div(val1
->d
, val0
->d
, &env
->fp_status
);
325 void HELPER(fddiv
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
328 res
->d
= floatx80_div(val1
->d
, val0
->d
, &env
->fp_status
);
332 void HELPER(fsgldiv
)(CPUM68KState
*env
, FPReg
*res
, FPReg
*val0
, FPReg
*val1
)
334 int rounding_mode
= get_float_rounding_mode(&env
->fp_status
);
338 set_float_rounding_mode(float_round_to_zero
, &env
->fp_status
);
339 a
= floatx80_round(val1
->d
, &env
->fp_status
);
340 b
= floatx80_round(val0
->d
, &env
->fp_status
);
341 set_float_rounding_mode(rounding_mode
, &env
->fp_status
);
342 res
->d
= floatx80_div(a
, b
, &env
->fp_status
);
346 static int float_comp_to_cc(int float_compare
)
348 switch (float_compare
) {
349 case float_relation_equal
:
351 case float_relation_less
:
353 case float_relation_unordered
:
355 case float_relation_greater
:
358 g_assert_not_reached();
362 void HELPER(fcmp
)(CPUM68KState
*env
, FPReg
*val0
, FPReg
*val1
)
366 float_compare
= floatx80_compare(val1
->d
, val0
->d
, &env
->fp_status
);
367 env
->fpsr
= (env
->fpsr
& ~FPSR_CC_MASK
) | float_comp_to_cc(float_compare
);
370 void HELPER(ftst
)(CPUM68KState
*env
, FPReg
*val
)
374 if (floatx80_is_neg(val
->d
)) {
378 if (floatx80_is_any_nan(val
->d
)) {
380 } else if (floatx80_is_infinity(val
->d
)) {
382 } else if (floatx80_is_zero(val
->d
)) {
385 env
->fpsr
= (env
->fpsr
& ~FPSR_CC_MASK
) | cc
;
388 void HELPER(fconst
)(CPUM68KState
*env
, FPReg
*val
, uint32_t offset
)
390 val
->d
= fpu_rom
[offset
];
393 typedef int (*float_access
)(CPUM68KState
*env
, uint32_t addr
, FPReg
*fp
,
396 static uint32_t fmovem_predec(CPUM68KState
*env
, uint32_t addr
, uint32_t mask
,
399 uintptr_t ra
= GETPC();
402 for (i
= 7; i
>= 0; i
--, mask
<<= 1) {
404 size
= access(env
, addr
, &env
->fregs
[i
], ra
);
405 if ((mask
& 0xff) != 0x80) {
414 static uint32_t fmovem_postinc(CPUM68KState
*env
, uint32_t addr
, uint32_t mask
,
417 uintptr_t ra
= GETPC();
420 for (i
= 0; i
< 8; i
++, mask
<<= 1) {
422 size
= access(env
, addr
, &env
->fregs
[i
], ra
);
430 static int cpu_ld_floatx80_ra(CPUM68KState
*env
, uint32_t addr
, FPReg
*fp
,
436 high
= cpu_ldl_data_ra(env
, addr
, ra
);
437 low
= cpu_ldq_data_ra(env
, addr
+ 4, ra
);
439 fp
->l
.upper
= high
>> 16;
445 static int cpu_st_floatx80_ra(CPUM68KState
*env
, uint32_t addr
, FPReg
*fp
,
448 cpu_stl_data_ra(env
, addr
, fp
->l
.upper
<< 16, ra
);
449 cpu_stq_data_ra(env
, addr
+ 4, fp
->l
.lower
, ra
);
454 static int cpu_ld_float64_ra(CPUM68KState
*env
, uint32_t addr
, FPReg
*fp
,
459 val
= cpu_ldq_data_ra(env
, addr
, ra
);
460 fp
->d
= float64_to_floatx80(*(float64
*)&val
, &env
->fp_status
);
465 static int cpu_st_float64_ra(CPUM68KState
*env
, uint32_t addr
, FPReg
*fp
,
470 val
= floatx80_to_float64(fp
->d
, &env
->fp_status
);
471 cpu_stq_data_ra(env
, addr
, *(uint64_t *)&val
, ra
);
476 uint32_t HELPER(fmovemx_st_predec
)(CPUM68KState
*env
, uint32_t addr
,
479 return fmovem_predec(env
, addr
, mask
, cpu_st_floatx80_ra
);
482 uint32_t HELPER(fmovemx_st_postinc
)(CPUM68KState
*env
, uint32_t addr
,
485 return fmovem_postinc(env
, addr
, mask
, cpu_st_floatx80_ra
);
488 uint32_t HELPER(fmovemx_ld_postinc
)(CPUM68KState
*env
, uint32_t addr
,
491 return fmovem_postinc(env
, addr
, mask
, cpu_ld_floatx80_ra
);
494 uint32_t HELPER(fmovemd_st_predec
)(CPUM68KState
*env
, uint32_t addr
,
497 return fmovem_predec(env
, addr
, mask
, cpu_st_float64_ra
);
500 uint32_t HELPER(fmovemd_st_postinc
)(CPUM68KState
*env
, uint32_t addr
,
503 return fmovem_postinc(env
, addr
, mask
, cpu_st_float64_ra
);
506 uint32_t HELPER(fmovemd_ld_postinc
)(CPUM68KState
*env
, uint32_t addr
,
509 return fmovem_postinc(env
, addr
, mask
, cpu_ld_float64_ra
);