Arm Linux EABI syscall support.
[qemu] / target-ppc / op_helper.c
1 /*
2  *  PowerPC emulation helpers for qemu.
3  * 
4  *  Copyright (c) 2003-2005 Jocelyn Mayer
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 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <math.h>
21 #include "exec.h"
22
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"
30 #endif
31
32 //#define DEBUG_OP
33 //#define DEBUG_EXCEPTIONS
34 //#define FLUSH_ALL_TLBS
35
36 #define Ts0 (long)((target_long)T0)
37 #define Ts1 (long)((target_long)T1)
38 #define Ts2 (long)((target_long)T2)
39
40 /*****************************************************************************/
41 /* Exceptions processing helpers */
42 void cpu_loop_exit(void)
43 {
44     longjmp(env->jmp_env, 1);
45 }
46
47 void do_raise_exception_err (uint32_t exception, int error_code)
48 {
49 #if 0
50     printf("Raise exception %3x code : %d\n", exception, error_code);
51 #endif
52     switch (exception) {
53     case EXCP_PROGRAM:
54         if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
55             return;
56         break;
57     default:
58         break;
59 }
60     env->exception_index = exception;
61     env->error_code = error_code;
62         cpu_loop_exit();
63     }
64
65 void do_raise_exception (uint32_t exception)
66 {
67     do_raise_exception_err(exception, 0);
68 }
69
70 /*****************************************************************************/
71 /* Fixed point operations helpers */
72 void do_addo (void)
73 {
74     T2 = T0;
75     T0 += T1;
76     if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
77         xer_ov = 0;
78     } else {
79         xer_so = 1;
80         xer_ov = 1;
81     }
82 }
83
84 void do_addco (void)
85 {
86     T2 = T0;
87     T0 += T1;
88     if (likely(T0 >= T2)) {
89         xer_ca = 0;
90     } else {
91         xer_ca = 1;
92     }
93     if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
94         xer_ov = 0;
95     } else {
96         xer_so = 1;
97         xer_ov = 1;
98     }
99 }
100
101 void do_adde (void)
102 {
103     T2 = T0;
104     T0 += T1 + xer_ca;
105     if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
106         xer_ca = 0;
107     } else {
108         xer_ca = 1;
109     }
110 }
111
112 void do_addeo (void)
113 {
114     T2 = T0;
115     T0 += T1 + xer_ca;
116     if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
117         xer_ca = 0;
118     } else {
119         xer_ca = 1;
120     }
121     if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
122         xer_ov = 0;
123     } else {
124         xer_so = 1;
125         xer_ov = 1;
126     }
127 }
128
129 void do_addmeo (void)
130 {
131     T1 = T0;
132     T0 += xer_ca + (-1);
133     if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) {
134         xer_ov = 0;
135     } else {
136         xer_so = 1;
137         xer_ov = 1;
138     }
139     if (likely(T1 != 0))
140         xer_ca = 1;
141 }
142
143 void do_addzeo (void)
144 {
145     T1 = T0;
146     T0 += xer_ca;
147     if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) {
148         xer_ov = 0;
149     } else {
150         xer_so = 1;
151         xer_ov = 1;
152     }
153     if (likely(T0 >= T1)) {
154         xer_ca = 0;
155     } else {
156         xer_ca = 1;
157     }
158 }
159
160 void do_divwo (void)
161 {
162     if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) {
163         xer_ov = 0;
164         T0 = (Ts0 / Ts1);
165     } else {
166         xer_so = 1;
167         xer_ov = 1;
168         T0 = (-1) * ((uint32_t)T0 >> 31);
169     }
170 }
171
172 void do_divwuo (void)
173 {
174     if (likely((uint32_t)T1 != 0)) {
175         xer_ov = 0;
176         T0 = (uint32_t)T0 / (uint32_t)T1;
177     } else {
178         xer_so = 1;
179         xer_ov = 1;
180         T0 = 0;
181     }
182 }
183
184 void do_mullwo (void)
185 {
186     int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
187
188     if (likely((int32_t)res == res)) {
189         xer_ov = 0;
190     } else {
191         xer_ov = 1;
192         xer_so = 1;
193     }
194     T0 = (int32_t)res;
195 }
196
197 void do_nego (void)
198 {
199     if (likely(T0 != INT32_MIN)) {
200         xer_ov = 0;
201         T0 = -Ts0;
202     } else {
203         xer_ov = 1;
204         xer_so = 1;
205     }
206 }
207
208 void do_subfo (void)
209 {
210     T2 = T0;
211     T0 = T1 - T0;
212     if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
213         xer_ov = 0;
214     } else {
215         xer_so = 1;
216         xer_ov = 1;
217     }
218     RETURN();
219 }
220
221 void do_subfco (void)
222 {
223     T2 = T0;
224     T0 = T1 - T0;
225     if (likely(T0 > T1)) {
226         xer_ca = 0;
227     } else {
228         xer_ca = 1;
229     }
230     if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
231         xer_ov = 0;
232     } else {
233         xer_so = 1;
234         xer_ov = 1;
235     }
236 }
237
238 void do_subfe (void)
239 {
240     T0 = T1 + ~T0 + xer_ca;
241     if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
242         xer_ca = 0;
243     } else {
244         xer_ca = 1;
245     }
246 }
247
248 void do_subfeo (void)
249 {
250     T2 = T0;
251     T0 = T1 + ~T0 + xer_ca;
252     if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) {
253         xer_ov = 0;
254     } else {
255         xer_so = 1;
256         xer_ov = 1;
257     }
258     if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
259         xer_ca = 0;
260     } else {
261         xer_ca = 1;
262     }
263 }
264
265 void do_subfmeo (void)
266 {
267     T1 = T0;
268     T0 = ~T0 + xer_ca - 1;
269     if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) {
270         xer_ov = 0;
271     } else {
272         xer_so = 1;
273         xer_ov = 1;
274     }
275     if (likely(T1 != -1))
276         xer_ca = 1;
277 }
278
279 void do_subfzeo (void)
280 {
281     T1 = T0;
282     T0 = ~T0 + xer_ca;
283     if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) {
284         xer_ov = 0;
285     } else {
286         xer_ov = 1;
287         xer_so = 1;
288     }
289     if (likely(T0 >= ~T1)) {
290         xer_ca = 0;
291     } else {
292         xer_ca = 1;
293     }
294 }
295
296 /* shift right arithmetic helper */
297 void do_sraw (void)
298 {
299     int32_t ret;
300
301     if (likely(!(T1 & 0x20UL))) {
302         if (likely(T1 != 0)) {
303             ret = (int32_t)T0 >> (T1 & 0x1fUL);
304             if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
305     xer_ca = 0;
306             } else {
307             xer_ca = 1;
308             }
309         } else {
310         ret = T0;
311             xer_ca = 0;
312         }
313     } else {
314         ret = (-1) * ((uint32_t)T0 >> 31);
315         if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
316             xer_ca = 0;
317     } else {
318             xer_ca = 1;
319     }
320     }
321     T0 = ret;
322 }
323
324 /*****************************************************************************/
325 /* Floating point operations helpers */
326 void do_fctiw (void)
327 {
328     union {
329         double d;
330         uint64_t i;
331     } p;
332
333     /* XXX: higher bits are not supposed to be significant.
334      *      to make tests easier, return the same as a real PowerPC 750 (aka G3)
335      */
336     p.i = float64_to_int32(FT0, &env->fp_status);
337     p.i |= 0xFFF80000ULL << 32;
338     FT0 = p.d;
339 }
340
341 void do_fctiwz (void)
342 {
343     union {
344         double d;
345         uint64_t i;
346     } p;
347
348     /* XXX: higher bits are not supposed to be significant.
349      *      to make tests easier, return the same as a real PowerPC 750 (aka G3)
350      */
351     p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
352     p.i |= 0xFFF80000ULL << 32;
353     FT0 = p.d;
354 }
355
356 void do_fnmadd (void)
357 {
358     FT0 = float64_mul(FT0, FT1, &env->fp_status);
359     FT0 = float64_add(FT0, FT2, &env->fp_status);
360     if (likely(!isnan(FT0)))
361         FT0 = float64_chs(FT0);
362 }
363
364 void do_fnmsub (void)
365 {
366     FT0 = float64_mul(FT0, FT1, &env->fp_status);
367     FT0 = float64_sub(FT0, FT2, &env->fp_status);
368     if (likely(!isnan(FT0)))
369         FT0 = float64_chs(FT0);
370 }
371
372 void do_fsqrt (void)
373 {
374     FT0 = float64_sqrt(FT0, &env->fp_status);
375 }
376
377 void do_fres (void)
378 {
379     union {
380         double d;
381         uint64_t i;
382     } p;
383
384     if (likely(isnormal(FT0))) {
385         FT0 = (float)(1.0 / FT0);
386     } else {
387         p.d = FT0;
388         if (p.i == 0x8000000000000000ULL) {
389             p.i = 0xFFF0000000000000ULL;
390         } else if (p.i == 0x0000000000000000ULL) {
391             p.i = 0x7FF0000000000000ULL;
392         } else if (isnan(FT0)) {
393             p.i = 0x7FF8000000000000ULL;
394         } else if (FT0 < 0.0) {
395             p.i = 0x8000000000000000ULL;
396         } else {
397             p.i = 0x0000000000000000ULL;
398         }
399         FT0 = p.d;
400     }
401 }
402
403 void do_frsqrte (void)
404 {
405     union {
406         double d;
407         uint64_t i;
408     } p;
409
410     if (likely(isnormal(FT0) && FT0 > 0.0)) {
411         FT0 = float64_sqrt(FT0, &env->fp_status);
412         FT0 = float32_div(1.0, FT0, &env->fp_status);
413     } else {
414         p.d = FT0;
415         if (p.i == 0x8000000000000000ULL) {
416             p.i = 0xFFF0000000000000ULL;
417         } else if (p.i == 0x0000000000000000ULL) {
418             p.i = 0x7FF0000000000000ULL;
419         } else if (isnan(FT0)) {
420             if (!(p.i & 0x0008000000000000ULL))
421                 p.i |= 0x000FFFFFFFFFFFFFULL;
422         } else if (FT0 < 0) {
423             p.i = 0x7FF8000000000000ULL;
424         } else {
425             p.i = 0x0000000000000000ULL;
426         }
427         FT0 = p.d;
428     }
429 }
430
431 void do_fsel (void)
432 {
433     if (FT0 >= 0)
434         FT0 = FT1;
435     else
436         FT0 = FT2;
437 }
438
439 void do_fcmpu (void)
440 {
441     if (likely(!isnan(FT0) && !isnan(FT1))) {
442         if (float64_lt(FT0, FT1, &env->fp_status)) {
443             T0 = 0x08UL;
444         } else if (!float64_le(FT0, FT1, &env->fp_status)) {
445             T0 = 0x04UL;
446         } else {
447             T0 = 0x02UL;
448         }
449     } else {
450         T0 = 0x01UL;
451         env->fpscr[4] |= 0x1;
452         env->fpscr[6] |= 0x1;
453     }
454     env->fpscr[3] = T0;
455 }
456
457 void do_fcmpo (void)
458 {
459     env->fpscr[4] &= ~0x1;
460     if (likely(!isnan(FT0) && !isnan(FT1))) {
461         if (float64_lt(FT0, FT1, &env->fp_status)) {
462             T0 = 0x08UL;
463         } else if (!float64_le(FT0, FT1, &env->fp_status)) {
464             T0 = 0x04UL;
465         } else {
466             T0 = 0x02UL;
467         }
468     } else {
469         T0 = 0x01UL;
470         env->fpscr[4] |= 0x1;
471         /* I don't know how to test "quiet" nan... */
472         if (0 /* || ! quiet_nan(...) */) {
473             env->fpscr[6] |= 0x1;
474             if (!(env->fpscr[1] & 0x8))
475                 env->fpscr[4] |= 0x8;
476         } else {
477             env->fpscr[4] |= 0x8;
478         }
479     }
480     env->fpscr[3] = T0;
481 }
482
483 void do_rfi (void)
484 {
485     env->nip = env->spr[SPR_SRR0] & ~0x00000003;
486     T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
487     do_store_msr(env, T0);
488 #if defined (DEBUG_OP)
489     dump_rfi();
490 #endif
491     env->interrupt_request |= CPU_INTERRUPT_EXITTB;
492 }
493
494 void do_tw (uint32_t cmp, int flags)
495 {
496     if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
497                   (Ts0 > (int32_t)cmp && (flags & 0x08)) ||
498                   (Ts0 == (int32_t)cmp && (flags & 0x04)) ||
499                   (T0 < cmp && (flags & 0x02)) ||
500                   (T0 > cmp && (flags & 0x01)))))
501         do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
502 }
503
504 /* Instruction cache invalidation helper */
505 void do_icbi (void)
506 {
507     uint32_t tmp;
508     /* Invalidate one cache line :
509      * PowerPC specification says this is to be treated like a load
510      * (not a fetch) by the MMU. To be sure it will be so,
511      * do the load "by hand".
512      */
513 #if defined(TARGET_PPC64)
514     if (!msr_sf)
515         T0 &= 0xFFFFFFFFULL;
516 #endif
517     tmp = ldl_kernel(T0);
518     T0 &= ~(ICACHE_LINE_SIZE - 1);
519     tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
520 }
521
522 /*****************************************************************************/
523 /* MMU related helpers */
524 /* TLB invalidation helpers */
525 void do_tlbia (void)
526 {
527     tlb_flush(env, 1);
528 }
529
530 void do_tlbie (void)
531 {
532 #if !defined(FLUSH_ALL_TLBS)
533     tlb_flush_page(env, T0);
534 #else
535     do_tlbia();
536 #endif
537 }
538
539 /*****************************************************************************/
540 /* Softmmu support */
541 #if !defined (CONFIG_USER_ONLY)
542
543 #define MMUSUFFIX _mmu
544 #define GETPC() (__builtin_return_address(0))
545
546 #define SHIFT 0
547 #include "softmmu_template.h"
548
549 #define SHIFT 1
550 #include "softmmu_template.h"
551
552 #define SHIFT 2
553 #include "softmmu_template.h"
554
555 #define SHIFT 3
556 #include "softmmu_template.h"
557
558 /* try to fill the TLB and return an exception if error. If retaddr is
559    NULL, it means that the function was called in C code (i.e. not
560    from generated code or from helper.c) */
561 /* XXX: fix it to restore all registers */
562 void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
563 {
564     TranslationBlock *tb;
565     CPUState *saved_env;
566     target_phys_addr_t pc;
567     int ret;
568
569     /* XXX: hack to restore env in all cases, even if not called from
570        generated code */
571     saved_env = env;
572     env = cpu_single_env;
573     ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
574     if (!likely(ret == 0)) {
575         if (likely(retaddr)) {
576             /* now we have a real cpu fault */
577             pc = (target_phys_addr_t)retaddr;
578             tb = tb_find_pc(pc);
579             if (likely(tb)) {
580                 /* the PC is inside the translated code. It means that we have
581                    a virtual CPU fault */
582                 cpu_restore_state(tb, env, pc, NULL);
583 }
584         }
585         do_raise_exception_err(env->exception_index, env->error_code);
586     }
587     env = saved_env;
588 }
589 #endif /* !CONFIG_USER_ONLY */
590