diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-04-27 21:07:38 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-04-27 21:07:38 +0000 |
commit | fdf9b3e831e8e6b5ceb2a44c742da7d1ab558242 (patch) | |
tree | ba55ae7076148e88f174b9ce8928f12551583941 /target-sh4/op_helper.c | |
parent | 66a93e0f47fa9869178008c7bc38d66a7c5e45f4 (diff) |
sh4 target (Samuel Tardieu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1861 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-sh4/op_helper.c')
-rw-r--r-- | target-sh4/op_helper.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c new file mode 100644 index 0000000000..1c63fe587b --- /dev/null +++ b/target-sh4/op_helper.c @@ -0,0 +1,372 @@ +/* + * SH4 emulation + * + * Copyright (c) 2005 Samuel Tardieu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <assert.h> +#include "exec.h" + +void cpu_loop_exit(void) +{ + longjmp(env->jmp_env, 1); +} + +void do_raise_exception(void) +{ + cpu_loop_exit(); +} + +#ifndef CONFIG_USER_ONLY + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + unsigned long pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long) retaddr; + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc, NULL); + } + } + do_raise_exception(); + } + env = saved_env; +} + +#endif + +void helper_addc_T0_T1(void) +{ + uint32_t tmp0, tmp1; + + tmp1 = T0 + T1; + tmp0 = T1; + T1 = tmp1 + (env->sr & 1); + if (tmp0 > tmp1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + if (tmp1 > T1) + env->sr |= SR_T; +} + +void helper_addv_T0_T1(void) +{ + uint32_t dest, src, ans; + + if ((int32_t) T1 >= 0) + dest = 0; + else + dest = 1; + if ((int32_t) T0 >= 0) + src = 0; + else + src = 1; + src += dest; + T1 += T0; + if ((int32_t) T1 >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 0 || src == 2) { + if (ans == 1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + } else + env->sr &= ~SR_T; +} + +#define T (env->sr & SR_T) +#define Q (env->sr & SR_Q ? 1 : 0) +#define M (env->sr & SR_M ? 1 : 0) +#define SETT env->sr |= SR_T +#define CLRT env->sr &= ~SR_T +#define SETQ env->sr |= SR_Q +#define CLRQ env->sr &= ~SR_Q +#define SETM env->sr |= SR_M +#define CLRM env->sr &= ~SR_M + +void helper_div1_T0_T1(void) +{ + uint32_t tmp0, tmp2; + uint8_t old_q, tmp1 = 0xff; + + printf("div1 T0=0x%08x T1=0x%08x M=%d Q=%d T=%d\n", T0, T1, M, Q, T); + old_q = Q; + if ((0x80000000 & T1) != 0) + SETQ; + else + CLRQ; + tmp2 = T0; + T1 <<= 1; + T1 |= T; + switch (old_q) { + case 0: + switch (M) { + case 0: + tmp0 = T1; + T1 -= tmp2; + tmp1 = T1 > tmp0; + switch (Q) { + case 0: + if (tmp1) + SETQ; + else + CLRQ; + break; + case 1: + if (tmp1 == 0) + SETQ; + else + CLRQ; + break; + } + break; + case 1: + tmp0 = T1; + T1 += tmp2; + tmp1 = T1 < tmp0; + switch (Q) { + case 0: + if (tmp1 == 0) + SETQ; + else + CLRQ; + break; + case 1: + if (tmp1) + SETQ; + else + CLRQ; + break; + } + break; + } + break; + case 1: + switch (M) { + case 0: + tmp0 = T1; + T1 += tmp2; + tmp1 = T1 < tmp0; + switch (Q) { + case 0: + if (tmp1) + SETQ; + else + CLRQ; + break; + case 1: + if (tmp1 == 0) + SETQ; + else + CLRQ; + break; + } + break; + case 1: + tmp0 = T1; + T1 -= tmp2; + tmp1 = T1 > tmp0; + switch (Q) { + case 0: + if (tmp1 == 0) + SETQ; + else + CLRQ; + break; + case 1: + if (tmp1) + SETQ; + else + CLRQ; + break; + } + break; + } + break; + } + if (Q == M) + SETT; + else + CLRT; + printf("Output: T1=0x%08x M=%d Q=%d T=%d\n", T1, M, Q, T); +} + +void helper_dmulsl_T0_T1() +{ + int64_t res; + + res = (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1; + env->mach = (res >> 32) & 0xffffffff; + env->macl = res & 0xffffffff; +} + +void helper_dmulul_T0_T1() +{ + uint64_t res; + + res = (uint64_t) (uint32_t) T0 *(uint64_t) (uint32_t) T1; + env->mach = (res >> 32) & 0xffffffff; + env->macl = res & 0xffffffff; +} + +void helper_macl_T0_T1() +{ + int64_t res; + + res = ((uint64_t) env->mach << 32) | env->macl; + res += (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1; + env->mach = (res >> 32) & 0xffffffff; + env->macl = res & 0xffffffff; + if (env->sr & SR_S) { + if (res < 0) + env->mach |= 0xffff0000; + else + env->mach &= 0x00007fff; + } +} + +void helper_macw_T0_T1() +{ + int64_t res; + + res = ((uint64_t) env->mach << 32) | env->macl; + res += (int64_t) (int16_t) T0 *(int64_t) (int16_t) T1; + env->mach = (res >> 32) & 0xffffffff; + env->macl = res & 0xffffffff; + if (env->sr & SR_S) { + if (res < -0x80000000) { + env->mach = 1; + env->macl = 0x80000000; + } else if (res > 0x000000007fffffff) { + env->mach = 1; + env->macl = 0x7fffffff; + } + } +} + +void helper_negc_T0() +{ + uint32_t temp; + + temp = -T0; + T0 = temp - (env->sr & SR_T); + if (0 < temp) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + if (temp < T0) + env->sr |= SR_T; +} + +void helper_subc_T0_T1() +{ + uint32_t tmp0, tmp1; + + tmp1 = T1 - T0; + tmp0 = T1; + T1 = tmp1 - (env->sr & SR_T); + if (tmp0 < tmp1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + if (tmp1 < T1) + env->sr |= SR_T; +} + +void helper_subv_T0_T1() +{ + int32_t dest, src, ans; + + if ((int32_t) T1 >= 0) + dest = 0; + else + dest = 1; + if ((int32_t) T0 >= 0) + src = 0; + else + src = 1; + src += dest; + T1 -= T0; + if ((int32_t) T1 >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 1) { + if (ans == 1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + } else + env->sr &= ~SR_T; +} + +void helper_rotcl(uint32_t * addr) +{ + uint32_t new; + + new = (*addr << 1) | (env->sr & SR_T); + if (*addr & 0x80000000) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + *addr = new; +} + +void helper_rotcr(uint32_t * addr) +{ + uint32_t new; + + new = (*addr >> 1) | ((env->sr & SR_T) ? 0x80000000 : 0); + if (*addr & 1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + *addr = new; +} |