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