63522194f77dec85ad99f7b5aa59b8e6ff6e99d3
[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, 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_raise_fpu_disable(void)
93 {
94   env->exception_index = 0x800;
95   cpu_loop_exit();
96 }
97
98 void helper_raise_slot_fpu_disable(void)
99 {
100   env->exception_index = 0x820;
101   cpu_loop_exit();
102 }
103
104 void helper_debug(void)
105 {
106     env->exception_index = EXCP_DEBUG;
107     cpu_loop_exit();
108 }
109
110 void helper_sleep(uint32_t next_pc)
111 {
112     env->halted = 1;
113     env->exception_index = EXCP_HLT;
114     env->pc = next_pc;
115     cpu_loop_exit();
116 }
117
118 void helper_trapa(uint32_t tra)
119 {
120     env->tra = tra << 2;
121     env->exception_index = 0x160;
122     cpu_loop_exit();
123 }
124
125 uint32_t helper_addc(uint32_t arg0, uint32_t arg1)
126 {
127     uint32_t tmp0, tmp1;
128
129     tmp1 = arg0 + arg1;
130     tmp0 = arg1;
131     arg1 = tmp1 + (env->sr & 1);
132     if (tmp0 > tmp1)
133         env->sr |= SR_T;
134     else
135         env->sr &= ~SR_T;
136     if (tmp1 > arg1)
137         env->sr |= SR_T;
138     return arg1;
139 }
140
141 uint32_t helper_addv(uint32_t arg0, uint32_t arg1)
142 {
143     uint32_t dest, src, ans;
144
145     if ((int32_t) arg1 >= 0)
146         dest = 0;
147     else
148         dest = 1;
149     if ((int32_t) arg0 >= 0)
150         src = 0;
151     else
152         src = 1;
153     src += dest;
154     arg1 += arg0;
155     if ((int32_t) arg1 >= 0)
156         ans = 0;
157     else
158         ans = 1;
159     ans += dest;
160     if (src == 0 || src == 2) {
161         if (ans == 1)
162             env->sr |= SR_T;
163         else
164             env->sr &= ~SR_T;
165     } else
166         env->sr &= ~SR_T;
167     return arg1;
168 }
169
170 #define T (env->sr & SR_T)
171 #define Q (env->sr & SR_Q ? 1 : 0)
172 #define M (env->sr & SR_M ? 1 : 0)
173 #define SETT env->sr |= SR_T
174 #define CLRT env->sr &= ~SR_T
175 #define SETQ env->sr |= SR_Q
176 #define CLRQ env->sr &= ~SR_Q
177 #define SETM env->sr |= SR_M
178 #define CLRM env->sr &= ~SR_M
179
180 uint32_t helper_div1(uint32_t arg0, uint32_t arg1)
181 {
182     uint32_t tmp0, tmp2;
183     uint8_t old_q, tmp1 = 0xff;
184
185     //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
186     old_q = Q;
187     if ((0x80000000 & arg1) != 0)
188         SETQ;
189     else
190         CLRQ;
191     tmp2 = arg0;
192     arg1 <<= 1;
193     arg1 |= T;
194     switch (old_q) {
195     case 0:
196         switch (M) {
197         case 0:
198             tmp0 = arg1;
199             arg1 -= tmp2;
200             tmp1 = arg1 > tmp0;
201             switch (Q) {
202             case 0:
203                 if (tmp1)
204                     SETQ;
205                 else
206                     CLRQ;
207                 break;
208             case 1:
209                 if (tmp1 == 0)
210                     SETQ;
211                 else
212                     CLRQ;
213                 break;
214             }
215             break;
216         case 1:
217             tmp0 = arg1;
218             arg1 += tmp2;
219             tmp1 = arg1 < tmp0;
220             switch (Q) {
221             case 0:
222                 if (tmp1 == 0)
223                     SETQ;
224                 else
225                     CLRQ;
226                 break;
227             case 1:
228                 if (tmp1)
229                     SETQ;
230                 else
231                     CLRQ;
232                 break;
233             }
234             break;
235         }
236         break;
237     case 1:
238         switch (M) {
239         case 0:
240             tmp0 = arg1;
241             arg1 += tmp2;
242             tmp1 = arg1 < tmp0;
243             switch (Q) {
244             case 0:
245                 if (tmp1)
246                     SETQ;
247                 else
248                     CLRQ;
249                 break;
250             case 1:
251                 if (tmp1 == 0)
252                     SETQ;
253                 else
254                     CLRQ;
255                 break;
256             }
257             break;
258         case 1:
259             tmp0 = arg1;
260             arg1 -= tmp2;
261             tmp1 = arg1 > tmp0;
262             switch (Q) {
263             case 0:
264                 if (tmp1 == 0)
265                     SETQ;
266                 else
267                     CLRQ;
268                 break;
269             case 1:
270                 if (tmp1)
271                     SETQ;
272                 else
273                     CLRQ;
274                 break;
275             }
276             break;
277         }
278         break;
279     }
280     if (Q == M)
281         SETT;
282     else
283         CLRT;
284     //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
285     return arg1;
286 }
287
288 void helper_macl(uint32_t arg0, uint32_t arg1)
289 {
290     int64_t res;
291
292     res = ((uint64_t) env->mach << 32) | env->macl;
293     res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
294     env->mach = (res >> 32) & 0xffffffff;
295     env->macl = res & 0xffffffff;
296     if (env->sr & SR_S) {
297         if (res < 0)
298             env->mach |= 0xffff0000;
299         else
300             env->mach &= 0x00007fff;
301     }
302 }
303
304 void helper_macw(uint32_t arg0, uint32_t arg1)
305 {
306     int64_t res;
307
308     res = ((uint64_t) env->mach << 32) | env->macl;
309     res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
310     env->mach = (res >> 32) & 0xffffffff;
311     env->macl = res & 0xffffffff;
312     if (env->sr & SR_S) {
313         if (res < -0x80000000) {
314             env->mach = 1;
315             env->macl = 0x80000000;
316         } else if (res > 0x000000007fffffff) {
317             env->mach = 1;
318             env->macl = 0x7fffffff;
319         }
320     }
321 }
322
323 uint32_t helper_negc(uint32_t arg)
324 {
325     uint32_t temp;
326
327     temp = -arg;
328     arg = temp - (env->sr & SR_T);
329     if (0 < temp)
330         env->sr |= SR_T;
331     else
332         env->sr &= ~SR_T;
333     if (temp < arg)
334         env->sr |= SR_T;
335     return arg;
336 }
337
338 uint32_t helper_subc(uint32_t arg0, uint32_t arg1)
339 {
340     uint32_t tmp0, tmp1;
341
342     tmp1 = arg1 - arg0;
343     tmp0 = arg1;
344     arg1 = tmp1 - (env->sr & SR_T);
345     if (tmp0 < tmp1)
346         env->sr |= SR_T;
347     else
348         env->sr &= ~SR_T;
349     if (tmp1 < arg1)
350         env->sr |= SR_T;
351     return arg1;
352 }
353
354 uint32_t helper_subv(uint32_t arg0, uint32_t arg1)
355 {
356     int32_t dest, src, ans;
357
358     if ((int32_t) arg1 >= 0)
359         dest = 0;
360     else
361         dest = 1;
362     if ((int32_t) arg0 >= 0)
363         src = 0;
364     else
365         src = 1;
366     src += dest;
367     arg1 -= arg0;
368     if ((int32_t) arg1 >= 0)
369         ans = 0;
370     else
371         ans = 1;
372     ans += dest;
373     if (src == 1) {
374         if (ans == 1)
375             env->sr |= SR_T;
376         else
377             env->sr &= ~SR_T;
378     } else
379         env->sr &= ~SR_T;
380     return arg1;
381 }
382
383 static inline void set_t(void)
384 {
385     env->sr |= SR_T;
386 }
387
388 static inline void clr_t(void)
389 {
390     env->sr &= ~SR_T;
391 }
392
393 void helper_ld_fpscr(uint32_t val)
394 {
395     env->fpscr = val & 0x003fffff;
396     if (val & 0x01)
397         set_float_rounding_mode(float_round_to_zero, &env->fp_status);
398     else
399         set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
400 }
401
402 uint32_t helper_fabs_FT(uint32_t t0)
403 {
404     CPU_FloatU f;
405     f.l = t0;
406     f.f = float32_abs(f.f);
407     return f.l;
408 }
409
410 uint64_t helper_fabs_DT(uint64_t t0)
411 {
412     CPU_DoubleU d;
413     d.ll = t0;
414     d.d = float64_abs(d.d);
415     return d.ll;
416 }
417
418 uint32_t helper_fadd_FT(uint32_t t0, uint32_t t1)
419 {
420     CPU_FloatU f0, f1;
421     f0.l = t0;
422     f1.l = t1;
423     f0.f = float32_add(f0.f, f1.f, &env->fp_status);
424     return f0.l;
425 }
426
427 uint64_t helper_fadd_DT(uint64_t t0, uint64_t t1)
428 {
429     CPU_DoubleU d0, d1;
430     d0.ll = t0;
431     d1.ll = t1;
432     d0.d = float64_add(d0.d, d1.d, &env->fp_status);
433     return d0.ll;
434 }
435
436 void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1)
437 {
438     CPU_FloatU f0, f1;
439     f0.l = t0;
440     f1.l = t1;
441
442     if (float32_compare(f0.f, f1.f, &env->fp_status) == 0)
443         set_t();
444     else
445         clr_t();
446 }
447
448 void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1)
449 {
450     CPU_DoubleU d0, d1;
451     d0.ll = t0;
452     d1.ll = t1;
453
454     if (float64_compare(d0.d, d1.d, &env->fp_status) == 0)
455         set_t();
456     else
457         clr_t();
458 }
459
460 void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1)
461 {
462     CPU_FloatU f0, f1;
463     f0.l = t0;
464     f1.l = t1;
465
466     if (float32_compare(f0.f, f1.f, &env->fp_status) == 1)
467         set_t();
468     else
469         clr_t();
470 }
471
472 void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1)
473 {
474     CPU_DoubleU d0, d1;
475     d0.ll = t0;
476     d1.ll = t1;
477
478     if (float64_compare(d0.d, d1.d, &env->fp_status) == 1)
479         set_t();
480     else
481         clr_t();
482 }
483
484 uint64_t helper_fcnvsd_FT_DT(uint32_t t0)
485 {
486     CPU_DoubleU d;
487     CPU_FloatU f;
488     f.l = t0;
489     d.d = float32_to_float64(f.f, &env->fp_status);
490     return d.ll;
491 }
492
493 uint32_t helper_fcnvds_DT_FT(uint64_t t0)
494 {
495     CPU_DoubleU d;
496     CPU_FloatU f;
497     d.ll = t0;
498     f.f = float64_to_float32(d.d, &env->fp_status);
499     return f.l;
500 }
501
502 uint32_t helper_fdiv_FT(uint32_t t0, uint32_t t1)
503 {
504     CPU_FloatU f0, f1;
505     f0.l = t0;
506     f1.l = t1;
507     f0.f = float32_div(f0.f, f1.f, &env->fp_status);
508     return f0.l;
509 }
510
511 uint64_t helper_fdiv_DT(uint64_t t0, uint64_t t1)
512 {
513     CPU_DoubleU d0, d1;
514     d0.ll = t0;
515     d1.ll = t1;
516     d0.d = float64_div(d0.d, d1.d, &env->fp_status);
517     return d0.ll;
518 }
519
520 uint32_t helper_float_FT(uint32_t t0)
521 {
522     CPU_FloatU f;
523     f.f = int32_to_float32(t0, &env->fp_status);
524     return f.l;
525 }
526
527 uint64_t helper_float_DT(uint32_t t0)
528 {
529     CPU_DoubleU d;
530     d.d = int32_to_float64(t0, &env->fp_status);
531     return d.ll;
532 }
533
534 uint32_t helper_fmul_FT(uint32_t t0, uint32_t t1)
535 {
536     CPU_FloatU f0, f1;
537     f0.l = t0;
538     f1.l = t1;
539     f0.f = float32_mul(f0.f, f1.f, &env->fp_status);
540     return f0.l;
541 }
542
543 uint64_t helper_fmul_DT(uint64_t t0, uint64_t t1)
544 {
545     CPU_DoubleU d0, d1;
546     d0.ll = t0;
547     d1.ll = t1;
548     d0.d = float64_mul(d0.d, d1.d, &env->fp_status);
549     return d0.ll;
550 }
551
552 uint32_t helper_fneg_T(uint32_t t0)
553 {
554     CPU_FloatU f;
555     f.l = t0;
556     f.f = float32_chs(f.f);
557     return f.l;
558 }
559
560 uint32_t helper_fsqrt_FT(uint32_t t0)
561 {
562     CPU_FloatU f;
563     f.l = t0;
564     f.f = float32_sqrt(f.f, &env->fp_status);
565     return f.l;
566 }
567
568 uint64_t helper_fsqrt_DT(uint64_t t0)
569 {
570     CPU_DoubleU d;
571     d.ll = t0;
572     d.d = float64_sqrt(d.d, &env->fp_status);
573     return d.ll;
574 }
575
576 uint32_t helper_fsub_FT(uint32_t t0, uint32_t t1)
577 {
578     CPU_FloatU f0, f1;
579     f0.l = t0;
580     f1.l = t1;
581     f0.f = float32_sub(f0.f, f1.f, &env->fp_status);
582     return f0.l;
583 }
584
585 uint64_t helper_fsub_DT(uint64_t t0, uint64_t t1)
586 {
587     CPU_DoubleU d0, d1;
588     d0.ll = t0;
589     d1.ll = t1;
590     d0.d = float64_sub(d0.d, d1.d, &env->fp_status);
591     return d0.ll;
592 }
593
594 uint32_t helper_ftrc_FT(uint32_t t0)
595 {
596     CPU_FloatU f;
597     f.l = t0;
598     return float32_to_int32_round_to_zero(f.f, &env->fp_status);
599 }
600
601 uint32_t helper_ftrc_DT(uint64_t t0)
602 {
603     CPU_DoubleU d;
604     d.ll = t0;
605     return float64_to_int32_round_to_zero(d.d, &env->fp_status);
606 }