e5a4cb7a00f352eed54feb3a26bad4960668e932
[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     float32 ret = float32_abs(*(float32*)&t0);
393     return *(uint32_t*)(&ret);
394 }
395
396 uint64_t helper_fabs_DT(uint64_t t0)
397 {
398     float64 ret = float64_abs(*(float64*)&t0);
399     return *(uint64_t*)(&ret);
400 }
401
402 uint32_t helper_fadd_FT(uint32_t t0, uint32_t t1)
403 {
404     float32 ret = float32_add(*(float32*)&t0, *(float32*)&t1, &env->fp_status);
405     return *(uint32_t*)(&ret);
406 }
407
408 uint64_t helper_fadd_DT(uint64_t t0, uint64_t t1)
409 {
410     float64 ret = float64_add(*(float64*)&t0, *(float64*)&t1, &env->fp_status);
411     return *(uint64_t*)(&ret);
412 }
413
414 void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1)
415 {
416     if (float32_compare(*(float32*)&t0, *(float32*)&t1, &env->fp_status) == 0)
417         set_t();
418     else
419         clr_t();
420 }
421
422 void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1)
423 {
424     if (float64_compare(*(float64*)&t0, *(float64*)&t1, &env->fp_status) == 0)
425         set_t();
426     else
427         clr_t();
428 }
429
430 void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1)
431 {
432     if (float32_compare(*(float32*)&t0, *(float32*)&t1, &env->fp_status) == 1)
433         set_t();
434     else
435         clr_t();
436 }
437
438 void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1)
439 {
440     if (float64_compare(*(float64*)&t0, *(float64*)&t1, &env->fp_status) == 1)
441         set_t();
442     else
443         clr_t();
444 }
445
446 uint64_t helper_fcnvsd_FT_DT(uint32_t t0)
447 {
448     float64 ret = float32_to_float64(*(float32*)&t0, &env->fp_status);
449     return *(uint64_t*)(&ret);
450 }
451
452 uint32_t helper_fcnvds_DT_FT(uint64_t t0)
453 {
454     float32 ret = float64_to_float32(*(float64*)&t0, &env->fp_status);
455     return *(uint32_t*)(&ret);
456 }
457
458 uint32_t helper_fdiv_FT(uint32_t t0, uint32_t t1)
459 {
460     float32 ret = float32_div(*(float32*)&t0, *(float32*)&t1, &env->fp_status);
461     return *(uint32_t*)(&ret);
462 }
463
464 uint64_t helper_fdiv_DT(uint64_t t0, uint64_t t1)
465 {
466     float64 ret = float64_div(*(float64*)&t0, *(float64*)&t1, &env->fp_status);
467     return *(uint64_t*)(&ret);
468 }
469
470 uint32_t helper_float_FT(uint32_t t0)
471 {
472     float32 ret = int32_to_float32(t0, &env->fp_status);
473     return *(uint32_t*)(&ret);
474 }
475
476 uint64_t helper_float_DT(uint32_t t0)
477 {
478     float64 ret = int32_to_float64(t0, &env->fp_status);
479     return *(uint64_t*)(&ret);
480 }
481
482 uint32_t helper_fmul_FT(uint32_t t0, uint32_t t1)
483 {
484     float32 ret = float32_mul(*(float32*)&t0, *(float32*)&t1, &env->fp_status);
485     return *(uint32_t*)(&ret);
486 }
487
488 uint64_t helper_fmul_DT(uint64_t t0, uint64_t t1)
489 {
490     float64 ret = float64_mul(*(float64*)&t0, *(float64*)&t1, &env->fp_status);
491     return *(uint64_t*)(&ret);
492 }
493
494 uint32_t helper_fneg_T(uint32_t t0)
495 {
496     float32 ret = float32_chs(*(float32*)&t0);
497     return *(uint32_t*)(&ret);
498 }
499
500 uint32_t helper_fsqrt_FT(uint32_t t0)
501 {
502     float32 ret = float32_sqrt(*(float32*)&t0, &env->fp_status);
503     return *(uint32_t*)(&ret);
504 }
505
506 uint64_t helper_fsqrt_DT(uint64_t t0)
507 {
508     float64 ret = float64_sqrt(*(float64*)&t0, &env->fp_status);
509     return *(uint64_t*)(&ret);
510 }
511
512 uint32_t helper_fsub_FT(uint32_t t0, uint32_t t1)
513 {
514     float32 ret = float32_sub(*(float32*)&t0, *(float32*)&t1, &env->fp_status);
515     return *(uint32_t*)(&ret);
516 }
517
518 uint64_t helper_fsub_DT(uint64_t t0, uint64_t t1)
519 {
520     float64 ret = float64_sub(*(float64*)&t0, *(float64*)&t1, &env->fp_status);
521     return *(uint64_t*)(&ret);
522 }
523
524 uint32_t helper_ftrc_FT(uint32_t t0)
525 {
526     return float32_to_int32_round_to_zero(*(float32*)&t0, &env->fp_status);
527 }
528
529 uint32_t helper_ftrc_DT(uint64_t t0)
530 {
531     return float64_to_int32_round_to_zero(*(float64*)&t0, &env->fp_status);
532 }