prep: qdev'ify Raven host bridge (PCIDevice)
[qemu/kevin.git] / target-sh4 / op_helper.c
blobb2995766510c01caed1a1d52caf1b93cb41539d0
1 /*
2 * SH4 emulation
4 * Copyright (c) 2005 Samuel Tardieu
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.
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.
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/>.
19 #include <assert.h>
20 #include <stdlib.h>
21 #include "cpu.h"
22 #include "dyngen-exec.h"
23 #include "helper.h"
25 static void cpu_restore_state_from_retaddr(void *retaddr)
27 TranslationBlock *tb;
28 unsigned long pc;
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);
41 #ifndef CONFIG_USER_ONLY
42 #include "softmmu_exec.h"
44 #define MMUSUFFIX _mmu
46 #define SHIFT 0
47 #include "softmmu_template.h"
49 #define SHIFT 1
50 #include "softmmu_template.h"
52 #define SHIFT 2
53 #include "softmmu_template.h"
55 #define SHIFT 3
56 #include "softmmu_template.h"
58 void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
59 void *retaddr)
61 CPUState *saved_env;
62 int ret;
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);
72 env = saved_env;
75 #endif
77 void helper_ldtlb(void)
79 #ifdef CONFIG_USER_ONLY
80 /* XXXXX */
81 cpu_abort(env, "Unhandled ldtlb");
82 #else
83 cpu_load_tlb(env);
84 #endif
87 static inline void raise_exception(int index, void *retaddr)
89 env->exception_index = index;
90 cpu_restore_state_from_retaddr(retaddr);
91 cpu_loop_exit(env);
94 void helper_raise_illegal_instruction(void)
96 raise_exception(0x180, GETPC());
99 void helper_raise_slot_illegal_instruction(void)
101 raise_exception(0x1a0, GETPC());
104 void helper_raise_fpu_disable(void)
106 raise_exception(0x800, GETPC());
109 void helper_raise_slot_fpu_disable(void)
111 raise_exception(0x820, GETPC());
114 void helper_debug(void)
116 env->exception_index = EXCP_DEBUG;
117 cpu_loop_exit(env);
120 void helper_sleep(uint32_t next_pc)
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);
129 void helper_trapa(uint32_t tra)
131 env->tra = tra << 2;
132 raise_exception(0x160, GETPC());
135 void helper_movcal(uint32_t address, uint32_t value)
137 if (cpu_sh4_is_cached (env, address))
139 memory_content *r = malloc (sizeof(memory_content));
140 r->address = address;
141 r->value = value;
142 r->next = NULL;
144 *(env->movcal_backup_tail) = r;
145 env->movcal_backup_tail = &(r->next);
149 void helper_discard_movcal_backup(void)
151 memory_content *current = env->movcal_backup;
153 while(current)
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);
163 void helper_ocbi(uint32_t address)
165 memory_content **current = &(env->movcal_backup);
166 while (*current)
168 uint32_t a = (*current)->address;
169 if ((a & ~0x1F) == (address & ~0x1F))
171 memory_content *next = (*current)->next;
172 stl(a, (*current)->value);
174 if (next == NULL)
176 env->movcal_backup_tail = current;
179 free (*current);
180 *current = next;
181 break;
186 uint32_t helper_addc(uint32_t arg0, uint32_t arg1)
188 uint32_t tmp0, tmp1;
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;
202 uint32_t helper_addv(uint32_t arg0, uint32_t arg1)
204 uint32_t dest, src, ans;
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;
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
241 uint32_t helper_div1(uint32_t arg0, uint32_t arg1)
243 uint32_t tmp0, tmp2;
244 uint8_t old_q, tmp1 = 0xff;
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;
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;
295 break;
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;
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;
337 break;
339 break;
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;
349 void helper_macl(uint32_t arg0, uint32_t arg1)
351 int64_t res;
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;
365 void helper_macw(uint32_t arg0, uint32_t arg1)
367 int64_t res;
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;
384 uint32_t helper_subc(uint32_t arg0, uint32_t arg1)
386 uint32_t tmp0, tmp1;
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;
400 uint32_t helper_subv(uint32_t arg0, uint32_t arg1)
402 int32_t dest, src, ans;
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;
429 static inline void set_t(void)
431 env->sr |= SR_T;
434 static inline void clr_t(void)
436 env->sr &= ~SR_T;
439 void helper_ld_fpscr(uint32_t val)
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);
447 set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
450 static void update_fpscr(void *retaddr)
452 int xcpt, cause, enable;
454 xcpt = get_float_exception_flags(&env->fp_status);
456 /* Clear the flag entries */
457 env->fpscr &= ~FPSCR_FLAG_MASK;
459 if (unlikely(xcpt)) {
460 if (xcpt & float_flag_invalid) {
461 env->fpscr |= FPSCR_FLAG_V;
463 if (xcpt & float_flag_divbyzero) {
464 env->fpscr |= FPSCR_FLAG_Z;
466 if (xcpt & float_flag_overflow) {
467 env->fpscr |= FPSCR_FLAG_O;
469 if (xcpt & float_flag_underflow) {
470 env->fpscr |= FPSCR_FLAG_U;
472 if (xcpt & float_flag_inexact) {
473 env->fpscr |= FPSCR_FLAG_I;
476 /* Accumulate in cause entries */
477 env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
478 << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
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);
491 float32 helper_fabs_FT(float32 t0)
493 return float32_abs(t0);
496 float64 helper_fabs_DT(float64 t0)
498 return float64_abs(t0);
501 float32 helper_fadd_FT(float32 t0, float32 t1)
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;
509 float64 helper_fadd_DT(float64 t0, float64 t1)
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;
517 void helper_fcmp_eq_FT(float32 t0, float32 t1)
519 int relation;
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();
532 void helper_fcmp_eq_DT(float64 t0, float64 t1)
534 int relation;
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();
547 void helper_fcmp_gt_FT(float32 t0, float32 t1)
549 int relation;
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();
562 void helper_fcmp_gt_DT(float64 t0, float64 t1)
564 int relation;
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();
577 float64 helper_fcnvsd_FT_DT(float32 t0)
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;
586 float32 helper_fcnvds_DT_FT(float64 t0)
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;
595 float32 helper_fdiv_FT(float32 t0, float32 t1)
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;
603 float64 helper_fdiv_DT(float64 t0, float64 t1)
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;
611 float32 helper_float_FT(uint32_t t0)
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;
620 float64 helper_float_DT(uint32_t t0)
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;
629 float32 helper_fmac_FT(float32 t0, float32 t1, float32 t2)
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;
638 float32 helper_fmul_FT(float32 t0, float32 t1)
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;
646 float64 helper_fmul_DT(float64 t0, float64 t1)
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;
654 float32 helper_fneg_T(float32 t0)
656 return float32_chs(t0);
659 float32 helper_fsqrt_FT(float32 t0)
661 set_float_exception_flags(0, &env->fp_status);
662 t0 = float32_sqrt(t0, &env->fp_status);
663 update_fpscr(GETPC());
664 return t0;
667 float64 helper_fsqrt_DT(float64 t0)
669 set_float_exception_flags(0, &env->fp_status);
670 t0 = float64_sqrt(t0, &env->fp_status);
671 update_fpscr(GETPC());
672 return t0;
675 float32 helper_fsub_FT(float32 t0, float32 t1)
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;
683 float64 helper_fsub_DT(float64 t0, float64 t1)
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;
691 uint32_t helper_ftrc_FT(float32 t0)
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;
700 uint32_t helper_ftrc_DT(float64 t0)
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;
709 void helper_fipr(uint32_t m, uint32_t n)
711 int bank, i;
712 float32 r, p;
714 bank = (env->sr & FPSCR_FR) ? 16 : 0;
715 r = float32_zero;
716 set_float_exception_flags(0, &env->fp_status);
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);
724 update_fpscr(GETPC());
726 env->fregs[bank + n + 3] = r;
729 void helper_ftrv(uint32_t n)
731 int bank_matrix, bank_vector;
732 int i, j;
733 float32 r[4];
734 float32 p;
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);
748 update_fpscr(GETPC());
750 for (i = 0 ; i < 4 ; i++) {
751 env->fregs[bank_vector + i] = r[i];