18aa52bdcSPhilippe Mathieu-Daudé /* 28aa52bdcSPhilippe Mathieu-Daudé * MIPS Exceptions processing helpers for QEMU. 38aa52bdcSPhilippe Mathieu-Daudé * 48aa52bdcSPhilippe Mathieu-Daudé * Copyright (c) 2004-2005 Jocelyn Mayer 58aa52bdcSPhilippe Mathieu-Daudé * 68aa52bdcSPhilippe Mathieu-Daudé * This library is free software; you can redistribute it and/or 78aa52bdcSPhilippe Mathieu-Daudé * modify it under the terms of the GNU Lesser General Public 88aa52bdcSPhilippe Mathieu-Daudé * License as published by the Free Software Foundation; either 98aa52bdcSPhilippe Mathieu-Daudé * version 2.1 of the License, or (at your option) any later version. 108aa52bdcSPhilippe Mathieu-Daudé * 118aa52bdcSPhilippe Mathieu-Daudé * This library is distributed in the hope that it will be useful, 128aa52bdcSPhilippe Mathieu-Daudé * but WITHOUT ANY WARRANTY; without even the implied warranty of 138aa52bdcSPhilippe Mathieu-Daudé * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 148aa52bdcSPhilippe Mathieu-Daudé * Lesser General Public License for more details. 158aa52bdcSPhilippe Mathieu-Daudé * 168aa52bdcSPhilippe Mathieu-Daudé * You should have received a copy of the GNU Lesser General Public 178aa52bdcSPhilippe Mathieu-Daudé * License along with this library; if not, see <http://www.gnu.org/licenses/>. 188aa52bdcSPhilippe Mathieu-Daudé * 198aa52bdcSPhilippe Mathieu-Daudé */ 208aa52bdcSPhilippe Mathieu-Daudé 218aa52bdcSPhilippe Mathieu-Daudé #include "qemu/osdep.h" 22*cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h" 238aa52bdcSPhilippe Mathieu-Daudé #include "cpu.h" 248aa52bdcSPhilippe Mathieu-Daudé #include "internal.h" 258aa52bdcSPhilippe Mathieu-Daudé #include "exec/helper-proto.h" 268aa52bdcSPhilippe Mathieu-Daudé #include "exec/exec-all.h" 278aa52bdcSPhilippe Mathieu-Daudé 288aa52bdcSPhilippe Mathieu-Daudé target_ulong exception_resume_pc(CPUMIPSState *env) 298aa52bdcSPhilippe Mathieu-Daudé { 308aa52bdcSPhilippe Mathieu-Daudé target_ulong bad_pc; 318aa52bdcSPhilippe Mathieu-Daudé target_ulong isa_mode; 328aa52bdcSPhilippe Mathieu-Daudé 338aa52bdcSPhilippe Mathieu-Daudé isa_mode = !!(env->hflags & MIPS_HFLAG_M16); 348aa52bdcSPhilippe Mathieu-Daudé bad_pc = env->active_tc.PC | isa_mode; 358aa52bdcSPhilippe Mathieu-Daudé if (env->hflags & MIPS_HFLAG_BMASK) { 368aa52bdcSPhilippe Mathieu-Daudé /* 378aa52bdcSPhilippe Mathieu-Daudé * If the exception was raised from a delay slot, come back to 388aa52bdcSPhilippe Mathieu-Daudé * the jump. 398aa52bdcSPhilippe Mathieu-Daudé */ 408aa52bdcSPhilippe Mathieu-Daudé bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); 418aa52bdcSPhilippe Mathieu-Daudé } 428aa52bdcSPhilippe Mathieu-Daudé 438aa52bdcSPhilippe Mathieu-Daudé return bad_pc; 448aa52bdcSPhilippe Mathieu-Daudé } 458aa52bdcSPhilippe Mathieu-Daudé 468aa52bdcSPhilippe Mathieu-Daudé void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception, 478aa52bdcSPhilippe Mathieu-Daudé int error_code) 488aa52bdcSPhilippe Mathieu-Daudé { 498aa52bdcSPhilippe Mathieu-Daudé do_raise_exception_err(env, exception, error_code, 0); 508aa52bdcSPhilippe Mathieu-Daudé } 518aa52bdcSPhilippe Mathieu-Daudé 528aa52bdcSPhilippe Mathieu-Daudé void helper_raise_exception(CPUMIPSState *env, uint32_t exception) 538aa52bdcSPhilippe Mathieu-Daudé { 548aa52bdcSPhilippe Mathieu-Daudé do_raise_exception(env, exception, GETPC()); 558aa52bdcSPhilippe Mathieu-Daudé } 568aa52bdcSPhilippe Mathieu-Daudé 578aa52bdcSPhilippe Mathieu-Daudé void helper_raise_exception_debug(CPUMIPSState *env) 588aa52bdcSPhilippe Mathieu-Daudé { 598aa52bdcSPhilippe Mathieu-Daudé do_raise_exception(env, EXCP_DEBUG, 0); 608aa52bdcSPhilippe Mathieu-Daudé } 618aa52bdcSPhilippe Mathieu-Daudé 628aa52bdcSPhilippe Mathieu-Daudé static void raise_exception(CPUMIPSState *env, uint32_t exception) 638aa52bdcSPhilippe Mathieu-Daudé { 648aa52bdcSPhilippe Mathieu-Daudé do_raise_exception(env, exception, 0); 658aa52bdcSPhilippe Mathieu-Daudé } 668aa52bdcSPhilippe Mathieu-Daudé 678aa52bdcSPhilippe Mathieu-Daudé void helper_wait(CPUMIPSState *env) 688aa52bdcSPhilippe Mathieu-Daudé { 698aa52bdcSPhilippe Mathieu-Daudé CPUState *cs = env_cpu(env); 708aa52bdcSPhilippe Mathieu-Daudé 718aa52bdcSPhilippe Mathieu-Daudé cs->halted = 1; 728aa52bdcSPhilippe Mathieu-Daudé cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); 738aa52bdcSPhilippe Mathieu-Daudé /* 748aa52bdcSPhilippe Mathieu-Daudé * Last instruction in the block, PC was updated before 758aa52bdcSPhilippe Mathieu-Daudé * - no need to recover PC and icount. 768aa52bdcSPhilippe Mathieu-Daudé */ 778aa52bdcSPhilippe Mathieu-Daudé raise_exception(env, EXCP_HLT); 788aa52bdcSPhilippe Mathieu-Daudé } 798aa52bdcSPhilippe Mathieu-Daudé 808aa52bdcSPhilippe Mathieu-Daudé void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) 818aa52bdcSPhilippe Mathieu-Daudé { 828aa52bdcSPhilippe Mathieu-Daudé MIPSCPU *cpu = MIPS_CPU(cs); 838aa52bdcSPhilippe Mathieu-Daudé CPUMIPSState *env = &cpu->env; 848aa52bdcSPhilippe Mathieu-Daudé 858aa52bdcSPhilippe Mathieu-Daudé env->active_tc.PC = tb->pc; 868aa52bdcSPhilippe Mathieu-Daudé env->hflags &= ~MIPS_HFLAG_BMASK; 878aa52bdcSPhilippe Mathieu-Daudé env->hflags |= tb->flags & MIPS_HFLAG_BMASK; 888aa52bdcSPhilippe Mathieu-Daudé } 898aa52bdcSPhilippe Mathieu-Daudé 908aa52bdcSPhilippe Mathieu-Daudé static const char * const excp_names[EXCP_LAST + 1] = { 918aa52bdcSPhilippe Mathieu-Daudé [EXCP_RESET] = "reset", 928aa52bdcSPhilippe Mathieu-Daudé [EXCP_SRESET] = "soft reset", 938aa52bdcSPhilippe Mathieu-Daudé [EXCP_DSS] = "debug single step", 948aa52bdcSPhilippe Mathieu-Daudé [EXCP_DINT] = "debug interrupt", 958aa52bdcSPhilippe Mathieu-Daudé [EXCP_NMI] = "non-maskable interrupt", 968aa52bdcSPhilippe Mathieu-Daudé [EXCP_MCHECK] = "machine check", 978aa52bdcSPhilippe Mathieu-Daudé [EXCP_EXT_INTERRUPT] = "interrupt", 988aa52bdcSPhilippe Mathieu-Daudé [EXCP_DFWATCH] = "deferred watchpoint", 998aa52bdcSPhilippe Mathieu-Daudé [EXCP_DIB] = "debug instruction breakpoint", 1008aa52bdcSPhilippe Mathieu-Daudé [EXCP_IWATCH] = "instruction fetch watchpoint", 1018aa52bdcSPhilippe Mathieu-Daudé [EXCP_AdEL] = "address error load", 1028aa52bdcSPhilippe Mathieu-Daudé [EXCP_AdES] = "address error store", 1038aa52bdcSPhilippe Mathieu-Daudé [EXCP_TLBF] = "TLB refill", 1048aa52bdcSPhilippe Mathieu-Daudé [EXCP_IBE] = "instruction bus error", 1058aa52bdcSPhilippe Mathieu-Daudé [EXCP_DBp] = "debug breakpoint", 1068aa52bdcSPhilippe Mathieu-Daudé [EXCP_SYSCALL] = "syscall", 1078aa52bdcSPhilippe Mathieu-Daudé [EXCP_BREAK] = "break", 1088aa52bdcSPhilippe Mathieu-Daudé [EXCP_CpU] = "coprocessor unusable", 1098aa52bdcSPhilippe Mathieu-Daudé [EXCP_RI] = "reserved instruction", 1108aa52bdcSPhilippe Mathieu-Daudé [EXCP_OVERFLOW] = "arithmetic overflow", 1118aa52bdcSPhilippe Mathieu-Daudé [EXCP_TRAP] = "trap", 1128aa52bdcSPhilippe Mathieu-Daudé [EXCP_FPE] = "floating point", 1138aa52bdcSPhilippe Mathieu-Daudé [EXCP_DDBS] = "debug data break store", 1148aa52bdcSPhilippe Mathieu-Daudé [EXCP_DWATCH] = "data watchpoint", 1158aa52bdcSPhilippe Mathieu-Daudé [EXCP_LTLBL] = "TLB modify", 1168aa52bdcSPhilippe Mathieu-Daudé [EXCP_TLBL] = "TLB load", 1178aa52bdcSPhilippe Mathieu-Daudé [EXCP_TLBS] = "TLB store", 1188aa52bdcSPhilippe Mathieu-Daudé [EXCP_DBE] = "data bus error", 1198aa52bdcSPhilippe Mathieu-Daudé [EXCP_DDBL] = "debug data break load", 1208aa52bdcSPhilippe Mathieu-Daudé [EXCP_THREAD] = "thread", 1218aa52bdcSPhilippe Mathieu-Daudé [EXCP_MDMX] = "MDMX", 1228aa52bdcSPhilippe Mathieu-Daudé [EXCP_C2E] = "precise coprocessor 2", 1238aa52bdcSPhilippe Mathieu-Daudé [EXCP_CACHE] = "cache error", 1248aa52bdcSPhilippe Mathieu-Daudé [EXCP_TLBXI] = "TLB execute-inhibit", 1258aa52bdcSPhilippe Mathieu-Daudé [EXCP_TLBRI] = "TLB read-inhibit", 1268aa52bdcSPhilippe Mathieu-Daudé [EXCP_MSADIS] = "MSA disabled", 1278aa52bdcSPhilippe Mathieu-Daudé [EXCP_MSAFPE] = "MSA floating point", 1288aa52bdcSPhilippe Mathieu-Daudé }; 1298aa52bdcSPhilippe Mathieu-Daudé 1308aa52bdcSPhilippe Mathieu-Daudé const char *mips_exception_name(int32_t exception) 1318aa52bdcSPhilippe Mathieu-Daudé { 1328aa52bdcSPhilippe Mathieu-Daudé if (exception < 0 || exception > EXCP_LAST) { 1338aa52bdcSPhilippe Mathieu-Daudé return "unknown"; 1348aa52bdcSPhilippe Mathieu-Daudé } 1358aa52bdcSPhilippe Mathieu-Daudé return excp_names[exception]; 1368aa52bdcSPhilippe Mathieu-Daudé } 1378aa52bdcSPhilippe Mathieu-Daudé 1388aa52bdcSPhilippe Mathieu-Daudé void do_raise_exception_err(CPUMIPSState *env, uint32_t exception, 1398aa52bdcSPhilippe Mathieu-Daudé int error_code, uintptr_t pc) 1408aa52bdcSPhilippe Mathieu-Daudé { 1418aa52bdcSPhilippe Mathieu-Daudé CPUState *cs = env_cpu(env); 1428aa52bdcSPhilippe Mathieu-Daudé 1438aa52bdcSPhilippe Mathieu-Daudé qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n", 1448aa52bdcSPhilippe Mathieu-Daudé __func__, exception, mips_exception_name(exception), 1458aa52bdcSPhilippe Mathieu-Daudé error_code); 1468aa52bdcSPhilippe Mathieu-Daudé cs->exception_index = exception; 1478aa52bdcSPhilippe Mathieu-Daudé env->error_code = error_code; 1488aa52bdcSPhilippe Mathieu-Daudé 1498aa52bdcSPhilippe Mathieu-Daudé cpu_loop_exit_restore(cs, pc); 1508aa52bdcSPhilippe Mathieu-Daudé } 151