sync with latest
[sdk/emulator/qemu.git] / target-sh4 / op_helper.c
1 /*
2  *  SH4 emulation
3  *
4  *  Copyright (c) 2005 Samuel Tardieu
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, see <http://www.gnu.org/licenses/>.
18  */
19 #include <assert.h>
20 #include <stdlib.h>
21 #include "cpu.h"
22 #include "dyngen-exec.h"
23 #include "helper.h"
24
25 static void cpu_restore_state_from_retaddr(uintptr_t retaddr)
26 {
27     TranslationBlock *tb;
28
29     if (retaddr) {
30         tb = tb_find_pc(retaddr);
31         if (tb) {
32             /* the PC is inside the translated code. It means that we have
33                a virtual CPU fault */
34             cpu_restore_state(tb, env, retaddr);
35         }
36     }
37 }
38
39 #ifndef CONFIG_USER_ONLY
40 #include "softmmu_exec.h"
41
42 #define MMUSUFFIX _mmu
43
44 #define SHIFT 0
45 #include "softmmu_template.h"
46
47 #define SHIFT 1
48 #include "softmmu_template.h"
49
50 #define SHIFT 2
51 #include "softmmu_template.h"
52
53 #define SHIFT 3
54 #include "softmmu_template.h"
55
56 void tlb_fill(CPUSH4State *env1, target_ulong addr, int is_write, int mmu_idx,
57               uintptr_t retaddr)
58 {
59     CPUSH4State *saved_env;
60     int ret;
61
62     saved_env = env;
63     env = env1;
64     ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx);
65     if (ret) {
66         /* now we have a real cpu fault */
67         cpu_restore_state_from_retaddr(retaddr);
68         cpu_loop_exit(env);
69     }
70     env = saved_env;
71 }
72
73 #endif
74
75 void helper_ldtlb(void)
76 {
77 #ifdef CONFIG_USER_ONLY
78     /* XXXXX */
79     cpu_abort(env, "Unhandled ldtlb");
80 #else
81     cpu_load_tlb(env);
82 #endif
83 }
84
85 static inline void raise_exception(int index, uintptr_t retaddr)
86 {
87     env->exception_index = index;
88     cpu_restore_state_from_retaddr(retaddr);
89     cpu_loop_exit(env);
90 }
91
92 void helper_raise_illegal_instruction(void)
93 {
94     raise_exception(0x180, GETPC());
95 }
96
97 void helper_raise_slot_illegal_instruction(void)
98 {
99     raise_exception(0x1a0, GETPC());
100 }
101
102 void helper_raise_fpu_disable(void)
103 {
104     raise_exception(0x800, GETPC());
105 }
106
107 void helper_raise_slot_fpu_disable(void)
108 {
109     raise_exception(0x820, GETPC());
110 }
111
112 void helper_debug(void)
113 {
114     env->exception_index = EXCP_DEBUG;
115     cpu_loop_exit(env);
116 }
117
118 void helper_sleep(uint32_t next_pc)
119 {
120     env->halted = 1;
121     env->in_sleep = 1;
122     env->exception_index = EXCP_HLT;
123     env->pc = next_pc;
124     cpu_loop_exit(env);
125 }
126
127 void helper_trapa(uint32_t tra)
128 {
129     env->tra = tra << 2;
130     raise_exception(0x160, GETPC());
131 }
132
133 void helper_movcal(uint32_t address, uint32_t value)
134 {
135     if (cpu_sh4_is_cached (env, address))
136     {
137         memory_content *r = malloc (sizeof(memory_content));
138         r->address = address;
139         r->value = value;
140         r->next = NULL;
141
142         *(env->movcal_backup_tail) = r;
143         env->movcal_backup_tail = &(r->next);
144     }
145 }
146
147 void helper_discard_movcal_backup(void)
148 {
149     memory_content *current = env->movcal_backup;
150
151     while(current)
152     {
153         memory_content *next = current->next;
154         free (current);
155         env->movcal_backup = current = next;
156         if (current == NULL)
157             env->movcal_backup_tail = &(env->movcal_backup);
158     } 
159 }
160
161 void helper_ocbi(uint32_t address)
162 {
163     memory_content **current = &(env->movcal_backup);
164     while (*current)
165     {
166         uint32_t a = (*current)->address;
167         if ((a & ~0x1F) == (address & ~0x1F))
168         {
169             memory_content *next = (*current)->next;
170             stl(a, (*current)->value);
171             
172             if (next == NULL)
173             {
174                 env->movcal_backup_tail = current;
175             }
176
177             free (*current);
178             *current = next;
179             break;
180         }
181     }
182 }
183
184 uint32_t helper_addc(uint32_t arg0, uint32_t arg1)
185 {
186     uint32_t tmp0, tmp1;
187
188     tmp1 = arg0 + arg1;
189     tmp0 = arg1;
190     arg1 = tmp1 + (env->sr & 1);
191     if (tmp0 > tmp1)
192         env->sr |= SR_T;
193     else
194         env->sr &= ~SR_T;
195     if (tmp1 > arg1)
196         env->sr |= SR_T;
197     return arg1;
198 }
199
200 uint32_t helper_addv(uint32_t arg0, uint32_t arg1)
201 {
202     uint32_t dest, src, ans;
203
204     if ((int32_t) arg1 >= 0)
205         dest = 0;
206     else
207         dest = 1;
208     if ((int32_t) arg0 >= 0)
209         src = 0;
210     else
211         src = 1;
212     src += dest;
213     arg1 += arg0;
214     if ((int32_t) arg1 >= 0)
215         ans = 0;
216     else
217         ans = 1;
218     ans += dest;
219     if (src == 0 || src == 2) {
220         if (ans == 1)
221             env->sr |= SR_T;
222         else
223             env->sr &= ~SR_T;
224     } else
225         env->sr &= ~SR_T;
226     return arg1;
227 }
228
229 #define T (env->sr & SR_T)
230 #define Q (env->sr & SR_Q ? 1 : 0)
231 #define M (env->sr & SR_M ? 1 : 0)
232 #define SETT env->sr |= SR_T
233 #define CLRT env->sr &= ~SR_T
234 #define SETQ env->sr |= SR_Q
235 #define CLRQ env->sr &= ~SR_Q
236 #define SETM env->sr |= SR_M
237 #define CLRM env->sr &= ~SR_M
238
239 uint32_t helper_div1(uint32_t arg0, uint32_t arg1)
240 {
241     uint32_t tmp0, tmp2;
242     uint8_t old_q, tmp1 = 0xff;
243
244     //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
245     old_q = Q;
246     if ((0x80000000 & arg1) != 0)
247         SETQ;
248     else
249         CLRQ;
250     tmp2 = arg0;
251     arg1 <<= 1;
252     arg1 |= T;
253     switch (old_q) {
254     case 0:
255         switch (M) {
256         case 0:
257             tmp0 = arg1;
258             arg1 -= tmp2;
259             tmp1 = arg1 > tmp0;
260             switch (Q) {
261             case 0:
262                 if (tmp1)
263                     SETQ;
264                 else
265                     CLRQ;
266                 break;
267             case 1:
268                 if (tmp1 == 0)
269                     SETQ;
270                 else
271                     CLRQ;
272                 break;
273             }
274             break;
275         case 1:
276             tmp0 = arg1;
277             arg1 += tmp2;
278             tmp1 = arg1 < tmp0;
279             switch (Q) {
280             case 0:
281                 if (tmp1 == 0)
282                     SETQ;
283                 else
284                     CLRQ;
285                 break;
286             case 1:
287                 if (tmp1)
288                     SETQ;
289                 else
290                     CLRQ;
291                 break;
292             }
293             break;
294         }
295         break;
296     case 1:
297         switch (M) {
298         case 0:
299             tmp0 = arg1;
300             arg1 += tmp2;
301             tmp1 = arg1 < tmp0;
302             switch (Q) {
303             case 0:
304                 if (tmp1)
305                     SETQ;
306                 else
307                     CLRQ;
308                 break;
309             case 1:
310                 if (tmp1 == 0)
311                     SETQ;
312                 else
313                     CLRQ;
314                 break;
315             }
316             break;
317         case 1:
318             tmp0 = arg1;
319             arg1 -= tmp2;
320             tmp1 = arg1 > tmp0;
321             switch (Q) {
322             case 0:
323                 if (tmp1 == 0)
324                     SETQ;
325                 else
326                     CLRQ;
327                 break;
328             case 1:
329                 if (tmp1)
330                     SETQ;
331                 else
332                     CLRQ;
333                 break;
334             }
335             break;
336         }
337         break;
338     }
339     if (Q == M)
340         SETT;
341     else
342         CLRT;
343     //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
344     return arg1;
345 }
346
347 void helper_macl(uint32_t arg0, uint32_t arg1)
348 {
349     int64_t res;
350
351     res = ((uint64_t) env->mach << 32) | env->macl;
352     res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
353     env->mach = (res >> 32) & 0xffffffff;
354     env->macl = res & 0xffffffff;
355     if (env->sr & SR_S) {
356         if (res < 0)
357             env->mach |= 0xffff0000;
358         else
359             env->mach &= 0x00007fff;
360     }
361 }
362
363 void helper_macw(uint32_t arg0, uint32_t arg1)
364 {
365     int64_t res;
366
367     res = ((uint64_t) env->mach << 32) | env->macl;
368     res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
369     env->mach = (res >> 32) & 0xffffffff;
370     env->macl = res & 0xffffffff;
371     if (env->sr & SR_S) {
372         if (res < -0x80000000) {
373             env->mach = 1;
374             env->macl = 0x80000000;
375         } else if (res > 0x000000007fffffff) {
376             env->mach = 1;
377             env->macl = 0x7fffffff;
378         }
379     }
380 }
381
382 uint32_t helper_subc(uint32_t arg0, uint32_t arg1)
383 {
384     uint32_t tmp0, tmp1;
385
386     tmp1 = arg1 - arg0;
387     tmp0 = arg1;
388     arg1 = tmp1 - (env->sr & SR_T);
389     if (tmp0 < tmp1)
390         env->sr |= SR_T;
391     else
392         env->sr &= ~SR_T;
393     if (tmp1 < arg1)
394         env->sr |= SR_T;
395     return arg1;
396 }
397
398 uint32_t helper_subv(uint32_t arg0, uint32_t arg1)
399 {
400     int32_t dest, src, ans;
401
402     if ((int32_t) arg1 >= 0)
403         dest = 0;
404     else
405         dest = 1;
406     if ((int32_t) arg0 >= 0)
407         src = 0;
408     else
409         src = 1;
410     src += dest;
411     arg1 -= arg0;
412     if ((int32_t) arg1 >= 0)
413         ans = 0;
414     else
415         ans = 1;
416     ans += dest;
417     if (src == 1) {
418         if (ans == 1)
419             env->sr |= SR_T;
420         else
421             env->sr &= ~SR_T;
422     } else
423         env->sr &= ~SR_T;
424     return arg1;
425 }
426
427 static inline void set_t(void)
428 {
429     env->sr |= SR_T;
430 }
431
432 static inline void clr_t(void)
433 {
434     env->sr &= ~SR_T;
435 }
436
437 void helper_ld_fpscr(uint32_t val)
438 {
439     env->fpscr = val & FPSCR_MASK;
440     if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
441         set_float_rounding_mode(float_round_to_zero, &env->fp_status);
442     } else {
443         set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
444     }
445     set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
446 }
447
448 static void update_fpscr(uintptr_t retaddr)
449 {
450     int xcpt, cause, enable;
451
452     xcpt = get_float_exception_flags(&env->fp_status);
453
454     /* Clear the flag entries */
455     env->fpscr &= ~FPSCR_FLAG_MASK;
456
457     if (unlikely(xcpt)) {
458         if (xcpt & float_flag_invalid) {
459             env->fpscr |= FPSCR_FLAG_V;
460         }
461         if (xcpt & float_flag_divbyzero) {
462             env->fpscr |= FPSCR_FLAG_Z;
463         }
464         if (xcpt & float_flag_overflow) {
465             env->fpscr |= FPSCR_FLAG_O;
466         }
467         if (xcpt & float_flag_underflow) {
468             env->fpscr |= FPSCR_FLAG_U;
469         }
470         if (xcpt & float_flag_inexact) {
471             env->fpscr |= FPSCR_FLAG_I;
472         }
473
474         /* Accumulate in cause entries */
475         env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
476                       << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
477
478         /* Generate an exception if enabled */
479         cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
480         enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
481         if (cause & enable) {
482             cpu_restore_state_from_retaddr(retaddr);
483             env->exception_index = 0x120;
484             cpu_loop_exit(env);
485         }
486     }
487 }
488
489 float32 helper_fabs_FT(float32 t0)
490 {
491     return float32_abs(t0);
492 }
493
494 float64 helper_fabs_DT(float64 t0)
495 {
496     return float64_abs(t0);
497 }
498
499 float32 helper_fadd_FT(float32 t0, float32 t1)
500 {
501     set_float_exception_flags(0, &env->fp_status);
502     t0 = float32_add(t0, t1, &env->fp_status);
503     update_fpscr(GETPC());
504     return t0;
505 }
506
507 float64 helper_fadd_DT(float64 t0, float64 t1)
508 {
509     set_float_exception_flags(0, &env->fp_status);
510     t0 = float64_add(t0, t1, &env->fp_status);
511     update_fpscr(GETPC());
512     return t0;
513 }
514
515 void helper_fcmp_eq_FT(float32 t0, float32 t1)
516 {
517     int relation;
518
519     set_float_exception_flags(0, &env->fp_status);
520     relation = float32_compare(t0, t1, &env->fp_status);
521     if (unlikely(relation == float_relation_unordered)) {
522         update_fpscr(GETPC());
523     } else if (relation == float_relation_equal) {
524         set_t();
525     } else {
526         clr_t();
527     }
528 }
529
530 void helper_fcmp_eq_DT(float64 t0, float64 t1)
531 {
532     int relation;
533
534     set_float_exception_flags(0, &env->fp_status);
535     relation = float64_compare(t0, t1, &env->fp_status);
536     if (unlikely(relation == float_relation_unordered)) {
537         update_fpscr(GETPC());
538     } else if (relation == float_relation_equal) {
539         set_t();
540     } else {
541         clr_t();
542     }
543 }
544
545 void helper_fcmp_gt_FT(float32 t0, float32 t1)
546 {
547     int relation;
548
549     set_float_exception_flags(0, &env->fp_status);
550     relation = float32_compare(t0, t1, &env->fp_status);
551     if (unlikely(relation == float_relation_unordered)) {
552         update_fpscr(GETPC());
553     } else if (relation == float_relation_greater) {
554         set_t();
555     } else {
556         clr_t();
557     }
558 }
559
560 void helper_fcmp_gt_DT(float64 t0, float64 t1)
561 {
562     int relation;
563
564     set_float_exception_flags(0, &env->fp_status);
565     relation = float64_compare(t0, t1, &env->fp_status);
566     if (unlikely(relation == float_relation_unordered)) {
567         update_fpscr(GETPC());
568     } else if (relation == float_relation_greater) {
569         set_t();
570     } else {
571         clr_t();
572     }
573 }
574
575 float64 helper_fcnvsd_FT_DT(float32 t0)
576 {
577     float64 ret;
578     set_float_exception_flags(0, &env->fp_status);
579     ret = float32_to_float64(t0, &env->fp_status);
580     update_fpscr(GETPC());
581     return ret;
582 }
583
584 float32 helper_fcnvds_DT_FT(float64 t0)
585 {
586     float32 ret;
587     set_float_exception_flags(0, &env->fp_status);
588     ret = float64_to_float32(t0, &env->fp_status);
589     update_fpscr(GETPC());
590     return ret;
591 }
592
593 float32 helper_fdiv_FT(float32 t0, float32 t1)
594 {
595     set_float_exception_flags(0, &env->fp_status);
596     t0 = float32_div(t0, t1, &env->fp_status);
597     update_fpscr(GETPC());
598     return t0;
599 }
600
601 float64 helper_fdiv_DT(float64 t0, float64 t1)
602 {
603     set_float_exception_flags(0, &env->fp_status);
604     t0 = float64_div(t0, t1, &env->fp_status);
605     update_fpscr(GETPC());
606     return t0;
607 }
608
609 float32 helper_float_FT(uint32_t t0)
610 {
611     float32 ret;
612     set_float_exception_flags(0, &env->fp_status);
613     ret = int32_to_float32(t0, &env->fp_status);
614     update_fpscr(GETPC());
615     return ret;
616 }
617
618 float64 helper_float_DT(uint32_t t0)
619 {
620     float64 ret;
621     set_float_exception_flags(0, &env->fp_status);
622     ret = int32_to_float64(t0, &env->fp_status);
623     update_fpscr(GETPC());
624     return ret;
625 }
626
627 float32 helper_fmac_FT(float32 t0, float32 t1, float32 t2)
628 {
629     set_float_exception_flags(0, &env->fp_status);
630     t0 = float32_mul(t0, t1, &env->fp_status);
631     t0 = float32_add(t0, t2, &env->fp_status);
632     update_fpscr(GETPC());
633     return t0;
634 }
635
636 float32 helper_fmul_FT(float32 t0, float32 t1)
637 {
638     set_float_exception_flags(0, &env->fp_status);
639     t0 = float32_mul(t0, t1, &env->fp_status);
640     update_fpscr(GETPC());
641     return t0;
642 }
643
644 float64 helper_fmul_DT(float64 t0, float64 t1)
645 {
646     set_float_exception_flags(0, &env->fp_status);
647     t0 = float64_mul(t0, t1, &env->fp_status);
648     update_fpscr(GETPC());
649     return t0;
650 }
651
652 float32 helper_fneg_T(float32 t0)
653 {
654     return float32_chs(t0);
655 }
656
657 float32 helper_fsqrt_FT(float32 t0)
658 {
659     set_float_exception_flags(0, &env->fp_status);
660     t0 = float32_sqrt(t0, &env->fp_status);
661     update_fpscr(GETPC());
662     return t0;
663 }
664
665 float64 helper_fsqrt_DT(float64 t0)
666 {
667     set_float_exception_flags(0, &env->fp_status);
668     t0 = float64_sqrt(t0, &env->fp_status);
669     update_fpscr(GETPC());
670     return t0;
671 }
672
673 float32 helper_fsub_FT(float32 t0, float32 t1)
674 {
675     set_float_exception_flags(0, &env->fp_status);
676     t0 = float32_sub(t0, t1, &env->fp_status);
677     update_fpscr(GETPC());
678     return t0;
679 }
680
681 float64 helper_fsub_DT(float64 t0, float64 t1)
682 {
683     set_float_exception_flags(0, &env->fp_status);
684     t0 = float64_sub(t0, t1, &env->fp_status);
685     update_fpscr(GETPC());
686     return t0;
687 }
688
689 uint32_t helper_ftrc_FT(float32 t0)
690 {
691     uint32_t ret;
692     set_float_exception_flags(0, &env->fp_status);
693     ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
694     update_fpscr(GETPC());
695     return ret;
696 }
697
698 uint32_t helper_ftrc_DT(float64 t0)
699 {
700     uint32_t ret;
701     set_float_exception_flags(0, &env->fp_status);
702     ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
703     update_fpscr(GETPC());
704     return ret;
705 }
706
707 void helper_fipr(uint32_t m, uint32_t n)
708 {
709     int bank, i;
710     float32 r, p;
711
712     bank = (env->sr & FPSCR_FR) ? 16 : 0;
713     r = float32_zero;
714     set_float_exception_flags(0, &env->fp_status);
715
716     for (i = 0 ; i < 4 ; i++) {
717         p = float32_mul(env->fregs[bank + m + i],
718                         env->fregs[bank + n + i],
719                         &env->fp_status);
720         r = float32_add(r, p, &env->fp_status);
721     }
722     update_fpscr(GETPC());
723
724     env->fregs[bank + n + 3] = r;
725 }
726
727 void helper_ftrv(uint32_t n)
728 {
729     int bank_matrix, bank_vector;
730     int i, j;
731     float32 r[4];
732     float32 p;
733
734     bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
735     bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
736     set_float_exception_flags(0, &env->fp_status);
737     for (i = 0 ; i < 4 ; i++) {
738         r[i] = float32_zero;
739         for (j = 0 ; j < 4 ; j++) {
740             p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
741                             env->fregs[bank_vector + j],
742                             &env->fp_status);
743             r[i] = float32_add(r[i], p, &env->fp_status);
744         }
745     }
746     update_fpscr(GETPC());
747
748     for (i = 0 ; i < 4 ; i++) {
749         env->fregs[bank_vector + i] = r[i];
750     }
751 }