aboutsummaryrefslogtreecommitdiff
path: root/target-sh4/op_helper.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2006-04-27 21:07:38 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2006-04-27 21:07:38 +0000
commitfdf9b3e831e8e6b5ceb2a44c742da7d1ab558242 (patch)
treeba55ae7076148e88f174b9ce8928f12551583941 /target-sh4/op_helper.c
parent66a93e0f47fa9869178008c7bc38d66a7c5e45f4 (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.c372
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;
+}