]>
git.proxmox.com Git - mirror_qemu.git/blob - target-ppc/op_helper.c
2 * PowerPC emulation helpers for qemu.
4 * Copyright (c) 2003-2005 Jocelyn Mayer
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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #define MEMSUFFIX _raw
24 #include "op_helper_mem.h"
25 #if !defined(CONFIG_USER_ONLY)
26 #define MEMSUFFIX _user
27 #include "op_helper_mem.h"
28 #define MEMSUFFIX _kernel
29 #include "op_helper_mem.h"
32 /*****************************************************************************/
33 /* Exceptions processing helpers */
34 void cpu_loop_exit(void)
36 longjmp(env
->jmp_env
, 1);
39 void do_raise_exception_err (uint32_t exception
, int error_code
)
42 printf("Raise exception %3x code : %d\n", exception
, error_code
);
47 printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n");
52 if (error_code
== EXCP_FP
&& msr_fe0
== 0 && msr_fe1
== 0)
58 env
->exception_index
= exception
;
59 env
->error_code
= error_code
;
63 void do_raise_exception (uint32_t exception
)
65 do_raise_exception_err(exception
, 0);
68 /*****************************************************************************/
69 /* Helpers for "fat" micro operations */
70 /* shift right arithmetic helper */
77 ret
= (-1) * (T0
>> 31);
78 if (ret
< 0 && (T0
& ~0x80000000) != 0)
85 ret
= (int32_t)T0
>> (T1
& 0x1f);
86 if (ret
< 0 && ((int32_t)T0
& ((1 << T1
) - 1)) != 0)
92 /* Floating point operations helpers */
100 /* XXX: higher bits are not supposed to be significant.
101 * to make tests easier, return the same as a real PowerPC 750 (aka G3)
103 p
.i
= float64_to_int32(FT0
, &env
->fp_status
);
104 p
.i
|= 0xFFF80000ULL
<< 32;
108 void do_fctiwz (void)
115 /* XXX: higher bits are not supposed to be significant.
116 * to make tests easier, return the same as a real PowerPC 750 (aka G3)
118 p
.i
= float64_to_int32_round_to_zero(FT0
, &env
->fp_status
);
119 p
.i
|= 0xFFF80000ULL
<< 32;
123 void do_fnmadd (void)
125 FT0
= (FT0
* FT1
) + FT2
;
130 void do_fnmsub (void)
132 FT0
= (FT0
* FT1
) - FT2
;
139 if (FT0
== -0.0 && FT1
== -0.0)
158 FT0
= (float)(1.0 / FT0
);
161 if (p
.i
== 0x8000000000000000ULL
) {
162 p
.i
= 0xFFF0000000000000ULL
;
163 } else if (p
.i
== 0x0000000000000000ULL
) {
164 p
.i
= 0x7FF0000000000000ULL
;
165 } else if (isnan(FT0
)) {
166 p
.i
= 0x7FF8000000000000ULL
;
167 } else if (FT0
< 0.0) {
168 p
.i
= 0x8000000000000000ULL
;
170 p
.i
= 0x0000000000000000ULL
;
176 void do_frsqrte (void)
183 if (isnormal(FT0
) && FT0
> 0.0) {
184 FT0
= (float)(1.0 / sqrt(FT0
));
187 if (p
.i
== 0x8000000000000000ULL
) {
188 p
.i
= 0xFFF0000000000000ULL
;
189 } else if (p
.i
== 0x0000000000000000ULL
) {
190 p
.i
= 0x7FF0000000000000ULL
;
191 } else if (isnan(FT0
)) {
192 if (!(p
.i
& 0x0008000000000000ULL
))
193 p
.i
|= 0x000FFFFFFFFFFFFFULL
;
194 } else if (FT0
< 0) {
195 p
.i
= 0x7FF8000000000000ULL
;
197 p
.i
= 0x0000000000000000ULL
;
213 if (isnan(FT0
) || isnan(FT1
)) {
215 env
->fpscr
[4] |= 0x1;
216 env
->fpscr
[6] |= 0x1;
217 } else if (FT0
< FT1
) {
219 } else if (FT0
> FT1
) {
229 env
->fpscr
[4] &= ~0x1;
230 if (isnan(FT0
) || isnan(FT1
)) {
232 env
->fpscr
[4] |= 0x1;
233 /* I don't know how to test "quiet" nan... */
234 if (0 /* || ! quiet_nan(...) */) {
235 env
->fpscr
[6] |= 0x1;
236 if (!(env
->fpscr
[1] & 0x8))
237 env
->fpscr
[4] |= 0x8;
239 env
->fpscr
[4] |= 0x8;
241 } else if (FT0
< FT1
) {
243 } else if (FT0
> FT1
) {
259 p
.i
&= ~0x8000000000000000ULL
;
271 p
.i
|= 0x8000000000000000ULL
;
275 /* Instruction cache invalidation helper */
276 #define ICACHE_LINE_SIZE 32
278 void do_check_reservation (void)
280 if ((env
->reserve
& ~0x03) == T0
)
286 /* Invalidate one cache line */
287 T0
&= ~(ICACHE_LINE_SIZE
- 1);
288 tb_invalidate_page_range(T0
, T0
+ ICACHE_LINE_SIZE
);
291 /* TLB invalidation helpers */
299 tlb_flush_page(env
, T0
);