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 178167ee88SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 180633879fSpbrook */ 193e457172SBlue Swirl #include "cpu.h" 20e1f3808eSpbrook #include "helpers.h" 210633879fSpbrook 220633879fSpbrook #if defined(CONFIG_USER_ONLY) 230633879fSpbrook 2497a8ea5aSAndreas Färber void m68k_cpu_do_interrupt(CPUState *cs) 250633879fSpbrook { 2697a8ea5aSAndreas Färber M68kCPU *cpu = M68K_CPU(cs); 2797a8ea5aSAndreas Färber CPUM68KState *env = &cpu->env; 2897a8ea5aSAndreas Färber 2931871141SBlue Swirl env->exception_index = -1; 303c688828SBlue Swirl } 313c688828SBlue Swirl 3231871141SBlue Swirl void do_interrupt_m68k_hardirq(CPUM68KState *env) 333c688828SBlue Swirl { 340633879fSpbrook } 350633879fSpbrook 360633879fSpbrook #else 370633879fSpbrook 38a87295e8Spbrook extern int semihosting_enabled; 39a87295e8Spbrook 40022c62cbSPaolo Bonzini #include "exec/softmmu_exec.h" 413e457172SBlue Swirl 420633879fSpbrook #define MMUSUFFIX _mmu 430633879fSpbrook 440633879fSpbrook #define SHIFT 0 45022c62cbSPaolo Bonzini #include "exec/softmmu_template.h" 460633879fSpbrook 470633879fSpbrook #define SHIFT 1 48022c62cbSPaolo Bonzini #include "exec/softmmu_template.h" 490633879fSpbrook 500633879fSpbrook #define SHIFT 2 51022c62cbSPaolo Bonzini #include "exec/softmmu_template.h" 520633879fSpbrook 530633879fSpbrook #define SHIFT 3 54022c62cbSPaolo Bonzini #include "exec/softmmu_template.h" 550633879fSpbrook 560633879fSpbrook /* Try to fill the TLB and return an exception if error. If retaddr is 570633879fSpbrook NULL, it means that the function was called in C code (i.e. not 580633879fSpbrook from generated code or from helper.c) */ 5931871141SBlue Swirl void tlb_fill(CPUM68KState *env, target_ulong addr, int is_write, int mmu_idx, 6020503968SBlue Swirl uintptr_t retaddr) 610633879fSpbrook { 620633879fSpbrook int ret; 630633879fSpbrook 6497b348e7SBlue Swirl ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx); 65551bd27fSths if (unlikely(ret)) { 660633879fSpbrook if (retaddr) { 670633879fSpbrook /* now we have a real cpu fault */ 68a8a826a3SBlue Swirl cpu_restore_state(env, retaddr); 690633879fSpbrook } 701162c041SBlue Swirl cpu_loop_exit(env); 710633879fSpbrook } 720633879fSpbrook } 730633879fSpbrook 7431871141SBlue Swirl static void do_rte(CPUM68KState *env) 750633879fSpbrook { 760633879fSpbrook uint32_t sp; 770633879fSpbrook uint32_t fmt; 780633879fSpbrook 790633879fSpbrook sp = env->aregs[7]; 8031871141SBlue Swirl fmt = cpu_ldl_kernel(env, sp); 8131871141SBlue Swirl env->pc = cpu_ldl_kernel(env, sp + 4); 820633879fSpbrook sp |= (fmt >> 28) & 3; 830633879fSpbrook env->sr = fmt & 0xffff; 8420dcee94Spbrook m68k_switch_sp(env); 850633879fSpbrook env->aregs[7] = sp + 8; 860633879fSpbrook } 870633879fSpbrook 8831871141SBlue Swirl static void do_interrupt_all(CPUM68KState *env, int is_hw) 890633879fSpbrook { 90259186a7SAndreas Färber CPUState *cs; 910633879fSpbrook uint32_t sp; 920633879fSpbrook uint32_t fmt; 930633879fSpbrook uint32_t retaddr; 940633879fSpbrook uint32_t vector; 950633879fSpbrook 960633879fSpbrook fmt = 0; 970633879fSpbrook retaddr = env->pc; 980633879fSpbrook 990633879fSpbrook if (!is_hw) { 1000633879fSpbrook switch (env->exception_index) { 1010633879fSpbrook case EXCP_RTE: 1020633879fSpbrook /* Return from an exception. */ 10331871141SBlue Swirl do_rte(env); 1040633879fSpbrook return; 105a87295e8Spbrook case EXCP_HALT_INSN: 106a87295e8Spbrook if (semihosting_enabled 107a87295e8Spbrook && (env->sr & SR_S) != 0 108a87295e8Spbrook && (env->pc & 3) == 0 10931871141SBlue Swirl && cpu_lduw_code(env, env->pc - 4) == 0x4e71 11031871141SBlue Swirl && cpu_ldl_code(env, env->pc) == 0x4e7bf000) { 111a87295e8Spbrook env->pc += 4; 112a87295e8Spbrook do_m68k_semihosting(env, env->dregs[0]); 113a87295e8Spbrook return; 114a87295e8Spbrook } 115259186a7SAndreas Färber cs = CPU(m68k_env_get_cpu(env)); 116259186a7SAndreas Färber cs->halted = 1; 117a87295e8Spbrook env->exception_index = EXCP_HLT; 1181162c041SBlue Swirl cpu_loop_exit(env); 119a87295e8Spbrook return; 1200633879fSpbrook } 1210633879fSpbrook if (env->exception_index >= EXCP_TRAP0 1220633879fSpbrook && env->exception_index <= EXCP_TRAP15) { 1230633879fSpbrook /* Move the PC after the trap instruction. */ 1240633879fSpbrook retaddr += 2; 1250633879fSpbrook } 1260633879fSpbrook } 1270633879fSpbrook 1280633879fSpbrook vector = env->exception_index << 2; 1290633879fSpbrook 1300cf5c677Spbrook sp = env->aregs[7]; 1310cf5c677Spbrook 1320633879fSpbrook fmt |= 0x40000000; 1330633879fSpbrook fmt |= (sp & 3) << 28; 1340633879fSpbrook fmt |= vector << 16; 1350633879fSpbrook fmt |= env->sr; 1360633879fSpbrook 13720dcee94Spbrook env->sr |= SR_S; 13820dcee94Spbrook if (is_hw) { 13920dcee94Spbrook env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); 14020dcee94Spbrook env->sr &= ~SR_M; 14120dcee94Spbrook } 14220dcee94Spbrook m68k_switch_sp(env); 14320dcee94Spbrook 1440633879fSpbrook /* ??? This could cause MMU faults. */ 1450633879fSpbrook sp &= ~3; 1460633879fSpbrook sp -= 4; 14731871141SBlue Swirl cpu_stl_kernel(env, sp, retaddr); 1480633879fSpbrook sp -= 4; 14931871141SBlue Swirl cpu_stl_kernel(env, sp, fmt); 1500633879fSpbrook env->aregs[7] = sp; 1510633879fSpbrook /* Jump to vector. */ 15231871141SBlue Swirl env->pc = cpu_ldl_kernel(env, env->vbr + vector); 1530633879fSpbrook } 1540633879fSpbrook 15597a8ea5aSAndreas Färber void m68k_cpu_do_interrupt(CPUState *cs) 1563c688828SBlue Swirl { 15797a8ea5aSAndreas Färber M68kCPU *cpu = M68K_CPU(cs); 15897a8ea5aSAndreas Färber CPUM68KState *env = &cpu->env; 15997a8ea5aSAndreas Färber 16031871141SBlue Swirl do_interrupt_all(env, 0); 1613c688828SBlue Swirl } 1623c688828SBlue Swirl 16331871141SBlue Swirl void do_interrupt_m68k_hardirq(CPUM68KState *env) 1643c688828SBlue Swirl { 16531871141SBlue Swirl do_interrupt_all(env, 1); 1663c688828SBlue Swirl } 1670633879fSpbrook #endif 168e1f3808eSpbrook 16931871141SBlue Swirl static void raise_exception(CPUM68KState *env, int tt) 170e1f3808eSpbrook { 171e1f3808eSpbrook env->exception_index = tt; 1721162c041SBlue Swirl cpu_loop_exit(env); 173e1f3808eSpbrook } 174e1f3808eSpbrook 17531871141SBlue Swirl void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) 176e1f3808eSpbrook { 17731871141SBlue Swirl raise_exception(env, tt); 178e1f3808eSpbrook } 179e1f3808eSpbrook 1802b3e3cfeSAndreas Färber void HELPER(divu)(CPUM68KState *env, uint32_t word) 181e1f3808eSpbrook { 182e1f3808eSpbrook uint32_t num; 183e1f3808eSpbrook uint32_t den; 184e1f3808eSpbrook uint32_t quot; 185e1f3808eSpbrook uint32_t rem; 186e1f3808eSpbrook uint32_t flags; 187e1f3808eSpbrook 188e1f3808eSpbrook num = env->div1; 189e1f3808eSpbrook den = env->div2; 190e1f3808eSpbrook /* ??? This needs to make sure the throwing location is accurate. */ 19131871141SBlue Swirl if (den == 0) { 19231871141SBlue Swirl raise_exception(env, EXCP_DIV0); 19331871141SBlue Swirl } 194e1f3808eSpbrook quot = num / den; 195e1f3808eSpbrook rem = num % den; 196e1f3808eSpbrook flags = 0; 197e1f3808eSpbrook if (word && quot > 0xffff) 198e1f3808eSpbrook flags |= CCF_V; 199e1f3808eSpbrook if (quot == 0) 200e1f3808eSpbrook flags |= CCF_Z; 201e1f3808eSpbrook else if ((int32_t)quot < 0) 202e1f3808eSpbrook flags |= CCF_N; 203e1f3808eSpbrook env->div1 = quot; 204e1f3808eSpbrook env->div2 = rem; 205e1f3808eSpbrook env->cc_dest = flags; 206e1f3808eSpbrook } 207e1f3808eSpbrook 2082b3e3cfeSAndreas Färber void HELPER(divs)(CPUM68KState *env, uint32_t word) 209e1f3808eSpbrook { 210e1f3808eSpbrook int32_t num; 211e1f3808eSpbrook int32_t den; 212e1f3808eSpbrook int32_t quot; 213e1f3808eSpbrook int32_t rem; 214e1f3808eSpbrook int32_t flags; 215e1f3808eSpbrook 216e1f3808eSpbrook num = env->div1; 217e1f3808eSpbrook den = env->div2; 21831871141SBlue Swirl if (den == 0) { 21931871141SBlue Swirl raise_exception(env, EXCP_DIV0); 22031871141SBlue Swirl } 221e1f3808eSpbrook quot = num / den; 222e1f3808eSpbrook rem = num % den; 223e1f3808eSpbrook flags = 0; 224e1f3808eSpbrook if (word && quot != (int16_t)quot) 225e1f3808eSpbrook flags |= CCF_V; 226e1f3808eSpbrook if (quot == 0) 227e1f3808eSpbrook flags |= CCF_Z; 228e1f3808eSpbrook else if (quot < 0) 229e1f3808eSpbrook flags |= CCF_N; 230e1f3808eSpbrook env->div1 = quot; 231e1f3808eSpbrook env->div2 = rem; 232e1f3808eSpbrook env->cc_dest = flags; 233e1f3808eSpbrook } 234