1 /* 2 * QEMU MIPS emulation: Special opcode helpers 3 * 4 * Copyright (c) 2004-2005 Jocelyn Mayer 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu/log.h" 23 #include "cpu.h" 24 #include "exec/helper-proto.h" 25 #include "exec/exec-all.h" 26 #include "internal.h" 27 28 /* Specials */ 29 target_ulong helper_di(CPUMIPSState *env) 30 { 31 target_ulong t0 = env->CP0_Status; 32 33 env->CP0_Status = t0 & ~(1 << CP0St_IE); 34 return t0; 35 } 36 37 target_ulong helper_ei(CPUMIPSState *env) 38 { 39 target_ulong t0 = env->CP0_Status; 40 41 env->CP0_Status = t0 | (1 << CP0St_IE); 42 return t0; 43 } 44 45 static void debug_pre_eret(CPUMIPSState *env) 46 { 47 if (qemu_loglevel_mask(CPU_LOG_EXEC)) { 48 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, 49 env->active_tc.PC, env->CP0_EPC); 50 if (env->CP0_Status & (1 << CP0St_ERL)) { 51 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); 52 } 53 if (env->hflags & MIPS_HFLAG_DM) { 54 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); 55 } 56 qemu_log("\n"); 57 } 58 } 59 60 static void debug_post_eret(CPUMIPSState *env) 61 { 62 if (qemu_loglevel_mask(CPU_LOG_EXEC)) { 63 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, 64 env->active_tc.PC, env->CP0_EPC); 65 if (env->CP0_Status & (1 << CP0St_ERL)) { 66 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); 67 } 68 if (env->hflags & MIPS_HFLAG_DM) { 69 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); 70 } 71 switch (mips_env_mmu_index(env)) { 72 case 3: 73 qemu_log(", ERL\n"); 74 break; 75 case MIPS_HFLAG_UM: 76 qemu_log(", UM\n"); 77 break; 78 case MIPS_HFLAG_SM: 79 qemu_log(", SM\n"); 80 break; 81 case MIPS_HFLAG_KM: 82 qemu_log("\n"); 83 break; 84 default: 85 cpu_abort(env_cpu(env), "Invalid MMU mode!\n"); 86 break; 87 } 88 } 89 } 90 91 bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb) 92 { 93 CPUMIPSState *env = cpu_env(cs); 94 95 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 96 && !(cs->tcg_cflags & CF_PCREL) && env->active_tc.PC != tb->pc) { 97 env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); 98 env->hflags &= ~MIPS_HFLAG_BMASK; 99 return true; 100 } 101 return false; 102 } 103 104 static inline void exception_return(CPUMIPSState *env) 105 { 106 debug_pre_eret(env); 107 if (env->CP0_Status & (1 << CP0St_ERL)) { 108 mips_env_set_pc(env, env->CP0_ErrorEPC); 109 env->CP0_Status &= ~(1 << CP0St_ERL); 110 } else { 111 mips_env_set_pc(env, env->CP0_EPC); 112 env->CP0_Status &= ~(1 << CP0St_EXL); 113 } 114 compute_hflags(env); 115 debug_post_eret(env); 116 } 117 118 void helper_eret(CPUMIPSState *env) 119 { 120 exception_return(env); 121 env->CP0_LLAddr = 1; 122 env->lladdr = 1; 123 } 124 125 void helper_eretnc(CPUMIPSState *env) 126 { 127 exception_return(env); 128 } 129 130 void helper_deret(CPUMIPSState *env) 131 { 132 debug_pre_eret(env); 133 134 env->hflags &= ~MIPS_HFLAG_DM; 135 compute_hflags(env); 136 137 mips_env_set_pc(env, env->CP0_DEPC); 138 139 debug_post_eret(env); 140 } 141 142 void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op) 143 { 144 static const char *const type_name[] = { 145 "Primary Instruction", 146 "Primary Data or Unified Primary", 147 "Tertiary", 148 "Secondary" 149 }; 150 uint32_t cache_type = extract32(op, 0, 2); 151 uint32_t cache_operation = extract32(op, 2, 3); 152 target_ulong index = addr & 0x1fffffff; 153 154 switch (cache_operation) { 155 case 0b010: /* Index Store Tag */ 156 memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo, 157 MO_64, MEMTXATTRS_UNSPECIFIED); 158 break; 159 case 0b001: /* Index Load Tag */ 160 memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo, 161 MO_64, MEMTXATTRS_UNSPECIFIED); 162 break; 163 case 0b000: /* Index Invalidate */ 164 case 0b100: /* Hit Invalidate */ 165 case 0b110: /* Hit Writeback */ 166 /* no-op */ 167 break; 168 default: 169 qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n", 170 cache_operation, type_name[cache_type]); 171 break; 172 } 173 } 174