summaryrefslogtreecommitdiff
path: root/target-m68k/op_helper.c
diff options
context:
space:
mode:
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2007-05-23 19:58:11 +0000
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2007-05-23 19:58:11 +0000
commit0633879f1ac38b18d84c46dda506300cc8329723 (patch)
tree8df64e0861c32132c7a08af16451629f1ec69112 /target-m68k/op_helper.c
parent9daea9067aae3e324f14c6b139621c10683fc550 (diff)
downloadqemu-0633879f1ac38b18d84c46dda506300cc8329723.tar.gz
m68k/ColdFire system emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2851 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-m68k/op_helper.c')
-rw-r--r--target-m68k/op_helper.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
new file mode 100644
index 0000000000..7455e31659
--- /dev/null
+++ b/target-m68k/op_helper.c
@@ -0,0 +1,140 @@
+/*
+ * M68K helper routines
+ *
+ * Copyright (c) 2007 CodeSourcery
+ *
+ * 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 "exec.h"
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt(int is_hw)
+{
+ env->exception_index = -1;
+}
+
+#else
+
+#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"
+
+/* Try to fill the TLB and return an exception if error. If retaddr is
+ NULL, it means that the function was called in C code (i.e. not
+ from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
+{
+ TranslationBlock *tb;
+ CPUState *saved_env;
+ target_phys_addr_t 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_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1);
+ if (__builtin_expect(ret, 0)) {
+ if (retaddr) {
+ /* now we have a real cpu fault */
+ pc = (target_phys_addr_t)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);
+ }
+ }
+ cpu_loop_exit();
+ }
+ env = saved_env;
+}
+
+static void do_rte(void)
+{
+ uint32_t sp;
+ uint32_t fmt;
+
+ sp = env->aregs[7];
+ fmt = ldl_kernel(sp);
+ env->pc = ldl_kernel(sp + 4);
+ sp |= (fmt >> 28) & 3;
+ env->sr = fmt & 0xffff;
+ env->aregs[7] = sp + 8;
+}
+
+void do_interrupt(int is_hw)
+{
+ uint32_t sp;
+ uint32_t fmt;
+ uint32_t retaddr;
+ uint32_t vector;
+
+ fmt = 0;
+ retaddr = env->pc;
+
+ if (!is_hw) {
+ switch (env->exception_index) {
+ case EXCP_RTE:
+ /* Return from an exception. */
+ do_rte();
+ return;
+ }
+ if (env->exception_index >= EXCP_TRAP0
+ && env->exception_index <= EXCP_TRAP15) {
+ /* Move the PC after the trap instruction. */
+ retaddr += 2;
+ }
+ }
+
+ /* TODO: Implement USP. */
+ sp = env->aregs[7];
+
+ vector = env->exception_index << 2;
+
+ fmt |= 0x40000000;
+ fmt |= (sp & 3) << 28;
+ fmt |= vector << 16;
+ fmt |= env->sr;
+
+ /* ??? This could cause MMU faults. */
+ sp &= ~3;
+ sp -= 4;
+ stl_kernel(sp, retaddr);
+ sp -= 4;
+ stl_kernel(sp, fmt);
+ env->aregs[7] = sp;
+ env->sr |= SR_S;
+ if (is_hw) {
+ env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
+ }
+ /* Jump to vector. */
+ env->pc = ldl_kernel(env->vbr + vector);
+}
+
+#endif