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