1 /* 2 * Microblaze helper routines. 3 * 4 * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>. 5 * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu/log.h" 23 #include "cpu.h" 24 #include "exec/helper-proto.h" 25 #include "qemu/host-utils.h" 26 #include "exec/exec-all.h" 27 #include "exec/cpu_ldst.h" 28 #include "fpu/softfloat.h" 29 30 void helper_put(uint32_t id, uint32_t ctrl, uint32_t data) 31 { 32 int test = ctrl & STREAM_TEST; 33 int atomic = ctrl & STREAM_ATOMIC; 34 int control = ctrl & STREAM_CONTROL; 35 int nonblock = ctrl & STREAM_NONBLOCK; 36 int exception = ctrl & STREAM_EXCEPTION; 37 38 qemu_log_mask(LOG_UNIMP, "Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n", 39 id, data, 40 test ? "t" : "", 41 nonblock ? "n" : "", 42 exception ? "e" : "", 43 control ? "c" : "", 44 atomic ? "a" : ""); 45 } 46 47 uint32_t helper_get(uint32_t id, uint32_t ctrl) 48 { 49 int test = ctrl & STREAM_TEST; 50 int atomic = ctrl & STREAM_ATOMIC; 51 int control = ctrl & STREAM_CONTROL; 52 int nonblock = ctrl & STREAM_NONBLOCK; 53 int exception = ctrl & STREAM_EXCEPTION; 54 55 qemu_log_mask(LOG_UNIMP, "Unhandled stream get from stream-id=%d %s%s%s%s%s\n", 56 id, 57 test ? "t" : "", 58 nonblock ? "n" : "", 59 exception ? "e" : "", 60 control ? "c" : "", 61 atomic ? "a" : ""); 62 return 0xdead0000 | id; 63 } 64 65 void helper_raise_exception(CPUMBState *env, uint32_t index) 66 { 67 CPUState *cs = env_cpu(env); 68 69 cs->exception_index = index; 70 cpu_loop_exit(cs); 71 } 72 73 static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra) 74 { 75 if (unlikely(b == 0)) { 76 env->msr |= MSR_DZ; 77 78 if ((env->msr & MSR_EE) && 79 env_archcpu(env)->cfg.div_zero_exception) { 80 CPUState *cs = env_cpu(env); 81 82 env->esr = ESR_EC_DIVZERO; 83 cs->exception_index = EXCP_HW_EXCP; 84 cpu_loop_exit_restore(cs, ra); 85 } 86 return false; 87 } 88 return true; 89 } 90 91 uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b) 92 { 93 if (!check_divz(env, a, b, GETPC())) { 94 return 0; 95 } 96 return (int32_t)a / (int32_t)b; 97 } 98 99 uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b) 100 { 101 if (!check_divz(env, a, b, GETPC())) { 102 return 0; 103 } 104 return a / b; 105 } 106 107 /* raise FPU exception. */ 108 static void raise_fpu_exception(CPUMBState *env, uintptr_t ra) 109 { 110 CPUState *cs = env_cpu(env); 111 112 env->esr = ESR_EC_FPU; 113 cs->exception_index = EXCP_HW_EXCP; 114 cpu_loop_exit_restore(cs, ra); 115 } 116 117 static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra) 118 { 119 int raise = 0; 120 121 if (flags & float_flag_invalid) { 122 env->fsr |= FSR_IO; 123 raise = 1; 124 } 125 if (flags & float_flag_divbyzero) { 126 env->fsr |= FSR_DZ; 127 raise = 1; 128 } 129 if (flags & float_flag_overflow) { 130 env->fsr |= FSR_OF; 131 raise = 1; 132 } 133 if (flags & float_flag_underflow) { 134 env->fsr |= FSR_UF; 135 raise = 1; 136 } 137 if (raise 138 && (env_archcpu(env)->cfg.pvr_regs[2] & PVR2_FPU_EXC_MASK) 139 && (env->msr & MSR_EE)) { 140 raise_fpu_exception(env, ra); 141 } 142 } 143 144 uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b) 145 { 146 CPU_FloatU fd, fa, fb; 147 int flags; 148 149 set_float_exception_flags(0, &env->fp_status); 150 fa.l = a; 151 fb.l = b; 152 fd.f = float32_add(fa.f, fb.f, &env->fp_status); 153 154 flags = get_float_exception_flags(&env->fp_status); 155 update_fpu_flags(env, flags, GETPC()); 156 return fd.l; 157 } 158 159 uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b) 160 { 161 CPU_FloatU fd, fa, fb; 162 int flags; 163 164 set_float_exception_flags(0, &env->fp_status); 165 fa.l = a; 166 fb.l = b; 167 fd.f = float32_sub(fb.f, fa.f, &env->fp_status); 168 flags = get_float_exception_flags(&env->fp_status); 169 update_fpu_flags(env, flags, GETPC()); 170 return fd.l; 171 } 172 173 uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b) 174 { 175 CPU_FloatU fd, fa, fb; 176 int flags; 177 178 set_float_exception_flags(0, &env->fp_status); 179 fa.l = a; 180 fb.l = b; 181 fd.f = float32_mul(fa.f, fb.f, &env->fp_status); 182 flags = get_float_exception_flags(&env->fp_status); 183 update_fpu_flags(env, flags, GETPC()); 184 185 return fd.l; 186 } 187 188 uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b) 189 { 190 CPU_FloatU fd, fa, fb; 191 int flags; 192 193 set_float_exception_flags(0, &env->fp_status); 194 fa.l = a; 195 fb.l = b; 196 fd.f = float32_div(fb.f, fa.f, &env->fp_status); 197 flags = get_float_exception_flags(&env->fp_status); 198 update_fpu_flags(env, flags, GETPC()); 199 200 return fd.l; 201 } 202 203 uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b) 204 { 205 CPU_FloatU fa, fb; 206 uint32_t r = 0; 207 208 fa.l = a; 209 fb.l = b; 210 211 if (float32_is_signaling_nan(fa.f, &env->fp_status) || 212 float32_is_signaling_nan(fb.f, &env->fp_status)) { 213 update_fpu_flags(env, float_flag_invalid, GETPC()); 214 r = 1; 215 } 216 217 if (float32_is_quiet_nan(fa.f, &env->fp_status) || 218 float32_is_quiet_nan(fb.f, &env->fp_status)) { 219 r = 1; 220 } 221 222 return r; 223 } 224 225 uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b) 226 { 227 CPU_FloatU fa, fb; 228 int r; 229 int flags; 230 231 set_float_exception_flags(0, &env->fp_status); 232 fa.l = a; 233 fb.l = b; 234 r = float32_lt(fb.f, fa.f, &env->fp_status); 235 flags = get_float_exception_flags(&env->fp_status); 236 update_fpu_flags(env, flags & float_flag_invalid, GETPC()); 237 238 return r; 239 } 240 241 uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b) 242 { 243 CPU_FloatU fa, fb; 244 int flags; 245 int r; 246 247 set_float_exception_flags(0, &env->fp_status); 248 fa.l = a; 249 fb.l = b; 250 r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); 251 flags = get_float_exception_flags(&env->fp_status); 252 update_fpu_flags(env, flags & float_flag_invalid, GETPC()); 253 254 return r; 255 } 256 257 uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b) 258 { 259 CPU_FloatU fa, fb; 260 int flags; 261 int r; 262 263 fa.l = a; 264 fb.l = b; 265 set_float_exception_flags(0, &env->fp_status); 266 r = float32_le(fa.f, fb.f, &env->fp_status); 267 flags = get_float_exception_flags(&env->fp_status); 268 update_fpu_flags(env, flags & float_flag_invalid, GETPC()); 269 270 271 return r; 272 } 273 274 uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b) 275 { 276 CPU_FloatU fa, fb; 277 int flags, r; 278 279 fa.l = a; 280 fb.l = b; 281 set_float_exception_flags(0, &env->fp_status); 282 r = float32_lt(fa.f, fb.f, &env->fp_status); 283 flags = get_float_exception_flags(&env->fp_status); 284 update_fpu_flags(env, flags & float_flag_invalid, GETPC()); 285 return r; 286 } 287 288 uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b) 289 { 290 CPU_FloatU fa, fb; 291 int flags, r; 292 293 fa.l = a; 294 fb.l = b; 295 set_float_exception_flags(0, &env->fp_status); 296 r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); 297 flags = get_float_exception_flags(&env->fp_status); 298 update_fpu_flags(env, flags & float_flag_invalid, GETPC()); 299 300 return r; 301 } 302 303 uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b) 304 { 305 CPU_FloatU fa, fb; 306 int flags, r; 307 308 fa.l = a; 309 fb.l = b; 310 set_float_exception_flags(0, &env->fp_status); 311 r = !float32_lt(fa.f, fb.f, &env->fp_status); 312 flags = get_float_exception_flags(&env->fp_status); 313 update_fpu_flags(env, flags & float_flag_invalid, GETPC()); 314 315 return r; 316 } 317 318 uint32_t helper_flt(CPUMBState *env, uint32_t a) 319 { 320 CPU_FloatU fd, fa; 321 322 fa.l = a; 323 fd.f = int32_to_float32(fa.l, &env->fp_status); 324 return fd.l; 325 } 326 327 uint32_t helper_fint(CPUMBState *env, uint32_t a) 328 { 329 CPU_FloatU fa; 330 uint32_t r; 331 int flags; 332 333 set_float_exception_flags(0, &env->fp_status); 334 fa.l = a; 335 r = float32_to_int32(fa.f, &env->fp_status); 336 flags = get_float_exception_flags(&env->fp_status); 337 update_fpu_flags(env, flags, GETPC()); 338 339 return r; 340 } 341 342 uint32_t helper_fsqrt(CPUMBState *env, uint32_t a) 343 { 344 CPU_FloatU fd, fa; 345 int flags; 346 347 set_float_exception_flags(0, &env->fp_status); 348 fa.l = a; 349 fd.l = float32_sqrt(fa.f, &env->fp_status); 350 flags = get_float_exception_flags(&env->fp_status); 351 update_fpu_flags(env, flags, GETPC()); 352 353 return fd.l; 354 } 355 356 uint32_t helper_pcmpbf(uint32_t a, uint32_t b) 357 { 358 unsigned int i; 359 uint32_t mask = 0xff000000; 360 361 for (i = 0; i < 4; i++) { 362 if ((a & mask) == (b & mask)) 363 return i + 1; 364 mask >>= 8; 365 } 366 return 0; 367 } 368 369 void helper_stackprot(CPUMBState *env, target_ulong addr) 370 { 371 if (addr < env->slr || addr > env->shr) { 372 CPUState *cs = env_cpu(env); 373 374 qemu_log_mask(CPU_LOG_INT, "Stack protector violation at " 375 TARGET_FMT_lx " %x %x\n", 376 addr, env->slr, env->shr); 377 378 env->ear = addr; 379 env->esr = ESR_EC_STACKPROT; 380 cs->exception_index = EXCP_HW_EXCP; 381 cpu_loop_exit_restore(cs, GETPC()); 382 } 383 } 384 385 #if !defined(CONFIG_USER_ONLY) 386 /* Writes/reads to the MMU's special regs end up here. */ 387 uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn) 388 { 389 return mmu_read(env, ext, rn); 390 } 391 392 void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v) 393 { 394 mmu_write(env, ext, rn, v); 395 } 396 397 void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, 398 unsigned size, MMUAccessType access_type, 399 int mmu_idx, MemTxAttrs attrs, 400 MemTxResult response, uintptr_t retaddr) 401 { 402 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 403 CPUMBState *env = &cpu->env; 404 405 qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx 406 " physaddr 0x" TARGET_FMT_plx " size %d access type %s\n", 407 addr, physaddr, size, 408 access_type == MMU_INST_FETCH ? "INST_FETCH" : 409 (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE")); 410 411 if (!(env->msr & MSR_EE)) { 412 return; 413 } 414 415 if (access_type == MMU_INST_FETCH) { 416 if (!cpu->cfg.iopb_bus_exception) { 417 return; 418 } 419 env->esr = ESR_EC_INSN_BUS; 420 } else { 421 if (!cpu->cfg.dopb_bus_exception) { 422 return; 423 } 424 env->esr = ESR_EC_DATA_BUS; 425 } 426 427 env->ear = addr; 428 cs->exception_index = EXCP_HW_EXCP; 429 cpu_loop_exit_restore(cs, retaddr); 430 } 431 #endif 432