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