target-sh4: fix fldi0/fldi1
[qemu] / 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <assert.h>
21 #include "exec.h"
22 #include "helper.h"
23
24 #ifndef CONFIG_USER_ONLY
25
26 #define MMUSUFFIX _mmu
27
28 #define SHIFT 0
29 #include "softmmu_template.h"
30
31 #define SHIFT 1
32 #include "softmmu_template.h"
33
34 #define SHIFT 2
35 #include "softmmu_template.h"
36
37 #define SHIFT 3
38 #include "softmmu_template.h"
39
40 void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
41 {
42     TranslationBlock *tb;
43     CPUState *saved_env;
44     unsigned long pc;
45     int ret;
46
47     /* XXX: hack to restore env in all cases, even if not called from
48        generated code */
49     saved_env = env;
50     env = cpu_single_env;
51     ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
52     if (ret) {
53         if (retaddr) {
54             /* now we have a real cpu fault */
55             pc = (unsigned long) retaddr;
56             tb = tb_find_pc(pc);
57             if (tb) {
58                 /* the PC is inside the translated code. It means that we have
59                    a virtual CPU fault */
60                 cpu_restore_state(tb, env, pc, NULL);
61             }
62         }
63         cpu_loop_exit();
64     }
65     env = saved_env;
66 }
67
68 #endif
69
70 void helper_ldtlb(void)
71 {
72 #ifdef CONFIG_USER_ONLY
73     /* XXXXX */
74     assert(0);
75 #else
76     cpu_load_tlb(env);
77 #endif
78 }
79
80 void helper_raise_illegal_instruction(void)
81 {
82     env->exception_index = 0x180;
83     cpu_loop_exit();
84 }
85
86 void helper_raise_slot_illegal_instruction(void)
87 {
88     env->exception_index = 0x1a0;
89     cpu_loop_exit();
90 }
91
92 void helper_debug(void)
93 {
94     env->exception_index = EXCP_DEBUG;
95     cpu_loop_exit();
96 }
97
98 void helper_sleep(uint32_t next_pc)
99 {
100     env->halted = 1;
101     env->exception_index = EXCP_HLT;
102     env->pc = next_pc;
103     cpu_loop_exit();
104 }
105
106 void helper_trapa(uint32_t tra)
107 {
108     env->tra = tra << 2;
109     env->exception_index = 0x160;
110     cpu_loop_exit();
111 }
112
113 uint32_t helper_addc(uint32_t arg0, uint32_t arg1)
114 {
115     uint32_t tmp0, tmp1;
116
117     tmp1 = arg0 + arg1;
118     tmp0 = arg1;
119     arg1 = tmp1 + (env->sr & 1);
120     if (tmp0 > tmp1)
121         env->sr |= SR_T;
122     else
123         env->sr &= ~SR_T;
124     if (tmp1 > arg1)
125         env->sr |= SR_T;
126     return arg1;
127 }
128
129 uint32_t helper_addv(uint32_t arg0, uint32_t arg1)
130 {
131     uint32_t dest, src, ans;
132
133     if ((int32_t) arg1 >= 0)
134         dest = 0;
135     else
136         dest = 1;
137     if ((int32_t) arg0 >= 0)
138         src = 0;
139     else
140         src = 1;
141     src += dest;
142     arg1 += arg0;
143     if ((int32_t) arg1 >= 0)
144         ans = 0;
145     else
146         ans = 1;
147     ans += dest;
148     if (src == 0 || src == 2) {
149         if (ans == 1)
150             env->sr |= SR_T;
151         else
152             env->sr &= ~SR_T;
153     } else
154         env->sr &= ~SR_T;
155     return arg1;
156 }
157
158 #define T (env->sr & SR_T)
159 #define Q (env->sr & SR_Q ? 1 : 0)
160 #define M (env->sr & SR_M ? 1 : 0)
161 #define SETT env->sr |= SR_T
162 #define CLRT env->sr &= ~SR_T
163 #define SETQ env->sr |= SR_Q
164 #define CLRQ env->sr &= ~SR_Q
165 #define SETM env->sr |= SR_M
166 #define CLRM env->sr &= ~SR_M
167
168 uint32_t helper_div1(uint32_t arg0, uint32_t arg1)
169 {
170     uint32_t tmp0, tmp2;
171     uint8_t old_q, tmp1 = 0xff;
172
173     //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
174     old_q = Q;
175     if ((0x80000000 & arg1) != 0)
176         SETQ;
177     else
178         CLRQ;
179     tmp2 = arg0;
180     arg1 <<= 1;
181     arg1 |= T;
182     switch (old_q) {
183     case 0:
184         switch (M) {
185         case 0:
186             tmp0 = arg1;
187             arg1 -= tmp2;
188             tmp1 = arg1 > tmp0;
189             switch (Q) {
190             case 0:
191                 if (tmp1)
192                     SETQ;
193                 else
194                     CLRQ;
195                 break;
196             case 1:
197                 if (tmp1 == 0)
198                     SETQ;
199                 else
200                     CLRQ;
201                 break;
202             }
203             break;
204         case 1:
205             tmp0 = arg1;
206             arg1 += tmp2;
207             tmp1 = arg1 < tmp0;
208             switch (Q) {
209             case 0:
210                 if (tmp1 == 0)
211                     SETQ;
212                 else
213                     CLRQ;
214                 break;
215             case 1:
216                 if (tmp1)
217                     SETQ;
218                 else
219                     CLRQ;
220                 break;
221             }
222             break;
223         }
224         break;
225     case 1:
226         switch (M) {
227         case 0:
228             tmp0 = arg1;
229             arg1 += tmp2;
230             tmp1 = arg1 < tmp0;
231             switch (Q) {
232             case 0:
233                 if (tmp1)
234                     SETQ;
235                 else
236                     CLRQ;
237                 break;
238             case 1:
239                 if (tmp1 == 0)
240                     SETQ;
241                 else
242                     CLRQ;
243                 break;
244             }
245             break;
246         case 1:
247             tmp0 = arg1;
248             arg1 -= tmp2;
249             tmp1 = arg1 > tmp0;
250             switch (Q) {
251             case 0:
252                 if (tmp1 == 0)
253                     SETQ;
254                 else
255                     CLRQ;
256                 break;
257             case 1:
258                 if (tmp1)
259                     SETQ;
260                 else
261                     CLRQ;
262                 break;
263             }
264             break;
265         }
266         break;
267     }
268     if (Q == M)
269         SETT;
270     else
271         CLRT;
272     //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
273     return arg1;
274 }
275
276 void helper_macl(uint32_t arg0, uint32_t arg1)
277 {
278     int64_t res;
279
280     res = ((uint64_t) env->mach << 32) | env->macl;
281     res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
282     env->mach = (res >> 32) & 0xffffffff;
283     env->macl = res & 0xffffffff;
284     if (env->sr & SR_S) {
285         if (res < 0)
286             env->mach |= 0xffff0000;
287         else
288             env->mach &= 0x00007fff;
289     }
290 }
291
292 void helper_macw(uint32_t arg0, uint32_t arg1)
293 {
294     int64_t res;
295
296     res = ((uint64_t) env->mach << 32) | env->macl;
297     res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
298     env->mach = (res >> 32) & 0xffffffff;
299     env->macl = res & 0xffffffff;
300     if (env->sr & SR_S) {
301         if (res < -0x80000000) {
302             env->mach = 1;
303             env->macl = 0x80000000;
304         } else if (res > 0x000000007fffffff) {
305             env->mach = 1;
306             env->macl = 0x7fffffff;
307         }
308     }
309 }
310
311 uint32_t helper_negc(uint32_t arg)
312 {
313     uint32_t temp;
314
315     temp = -arg;
316     arg = temp - (env->sr & SR_T);
317     if (0 < temp)
318         env->sr |= SR_T;
319     else
320         env->sr &= ~SR_T;
321     if (temp < arg)
322         env->sr |= SR_T;
323     return arg;
324 }
325
326 uint32_t helper_subc(uint32_t arg0, uint32_t arg1)
327 {
328     uint32_t tmp0, tmp1;
329
330     tmp1 = arg1 - arg0;
331     tmp0 = arg1;
332     arg1 = tmp1 - (env->sr & SR_T);
333     if (tmp0 < tmp1)
334         env->sr |= SR_T;
335     else
336         env->sr &= ~SR_T;
337     if (tmp1 < arg1)
338         env->sr |= SR_T;
339     return arg1;
340 }
341
342 uint32_t helper_subv(uint32_t arg0, uint32_t arg1)
343 {
344     int32_t dest, src, ans;
345
346     if ((int32_t) arg1 >= 0)
347         dest = 0;
348     else
349         dest = 1;
350     if ((int32_t) arg0 >= 0)
351         src = 0;
352     else
353         src = 1;
354     src += dest;
355     arg1 -= arg0;
356     if ((int32_t) arg1 >= 0)
357         ans = 0;
358     else
359         ans = 1;
360     ans += dest;
361     if (src == 1) {
362         if (ans == 1)
363             env->sr |= SR_T;
364         else
365             env->sr &= ~SR_T;
366     } else
367         env->sr &= ~SR_T;
368     return arg1;
369 }
370
371 static inline void set_t(void)
372 {
373     env->sr |= SR_T;
374 }
375
376 static inline void clr_t(void)
377 {
378     env->sr &= ~SR_T;
379 }
380
381 void helper_ld_fpscr(uint32_t val)
382 {
383     env->fpscr = val & 0x003fffff;
384     if (val & 0x01)
385         set_float_rounding_mode(float_round_to_zero, &env->fp_status);
386     else
387         set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
388 }
389
390 uint32_t helper_fabs_FT(uint32_t t0)
391 {
392     CPU_FloatU f;
393     f.l = t0;
394     f.f = float32_abs(f.f);
395     return f.l;
396 }
397
398 uint64_t helper_fabs_DT(uint64_t t0)
399 {
400     CPU_DoubleU d;
401     d.ll = t0;
402     d.d = float64_abs(d.d);
403     return d.ll;
404 }
405
406 uint32_t helper_fadd_FT(uint32_t t0, uint32_t t1)
407 {
408     CPU_FloatU f0, f1;
409     f0.l = t0;
410     f1.l = t1;
411     f0.f = float32_add(f0.f, f1.f, &env->fp_status);
412     return f0.l;
413 }
414
415 uint64_t helper_fadd_DT(uint64_t t0, uint64_t t1)
416 {
417     CPU_DoubleU d0, d1;
418     d0.ll = t0;
419     d1.ll = t1;
420     d0.d = float64_add(d0.d, d1.d, &env->fp_status);
421     return d0.ll;
422 }
423
424 void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1)
425 {
426     CPU_FloatU f0, f1;
427     f0.l = t0;
428     f1.l = t1;
429
430     if (float32_compare(f0.f, f1.f, &env->fp_status) == 0)
431         set_t();
432     else
433         clr_t();
434 }
435
436 void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1)
437 {
438     CPU_DoubleU d0, d1;
439     d0.ll = t0;
440     d1.ll = t1;
441
442     if (float64_compare(d0.d, d1.d, &env->fp_status) == 0)
443         set_t();
444     else
445         clr_t();
446 }
447
448 void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1)
449 {
450     CPU_FloatU f0, f1;
451     f0.l = t0;
452     f1.l = t1;
453
454     if (float32_compare(f0.f, f1.f, &env->fp_status) == 1)
455         set_t();
456     else
457         clr_t();
458 }
459
460 void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1)
461 {
462     CPU_DoubleU d0, d1;
463     d0.ll = t0;
464     d1.ll = t1;
465
466     if (float64_compare(d0.d, d1.d, &env->fp_status) == 1)
467         set_t();
468     else
469         clr_t();
470 }
471
472 uint64_t helper_fcnvsd_FT_DT(uint32_t t0)
473 {
474     CPU_DoubleU d;
475     CPU_FloatU f;
476     f.l = t0;
477     d.d = float32_to_float64(f.f, &env->fp_status);
478     return d.ll;
479 }
480
481 uint32_t helper_fcnvds_DT_FT(uint64_t t0)
482 {
483     CPU_DoubleU d;
484     CPU_FloatU f;
485     d.ll = t0;
486     f.f = float64_to_float32(d.d, &env->fp_status);
487     return f.l;
488 }
489
490 uint32_t helper_fdiv_FT(uint32_t t0, uint32_t t1)
491 {
492     CPU_FloatU f0, f1;
493     f0.l = t0;
494     f1.l = t1;
495     f0.f = float32_div(f0.f, f1.f, &env->fp_status);
496     return f0.l;
497 }
498
499 uint64_t helper_fdiv_DT(uint64_t t0, uint64_t t1)
500 {
501     CPU_DoubleU d0, d1;
502     d0.ll = t0;
503     d1.ll = t1;
504     d0.d = float64_div(d0.d, d1.d, &env->fp_status);
505     return d0.ll;
506 }
507
508 uint32_t helper_float_FT(uint32_t t0)
509 {
510     CPU_FloatU f;
511     f.f = int32_to_float32(t0, &env->fp_status);
512     return f.l;
513 }
514
515 uint64_t helper_float_DT(uint32_t t0)
516 {
517     CPU_DoubleU d;
518     d.d = int32_to_float64(t0, &env->fp_status);
519     return d.ll;
520 }
521
522 uint32_t helper_fmul_FT(uint32_t t0, uint32_t t1)
523 {
524     CPU_FloatU f0, f1;
525     f0.l = t0;
526     f1.l = t1;
527     f0.f = float32_mul(f0.f, f1.f, &env->fp_status);
528     return f0.l;
529 }
530
531 uint64_t helper_fmul_DT(uint64_t t0, uint64_t t1)
532 {
533     CPU_DoubleU d0, d1;
534     d0.ll = t0;
535     d1.ll = t1;
536     d0.d = float64_mul(d0.d, d1.d, &env->fp_status);
537     return d0.ll;
538 }
539
540 uint32_t helper_fneg_T(uint32_t t0)
541 {
542     CPU_FloatU f;
543     f.l = t0;
544     f.f = float32_chs(f.f);
545     return f.l;
546 }
547
548 uint32_t helper_fsqrt_FT(uint32_t t0)
549 {
550     CPU_FloatU f;
551     f.l = t0;
552     f.f = float32_sqrt(f.f, &env->fp_status);
553     return f.l;
554 }
555
556 uint64_t helper_fsqrt_DT(uint64_t t0)
557 {
558     CPU_DoubleU d;
559     d.ll = t0;
560     d.d = float64_sqrt(d.d, &env->fp_status);
561     return d.ll;
562 }
563
564 uint32_t helper_fsub_FT(uint32_t t0, uint32_t t1)
565 {
566     CPU_FloatU f0, f1;
567     f0.l = t0;
568     f1.l = t1;
569     f0.f = float32_sub(f0.f, f1.f, &env->fp_status);
570     return f0.l;
571 }
572
573 uint64_t helper_fsub_DT(uint64_t t0, uint64_t t1)
574 {
575     CPU_DoubleU d0, d1;
576     d0.ll = t0;
577     d1.ll = t1;
578     d0.d = float64_sub(d0.d, d1.d, &env->fp_status);
579     return d0.ll;
580 }
581
582 uint32_t helper_ftrc_FT(uint32_t t0)
583 {
584     CPU_FloatU f;
585     f.l = t0;
586     return float32_to_int32_round_to_zero(f.f, &env->fp_status);
587 }
588
589 uint32_t helper_ftrc_DT(uint64_t t0)
590 {
591     CPU_DoubleU d;
592     d.ll = t0;
593     return float64_to_int32_round_to_zero(d.d, &env->fp_status);
594 }