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