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