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 (cpu_mmu_index(env, false)) { 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 MIPSCPU *cpu = MIPS_CPU(cs); 94 CPUMIPSState *env = &cpu->env; 95 96 if ((env->hflags & MIPS_HFLAG_BMASK) != 0 97 && !(cs->tcg_cflags & CF_PCREL) && env->active_tc.PC != tb->pc) { 98 env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); 99 env->hflags &= ~MIPS_HFLAG_BMASK; 100 return true; 101 } 102 return false; 103 } 104 105 static inline void exception_return(CPUMIPSState *env) 106 { 107 debug_pre_eret(env); 108 if (env->CP0_Status & (1 << CP0St_ERL)) { 109 mips_env_set_pc(env, env->CP0_ErrorEPC); 110 env->CP0_Status &= ~(1 << CP0St_ERL); 111 } else { 112 mips_env_set_pc(env, env->CP0_EPC); 113 env->CP0_Status &= ~(1 << CP0St_EXL); 114 } 115 compute_hflags(env); 116 debug_post_eret(env); 117 } 118 119 void helper_eret(CPUMIPSState *env) 120 { 121 exception_return(env); 122 env->CP0_LLAddr = 1; 123 env->lladdr = 1; 124 } 125 126 void helper_eretnc(CPUMIPSState *env) 127 { 128 exception_return(env); 129 } 130 131 void helper_deret(CPUMIPSState *env) 132 { 133 debug_pre_eret(env); 134 135 env->hflags &= ~MIPS_HFLAG_DM; 136 compute_hflags(env); 137 138 mips_env_set_pc(env, env->CP0_DEPC); 139 140 debug_post_eret(env); 141 } 142 143 void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op) 144 { 145 static const char *const type_name[] = { 146 "Primary Instruction", 147 "Primary Data or Unified Primary", 148 "Tertiary", 149 "Secondary" 150 }; 151 uint32_t cache_type = extract32(op, 0, 2); 152 uint32_t cache_operation = extract32(op, 2, 3); 153 target_ulong index = addr & 0x1fffffff; 154 155 switch (cache_operation) { 156 case 0b010: /* Index Store Tag */ 157 memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo, 158 MO_64, MEMTXATTRS_UNSPECIFIED); 159 break; 160 case 0b001: /* Index Load Tag */ 161 memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo, 162 MO_64, MEMTXATTRS_UNSPECIFIED); 163 break; 164 case 0b000: /* Index Invalidate */ 165 case 0b100: /* Hit Invalidate */ 166 case 0b110: /* Hit Writeback */ 167 /* no-op */ 168 break; 169 default: 170 qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n", 171 cache_operation, type_name[cache_type]); 172 break; 173 } 174 } 175