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 "cpu.h" 23 #include "exec/helper-proto.h" 24 #include "exec/exec-all.h" 25 #include "internal.h" 26 27 /* Specials */ 28 target_ulong helper_di(CPUMIPSState *env) 29 { 30 target_ulong t0 = env->CP0_Status; 31 32 env->CP0_Status = t0 & ~(1 << CP0St_IE); 33 return t0; 34 } 35 36 target_ulong helper_ei(CPUMIPSState *env) 37 { 38 target_ulong t0 = env->CP0_Status; 39 40 env->CP0_Status = t0 | (1 << CP0St_IE); 41 return t0; 42 } 43 44 static void debug_pre_eret(CPUMIPSState *env) 45 { 46 if (qemu_loglevel_mask(CPU_LOG_EXEC)) { 47 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, 48 env->active_tc.PC, env->CP0_EPC); 49 if (env->CP0_Status & (1 << CP0St_ERL)) { 50 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); 51 } 52 if (env->hflags & MIPS_HFLAG_DM) { 53 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); 54 } 55 qemu_log("\n"); 56 } 57 } 58 59 static void debug_post_eret(CPUMIPSState *env) 60 { 61 if (qemu_loglevel_mask(CPU_LOG_EXEC)) { 62 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, 63 env->active_tc.PC, env->CP0_EPC); 64 if (env->CP0_Status & (1 << CP0St_ERL)) { 65 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); 66 } 67 if (env->hflags & MIPS_HFLAG_DM) { 68 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); 69 } 70 switch (cpu_mmu_index(env, false)) { 71 case 3: 72 qemu_log(", ERL\n"); 73 break; 74 case MIPS_HFLAG_UM: 75 qemu_log(", UM\n"); 76 break; 77 case MIPS_HFLAG_SM: 78 qemu_log(", SM\n"); 79 break; 80 case MIPS_HFLAG_KM: 81 qemu_log("\n"); 82 break; 83 default: 84 cpu_abort(env_cpu(env), "Invalid MMU mode!\n"); 85 break; 86 } 87 } 88 } 89 90 bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb) 91 { 92 MIPSCPU *cpu = MIPS_CPU(cs); 93 CPUMIPSState *env = &cpu->env; 94 95 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 96 && 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