diff options
author | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-23 19:58:11 +0000 |
---|---|---|
committer | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-23 19:58:11 +0000 |
commit | 0633879f1ac38b18d84c46dda506300cc8329723 (patch) | |
tree | 8df64e0861c32132c7a08af16451629f1ec69112 /target-m68k/op_helper.c | |
parent | 9daea9067aae3e324f14c6b139621c10683fc550 (diff) | |
download | hqemu-0633879f1ac38b18d84c46dda506300cc8329723.zip hqemu-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.c | 140 |
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 0000000..7455e31 --- /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 |