10633879fSpbrook /* 20633879fSpbrook * M68K helper routines 30633879fSpbrook * 40633879fSpbrook * Copyright (c) 2007 CodeSourcery 50633879fSpbrook * 60633879fSpbrook * This library is free software; you can redistribute it and/or 70633879fSpbrook * modify it under the terms of the GNU Lesser General Public 80633879fSpbrook * License as published by the Free Software Foundation; either 90633879fSpbrook * version 2 of the License, or (at your option) any later version. 100633879fSpbrook * 110633879fSpbrook * This library is distributed in the hope that it will be useful, 120633879fSpbrook * but WITHOUT ANY WARRANTY; without even the implied warranty of 130633879fSpbrook * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 140633879fSpbrook * Lesser General Public License for more details. 150633879fSpbrook * 160633879fSpbrook * You should have received a copy of the GNU Lesser General Public 170633879fSpbrook * License along with this library; if not, write to the Free Software 180633879fSpbrook * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 190633879fSpbrook */ 200633879fSpbrook #include "exec.h" 210633879fSpbrook 220633879fSpbrook #if defined(CONFIG_USER_ONLY) 230633879fSpbrook 240633879fSpbrook void do_interrupt(int is_hw) 250633879fSpbrook { 260633879fSpbrook env->exception_index = -1; 270633879fSpbrook } 280633879fSpbrook 290633879fSpbrook #else 300633879fSpbrook 31a87295e8Spbrook extern int semihosting_enabled; 32a87295e8Spbrook 330633879fSpbrook #define MMUSUFFIX _mmu 340633879fSpbrook #define GETPC() (__builtin_return_address(0)) 350633879fSpbrook 360633879fSpbrook #define SHIFT 0 370633879fSpbrook #include "softmmu_template.h" 380633879fSpbrook 390633879fSpbrook #define SHIFT 1 400633879fSpbrook #include "softmmu_template.h" 410633879fSpbrook 420633879fSpbrook #define SHIFT 2 430633879fSpbrook #include "softmmu_template.h" 440633879fSpbrook 450633879fSpbrook #define SHIFT 3 460633879fSpbrook #include "softmmu_template.h" 470633879fSpbrook 480633879fSpbrook /* Try to fill the TLB and return an exception if error. If retaddr is 490633879fSpbrook NULL, it means that the function was called in C code (i.e. not 500633879fSpbrook from generated code or from helper.c) */ 510633879fSpbrook /* XXX: fix it to restore all registers */ 520633879fSpbrook void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) 530633879fSpbrook { 540633879fSpbrook TranslationBlock *tb; 550633879fSpbrook CPUState *saved_env; 560633879fSpbrook target_phys_addr_t pc; 570633879fSpbrook int ret; 580633879fSpbrook 590633879fSpbrook /* XXX: hack to restore env in all cases, even if not called from 600633879fSpbrook generated code */ 610633879fSpbrook saved_env = env; 620633879fSpbrook env = cpu_single_env; 630633879fSpbrook ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1); 640633879fSpbrook if (__builtin_expect(ret, 0)) { 650633879fSpbrook if (retaddr) { 660633879fSpbrook /* now we have a real cpu fault */ 670633879fSpbrook pc = (target_phys_addr_t)retaddr; 680633879fSpbrook tb = tb_find_pc(pc); 690633879fSpbrook if (tb) { 700633879fSpbrook /* the PC is inside the translated code. It means that we have 710633879fSpbrook a virtual CPU fault */ 720633879fSpbrook cpu_restore_state(tb, env, pc, NULL); 730633879fSpbrook } 740633879fSpbrook } 750633879fSpbrook cpu_loop_exit(); 760633879fSpbrook } 770633879fSpbrook env = saved_env; 780633879fSpbrook } 790633879fSpbrook 800633879fSpbrook static void do_rte(void) 810633879fSpbrook { 820633879fSpbrook uint32_t sp; 830633879fSpbrook uint32_t fmt; 840633879fSpbrook 850633879fSpbrook sp = env->aregs[7]; 860633879fSpbrook fmt = ldl_kernel(sp); 870633879fSpbrook env->pc = ldl_kernel(sp + 4); 880633879fSpbrook sp |= (fmt >> 28) & 3; 890633879fSpbrook env->sr = fmt & 0xffff; 9020dcee94Spbrook m68k_switch_sp(env); 910633879fSpbrook env->aregs[7] = sp + 8; 920633879fSpbrook } 930633879fSpbrook 940633879fSpbrook void do_interrupt(int is_hw) 950633879fSpbrook { 960633879fSpbrook uint32_t sp; 970633879fSpbrook uint32_t fmt; 980633879fSpbrook uint32_t retaddr; 990633879fSpbrook uint32_t vector; 1000633879fSpbrook 1010633879fSpbrook fmt = 0; 1020633879fSpbrook retaddr = env->pc; 1030633879fSpbrook 1040633879fSpbrook if (!is_hw) { 1050633879fSpbrook switch (env->exception_index) { 1060633879fSpbrook case EXCP_RTE: 1070633879fSpbrook /* Return from an exception. */ 1080633879fSpbrook do_rte(); 1090633879fSpbrook return; 110a87295e8Spbrook case EXCP_HALT_INSN: 111a87295e8Spbrook if (semihosting_enabled 112a87295e8Spbrook && (env->sr & SR_S) != 0 113a87295e8Spbrook && (env->pc & 3) == 0 114a87295e8Spbrook && lduw_code(env->pc - 4) == 0x4e71 115a87295e8Spbrook && ldl_code(env->pc) == 0x4e7bf000) { 116a87295e8Spbrook env->pc += 4; 117a87295e8Spbrook do_m68k_semihosting(env, env->dregs[0]); 118a87295e8Spbrook return; 119a87295e8Spbrook } 120a87295e8Spbrook env->halted = 1; 121a87295e8Spbrook env->exception_index = EXCP_HLT; 122a87295e8Spbrook cpu_loop_exit(); 123a87295e8Spbrook return; 1240633879fSpbrook } 1250633879fSpbrook if (env->exception_index >= EXCP_TRAP0 1260633879fSpbrook && env->exception_index <= EXCP_TRAP15) { 1270633879fSpbrook /* Move the PC after the trap instruction. */ 1280633879fSpbrook retaddr += 2; 1290633879fSpbrook } 1300633879fSpbrook } 1310633879fSpbrook 1320633879fSpbrook vector = env->exception_index << 2; 1330633879fSpbrook 1340633879fSpbrook fmt |= 0x40000000; 1350633879fSpbrook fmt |= (sp & 3) << 28; 1360633879fSpbrook fmt |= vector << 16; 1370633879fSpbrook fmt |= env->sr; 1380633879fSpbrook 13920dcee94Spbrook env->sr |= SR_S; 14020dcee94Spbrook if (is_hw) { 14120dcee94Spbrook env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); 14220dcee94Spbrook env->sr &= ~SR_M; 14320dcee94Spbrook } 14420dcee94Spbrook m68k_switch_sp(env); 14520dcee94Spbrook 14620dcee94Spbrook sp = env->aregs[7]; 14720dcee94Spbrook 1480633879fSpbrook /* ??? This could cause MMU faults. */ 1490633879fSpbrook sp &= ~3; 1500633879fSpbrook sp -= 4; 1510633879fSpbrook stl_kernel(sp, retaddr); 1520633879fSpbrook sp -= 4; 1530633879fSpbrook stl_kernel(sp, fmt); 1540633879fSpbrook env->aregs[7] = sp; 1550633879fSpbrook /* Jump to vector. */ 1560633879fSpbrook env->pc = ldl_kernel(env->vbr + vector); 1570633879fSpbrook } 1580633879fSpbrook 1590633879fSpbrook #endif 160