1 /* 2 * MIPS emulation helpers for qemu. 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 "internal.h" 24 #include "exec/helper-proto.h" 25 #include "exec/exec-all.h" 26 #include "exec/memop.h" 27 #include "fpu_helper.h" 28 29 static inline target_ulong bitswap(target_ulong v) 30 { 31 v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | 32 ((v & (target_ulong)0x5555555555555555ULL) << 1); 33 v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | 34 ((v & (target_ulong)0x3333333333333333ULL) << 2); 35 v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | 36 ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); 37 return v; 38 } 39 40 #ifdef TARGET_MIPS64 41 target_ulong helper_dbitswap(target_ulong rt) 42 { 43 return bitswap(rt); 44 } 45 #endif 46 47 target_ulong helper_bitswap(target_ulong rt) 48 { 49 return (int32_t)bitswap(rt); 50 } 51 52 target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx, 53 uint32_t stripe) 54 { 55 int i; 56 uint64_t tmp0 = ((uint64_t)rs) << 32 | ((uint64_t)rs & 0xffffffff); 57 uint64_t tmp1 = tmp0; 58 for (i = 0; i <= 46; i++) { 59 int s; 60 if (i & 0x8) { 61 s = shift; 62 } else { 63 s = shiftx; 64 } 65 66 if (stripe != 0 && !(i & 0x4)) { 67 s = ~s; 68 } 69 if (s & 0x10) { 70 if (tmp0 & (1LL << (i + 16))) { 71 tmp1 |= 1LL << i; 72 } else { 73 tmp1 &= ~(1LL << i); 74 } 75 } 76 } 77 78 uint64_t tmp2 = tmp1; 79 for (i = 0; i <= 38; i++) { 80 int s; 81 if (i & 0x4) { 82 s = shift; 83 } else { 84 s = shiftx; 85 } 86 87 if (s & 0x8) { 88 if (tmp1 & (1LL << (i + 8))) { 89 tmp2 |= 1LL << i; 90 } else { 91 tmp2 &= ~(1LL << i); 92 } 93 } 94 } 95 96 uint64_t tmp3 = tmp2; 97 for (i = 0; i <= 34; i++) { 98 int s; 99 if (i & 0x2) { 100 s = shift; 101 } else { 102 s = shiftx; 103 } 104 if (s & 0x4) { 105 if (tmp2 & (1LL << (i + 4))) { 106 tmp3 |= 1LL << i; 107 } else { 108 tmp3 &= ~(1LL << i); 109 } 110 } 111 } 112 113 uint64_t tmp4 = tmp3; 114 for (i = 0; i <= 32; i++) { 115 int s; 116 if (i & 0x1) { 117 s = shift; 118 } else { 119 s = shiftx; 120 } 121 if (s & 0x2) { 122 if (tmp3 & (1LL << (i + 2))) { 123 tmp4 |= 1LL << i; 124 } else { 125 tmp4 &= ~(1LL << i); 126 } 127 } 128 } 129 130 uint64_t tmp5 = tmp4; 131 for (i = 0; i <= 31; i++) { 132 int s; 133 s = shift; 134 if (s & 0x1) { 135 if (tmp4 & (1LL << (i + 1))) { 136 tmp5 |= 1LL << i; 137 } else { 138 tmp5 &= ~(1LL << i); 139 } 140 } 141 } 142 143 return (int64_t)(int32_t)(uint32_t)tmp5; 144 } 145 146 void helper_fork(target_ulong arg1, target_ulong arg2) 147 { 148 /* 149 * arg1 = rt, arg2 = rs 150 * TODO: store to TC register 151 */ 152 } 153 154 target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) 155 { 156 target_long arg1 = arg; 157 158 if (arg1 < 0) { 159 /* No scheduling policy implemented. */ 160 if (arg1 != -2) { 161 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) && 162 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) { 163 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 164 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; 165 do_raise_exception(env, EXCP_THREAD, GETPC()); 166 } 167 } 168 } else if (arg1 == 0) { 169 if (0) { 170 /* TODO: TC underflow */ 171 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 172 do_raise_exception(env, EXCP_THREAD, GETPC()); 173 } else { 174 /* TODO: Deallocate TC */ 175 } 176 } else if (arg1 > 0) { 177 /* Yield qualifier inputs not implemented. */ 178 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 179 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; 180 do_raise_exception(env, EXCP_THREAD, GETPC()); 181 } 182 return env->CP0_YQMask; 183 } 184 185 static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc) 186 { 187 if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) { 188 return; 189 } 190 do_raise_exception(env, EXCP_RI, pc); 191 } 192 193 target_ulong helper_rdhwr_cpunum(CPUMIPSState *env) 194 { 195 check_hwrena(env, 0, GETPC()); 196 return env->CP0_EBase & 0x3ff; 197 } 198 199 target_ulong helper_rdhwr_synci_step(CPUMIPSState *env) 200 { 201 check_hwrena(env, 1, GETPC()); 202 return env->SYNCI_Step; 203 } 204 205 target_ulong helper_rdhwr_cc(CPUMIPSState *env) 206 { 207 check_hwrena(env, 2, GETPC()); 208 #ifdef CONFIG_USER_ONLY 209 return env->CP0_Count; 210 #else 211 return (int32_t)cpu_mips_get_count(env); 212 #endif 213 } 214 215 target_ulong helper_rdhwr_ccres(CPUMIPSState *env) 216 { 217 check_hwrena(env, 3, GETPC()); 218 return env->CCRes; 219 } 220 221 target_ulong helper_rdhwr_performance(CPUMIPSState *env) 222 { 223 check_hwrena(env, 4, GETPC()); 224 return env->CP0_Performance0; 225 } 226 227 target_ulong helper_rdhwr_xnp(CPUMIPSState *env) 228 { 229 check_hwrena(env, 5, GETPC()); 230 return (env->CP0_Config5 >> CP0C5_XNP) & 1; 231 } 232 233 void helper_pmon(CPUMIPSState *env, int function) 234 { 235 function /= 2; 236 switch (function) { 237 case 2: /* TODO: char inbyte(int waitflag); */ 238 if (env->active_tc.gpr[4] == 0) { 239 env->active_tc.gpr[2] = -1; 240 } 241 /* Fall through */ 242 case 11: /* TODO: char inbyte (void); */ 243 env->active_tc.gpr[2] = -1; 244 break; 245 case 3: 246 case 12: 247 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF)); 248 break; 249 case 17: 250 break; 251 case 158: 252 { 253 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4]; 254 printf("%s", fmt); 255 } 256 break; 257 } 258 } 259 260 #ifdef TARGET_MIPS64 261 target_ulong helper_lcsr_cpucfg(CPUMIPSState *env, target_ulong rs) 262 { 263 switch (rs) { 264 case 0: 265 return env->CP0_PRid; 266 case 1: 267 return env->lcsr_cpucfg1; 268 case 2: 269 return env->lcsr_cpucfg2; 270 default: 271 return 0; 272 } 273 } 274 #endif 275 276 #if !defined(CONFIG_USER_ONLY) 277 278 void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 279 MMUAccessType access_type, 280 int mmu_idx, uintptr_t retaddr) 281 { 282 MIPSCPU *cpu = MIPS_CPU(cs); 283 CPUMIPSState *env = &cpu->env; 284 int error_code = 0; 285 int excp; 286 287 if (!(env->hflags & MIPS_HFLAG_DM)) { 288 env->CP0_BadVAddr = addr; 289 } 290 291 if (access_type == MMU_DATA_STORE) { 292 excp = EXCP_AdES; 293 } else { 294 excp = EXCP_AdEL; 295 if (access_type == MMU_INST_FETCH) { 296 error_code |= EXCP_INST_NOTAVAIL; 297 } 298 } 299 300 do_raise_exception_err(env, excp, error_code, retaddr); 301 } 302 303 void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, 304 vaddr addr, unsigned size, 305 MMUAccessType access_type, 306 int mmu_idx, MemTxAttrs attrs, 307 MemTxResult response, uintptr_t retaddr) 308 { 309 MIPSCPU *cpu = MIPS_CPU(cs); 310 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu); 311 CPUMIPSState *env = &cpu->env; 312 313 if (access_type == MMU_INST_FETCH) { 314 do_raise_exception(env, EXCP_IBE, retaddr); 315 } else if (!mcc->no_data_aborts) { 316 do_raise_exception(env, EXCP_DBE, retaddr); 317 } 318 } 319 #endif /* !CONFIG_USER_ONLY */ 320