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 /* 64 bits arithmetic for 32 bits hosts */ 30 static inline uint64_t get_HILO(CPUMIPSState *env) 31 { 32 return ((uint64_t)(env->active_tc.HI[0]) << 32) | 33 (uint32_t)env->active_tc.LO[0]; 34 } 35 36 static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO) 37 { 38 env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); 39 return env->active_tc.HI[0] = (int32_t)(HILO >> 32); 40 } 41 42 static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO) 43 { 44 target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); 45 env->active_tc.HI[0] = (int32_t)(HILO >> 32); 46 return tmp; 47 } 48 49 /* Multiplication variants of the vr54xx. */ 50 target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1, 51 target_ulong arg2) 52 { 53 return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 * 54 (int64_t)(int32_t)arg2)); 55 } 56 57 target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1, 58 target_ulong arg2) 59 { 60 return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 * 61 (uint64_t)(uint32_t)arg2); 62 } 63 64 target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1, 65 target_ulong arg2) 66 { 67 return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 * 68 (int64_t)(int32_t)arg2); 69 } 70 71 target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1, 72 target_ulong arg2) 73 { 74 return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 * 75 (int64_t)(int32_t)arg2); 76 } 77 78 target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1, 79 target_ulong arg2) 80 { 81 return set_HI_LOT0(env, (uint64_t)get_HILO(env) + 82 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); 83 } 84 85 target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1, 86 target_ulong arg2) 87 { 88 return set_HIT0_LO(env, (uint64_t)get_HILO(env) + 89 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); 90 } 91 92 target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1, 93 target_ulong arg2) 94 { 95 return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 * 96 (int64_t)(int32_t)arg2); 97 } 98 99 target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1, 100 target_ulong arg2) 101 { 102 return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 * 103 (int64_t)(int32_t)arg2); 104 } 105 106 target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1, 107 target_ulong arg2) 108 { 109 return set_HI_LOT0(env, (uint64_t)get_HILO(env) - 110 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); 111 } 112 113 target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1, 114 target_ulong arg2) 115 { 116 return set_HIT0_LO(env, (uint64_t)get_HILO(env) - 117 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); 118 } 119 120 target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1, 121 target_ulong arg2) 122 { 123 return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); 124 } 125 126 target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1, 127 target_ulong arg2) 128 { 129 return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 * 130 (uint64_t)(uint32_t)arg2); 131 } 132 133 target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1, 134 target_ulong arg2) 135 { 136 return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 * 137 (int64_t)(int32_t)arg2); 138 } 139 140 target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1, 141 target_ulong arg2) 142 { 143 return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 * 144 (uint64_t)(uint32_t)arg2); 145 } 146 147 static inline target_ulong bitswap(target_ulong v) 148 { 149 v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | 150 ((v & (target_ulong)0x5555555555555555ULL) << 1); 151 v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | 152 ((v & (target_ulong)0x3333333333333333ULL) << 2); 153 v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | 154 ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); 155 return v; 156 } 157 158 #ifdef TARGET_MIPS64 159 target_ulong helper_dbitswap(target_ulong rt) 160 { 161 return bitswap(rt); 162 } 163 #endif 164 165 target_ulong helper_bitswap(target_ulong rt) 166 { 167 return (int32_t)bitswap(rt); 168 } 169 170 target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx, 171 uint32_t stripe) 172 { 173 int i; 174 uint64_t tmp0 = ((uint64_t)rs) << 32 | ((uint64_t)rs & 0xffffffff); 175 uint64_t tmp1 = tmp0; 176 for (i = 0; i <= 46; i++) { 177 int s; 178 if (i & 0x8) { 179 s = shift; 180 } else { 181 s = shiftx; 182 } 183 184 if (stripe != 0 && !(i & 0x4)) { 185 s = ~s; 186 } 187 if (s & 0x10) { 188 if (tmp0 & (1LL << (i + 16))) { 189 tmp1 |= 1LL << i; 190 } else { 191 tmp1 &= ~(1LL << i); 192 } 193 } 194 } 195 196 uint64_t tmp2 = tmp1; 197 for (i = 0; i <= 38; i++) { 198 int s; 199 if (i & 0x4) { 200 s = shift; 201 } else { 202 s = shiftx; 203 } 204 205 if (s & 0x8) { 206 if (tmp1 & (1LL << (i + 8))) { 207 tmp2 |= 1LL << i; 208 } else { 209 tmp2 &= ~(1LL << i); 210 } 211 } 212 } 213 214 uint64_t tmp3 = tmp2; 215 for (i = 0; i <= 34; i++) { 216 int s; 217 if (i & 0x2) { 218 s = shift; 219 } else { 220 s = shiftx; 221 } 222 if (s & 0x4) { 223 if (tmp2 & (1LL << (i + 4))) { 224 tmp3 |= 1LL << i; 225 } else { 226 tmp3 &= ~(1LL << i); 227 } 228 } 229 } 230 231 uint64_t tmp4 = tmp3; 232 for (i = 0; i <= 32; i++) { 233 int s; 234 if (i & 0x1) { 235 s = shift; 236 } else { 237 s = shiftx; 238 } 239 if (s & 0x2) { 240 if (tmp3 & (1LL << (i + 2))) { 241 tmp4 |= 1LL << i; 242 } else { 243 tmp4 &= ~(1LL << i); 244 } 245 } 246 } 247 248 uint64_t tmp5 = tmp4; 249 for (i = 0; i <= 31; i++) { 250 int s; 251 s = shift; 252 if (s & 0x1) { 253 if (tmp4 & (1LL << (i + 1))) { 254 tmp5 |= 1LL << i; 255 } else { 256 tmp5 &= ~(1LL << i); 257 } 258 } 259 } 260 261 return (int64_t)(int32_t)(uint32_t)tmp5; 262 } 263 264 void helper_fork(target_ulong arg1, target_ulong arg2) 265 { 266 /* 267 * arg1 = rt, arg2 = rs 268 * TODO: store to TC register 269 */ 270 } 271 272 target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) 273 { 274 target_long arg1 = arg; 275 276 if (arg1 < 0) { 277 /* No scheduling policy implemented. */ 278 if (arg1 != -2) { 279 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) && 280 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) { 281 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 282 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; 283 do_raise_exception(env, EXCP_THREAD, GETPC()); 284 } 285 } 286 } else if (arg1 == 0) { 287 if (0) { 288 /* TODO: TC underflow */ 289 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 290 do_raise_exception(env, EXCP_THREAD, GETPC()); 291 } else { 292 /* TODO: Deallocate TC */ 293 } 294 } else if (arg1 > 0) { 295 /* Yield qualifier inputs not implemented. */ 296 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); 297 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; 298 do_raise_exception(env, EXCP_THREAD, GETPC()); 299 } 300 return env->CP0_YQMask; 301 } 302 303 static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc) 304 { 305 if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) { 306 return; 307 } 308 do_raise_exception(env, EXCP_RI, pc); 309 } 310 311 target_ulong helper_rdhwr_cpunum(CPUMIPSState *env) 312 { 313 check_hwrena(env, 0, GETPC()); 314 return env->CP0_EBase & 0x3ff; 315 } 316 317 target_ulong helper_rdhwr_synci_step(CPUMIPSState *env) 318 { 319 check_hwrena(env, 1, GETPC()); 320 return env->SYNCI_Step; 321 } 322 323 target_ulong helper_rdhwr_cc(CPUMIPSState *env) 324 { 325 check_hwrena(env, 2, GETPC()); 326 #ifdef CONFIG_USER_ONLY 327 return env->CP0_Count; 328 #else 329 return (int32_t)cpu_mips_get_count(env); 330 #endif 331 } 332 333 target_ulong helper_rdhwr_ccres(CPUMIPSState *env) 334 { 335 check_hwrena(env, 3, GETPC()); 336 return env->CCRes; 337 } 338 339 target_ulong helper_rdhwr_performance(CPUMIPSState *env) 340 { 341 check_hwrena(env, 4, GETPC()); 342 return env->CP0_Performance0; 343 } 344 345 target_ulong helper_rdhwr_xnp(CPUMIPSState *env) 346 { 347 check_hwrena(env, 5, GETPC()); 348 return (env->CP0_Config5 >> CP0C5_XNP) & 1; 349 } 350 351 void helper_pmon(CPUMIPSState *env, int function) 352 { 353 function /= 2; 354 switch (function) { 355 case 2: /* TODO: char inbyte(int waitflag); */ 356 if (env->active_tc.gpr[4] == 0) { 357 env->active_tc.gpr[2] = -1; 358 } 359 /* Fall through */ 360 case 11: /* TODO: char inbyte (void); */ 361 env->active_tc.gpr[2] = -1; 362 break; 363 case 3: 364 case 12: 365 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF)); 366 break; 367 case 17: 368 break; 369 case 158: 370 { 371 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4]; 372 printf("%s", fmt); 373 } 374 break; 375 } 376 } 377 378 #if !defined(CONFIG_USER_ONLY) 379 380 void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 381 MMUAccessType access_type, 382 int mmu_idx, uintptr_t retaddr) 383 { 384 MIPSCPU *cpu = MIPS_CPU(cs); 385 CPUMIPSState *env = &cpu->env; 386 int error_code = 0; 387 int excp; 388 389 if (!(env->hflags & MIPS_HFLAG_DM)) { 390 env->CP0_BadVAddr = addr; 391 } 392 393 if (access_type == MMU_DATA_STORE) { 394 excp = EXCP_AdES; 395 } else { 396 excp = EXCP_AdEL; 397 if (access_type == MMU_INST_FETCH) { 398 error_code |= EXCP_INST_NOTAVAIL; 399 } 400 } 401 402 do_raise_exception_err(env, excp, error_code, retaddr); 403 } 404 405 void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, 406 vaddr addr, unsigned size, 407 MMUAccessType access_type, 408 int mmu_idx, MemTxAttrs attrs, 409 MemTxResult response, uintptr_t retaddr) 410 { 411 MIPSCPU *cpu = MIPS_CPU(cs); 412 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu); 413 CPUMIPSState *env = &cpu->env; 414 415 if (access_type == MMU_INST_FETCH) { 416 do_raise_exception(env, EXCP_IBE, retaddr); 417 } else if (!mcc->no_data_aborts) { 418 do_raise_exception(env, EXCP_DBE, retaddr); 419 } 420 } 421 #endif /* !CONFIG_USER_ONLY */ 422