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