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 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 "cpu.h" 23 #include "exec/helper-proto.h" 24 #include "qemu/host-utils.h" 25 #include "exec/exec-all.h" 26 #include "exec/cpu_ldst.h" 27 #include "fpu/softfloat.h" 28 29 #define D(x) 30 31 void helper_put(uint32_t id, uint32_t ctrl, uint32_t data) 32 { 33 int test = ctrl & STREAM_TEST; 34 int atomic = ctrl & STREAM_ATOMIC; 35 int control = ctrl & STREAM_CONTROL; 36 int nonblock = ctrl & STREAM_NONBLOCK; 37 int exception = ctrl & STREAM_EXCEPTION; 38 39 qemu_log_mask(LOG_UNIMP, "Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n", 40 id, data, 41 test ? "t" : "", 42 nonblock ? "n" : "", 43 exception ? "e" : "", 44 control ? "c" : "", 45 atomic ? "a" : ""); 46 } 47 48 uint32_t helper_get(uint32_t id, uint32_t ctrl) 49 { 50 int test = ctrl & STREAM_TEST; 51 int atomic = ctrl & STREAM_ATOMIC; 52 int control = ctrl & STREAM_CONTROL; 53 int nonblock = ctrl & STREAM_NONBLOCK; 54 int exception = ctrl & STREAM_EXCEPTION; 55 56 qemu_log_mask(LOG_UNIMP, "Unhandled stream get from stream-id=%d %s%s%s%s%s\n", 57 id, 58 test ? "t" : "", 59 nonblock ? "n" : "", 60 exception ? "e" : "", 61 control ? "c" : "", 62 atomic ? "a" : ""); 63 return 0xdead0000 | id; 64 } 65 66 void helper_raise_exception(CPUMBState *env, uint32_t index) 67 { 68 CPUState *cs = env_cpu(env); 69 70 cs->exception_index = index; 71 cpu_loop_exit(cs); 72 } 73 74 void helper_debug(CPUMBState *env) 75 { 76 int i; 77 78 qemu_log("PC=%" PRIx64 "\n", env->sregs[SR_PC]); 79 qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " 80 "debug[%x] imm=%x iflags=%x\n", 81 env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], 82 env->debug, env->imm, env->iflags); 83 qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n", 84 env->btaken, env->btarget, 85 (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", 86 (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", 87 (bool)(env->sregs[SR_MSR] & MSR_EIP), 88 (bool)(env->sregs[SR_MSR] & MSR_IE)); 89 for (i = 0; i < 32; i++) { 90 qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); 91 if ((i + 1) % 4 == 0) 92 qemu_log("\n"); 93 } 94 qemu_log("\n\n"); 95 } 96 97 static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin) 98 { 99 uint32_t cout = 0; 100 101 if ((b == ~0) && cin) 102 cout = 1; 103 else if ((~0 - a) < (b + cin)) 104 cout = 1; 105 return cout; 106 } 107 108 uint32_t helper_cmp(uint32_t a, uint32_t b) 109 { 110 uint32_t t; 111 112 t = b + ~a + 1; 113 if ((b & 0x80000000) ^ (a & 0x80000000)) 114 t = (t & 0x7fffffff) | (b & 0x80000000); 115 return t; 116 } 117 118 uint32_t helper_cmpu(uint32_t a, uint32_t b) 119 { 120 uint32_t t; 121 122 t = b + ~a + 1; 123 if ((b & 0x80000000) ^ (a & 0x80000000)) 124 t = (t & 0x7fffffff) | (a & 0x80000000); 125 return t; 126 } 127 128 uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf) 129 { 130 return compute_carry(a, b, cf); 131 } 132 133 static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b) 134 { 135 MicroBlazeCPU *cpu = env_archcpu(env); 136 137 if (b == 0) { 138 env->sregs[SR_MSR] |= MSR_DZ; 139 140 if ((env->sregs[SR_MSR] & MSR_EE) && cpu->cfg.div_zero_exception) { 141 env->sregs[SR_ESR] = ESR_EC_DIVZERO; 142 helper_raise_exception(env, EXCP_HW_EXCP); 143 } 144 return 0; 145 } 146 env->sregs[SR_MSR] &= ~MSR_DZ; 147 return 1; 148 } 149 150 uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b) 151 { 152 if (!div_prepare(env, a, b)) { 153 return 0; 154 } 155 return (int32_t)a / (int32_t)b; 156 } 157 158 uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b) 159 { 160 if (!div_prepare(env, a, b)) { 161 return 0; 162 } 163 return a / b; 164 } 165 166 /* raise FPU exception. */ 167 static void raise_fpu_exception(CPUMBState *env) 168 { 169 env->sregs[SR_ESR] = ESR_EC_FPU; 170 helper_raise_exception(env, EXCP_HW_EXCP); 171 } 172 173 static void update_fpu_flags(CPUMBState *env, int flags) 174 { 175 int raise = 0; 176 177 if (flags & float_flag_invalid) { 178 env->sregs[SR_FSR] |= FSR_IO; 179 raise = 1; 180 } 181 if (flags & float_flag_divbyzero) { 182 env->sregs[SR_FSR] |= FSR_DZ; 183 raise = 1; 184 } 185 if (flags & float_flag_overflow) { 186 env->sregs[SR_FSR] |= FSR_OF; 187 raise = 1; 188 } 189 if (flags & float_flag_underflow) { 190 env->sregs[SR_FSR] |= FSR_UF; 191 raise = 1; 192 } 193 if (raise 194 && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) 195 && (env->sregs[SR_MSR] & MSR_EE)) { 196 raise_fpu_exception(env); 197 } 198 } 199 200 uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b) 201 { 202 CPU_FloatU fd, fa, fb; 203 int flags; 204 205 set_float_exception_flags(0, &env->fp_status); 206 fa.l = a; 207 fb.l = b; 208 fd.f = float32_add(fa.f, fb.f, &env->fp_status); 209 210 flags = get_float_exception_flags(&env->fp_status); 211 update_fpu_flags(env, flags); 212 return fd.l; 213 } 214 215 uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b) 216 { 217 CPU_FloatU fd, fa, fb; 218 int flags; 219 220 set_float_exception_flags(0, &env->fp_status); 221 fa.l = a; 222 fb.l = b; 223 fd.f = float32_sub(fb.f, fa.f, &env->fp_status); 224 flags = get_float_exception_flags(&env->fp_status); 225 update_fpu_flags(env, flags); 226 return fd.l; 227 } 228 229 uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b) 230 { 231 CPU_FloatU fd, fa, fb; 232 int flags; 233 234 set_float_exception_flags(0, &env->fp_status); 235 fa.l = a; 236 fb.l = b; 237 fd.f = float32_mul(fa.f, fb.f, &env->fp_status); 238 flags = get_float_exception_flags(&env->fp_status); 239 update_fpu_flags(env, flags); 240 241 return fd.l; 242 } 243 244 uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b) 245 { 246 CPU_FloatU fd, fa, fb; 247 int flags; 248 249 set_float_exception_flags(0, &env->fp_status); 250 fa.l = a; 251 fb.l = b; 252 fd.f = float32_div(fb.f, fa.f, &env->fp_status); 253 flags = get_float_exception_flags(&env->fp_status); 254 update_fpu_flags(env, flags); 255 256 return fd.l; 257 } 258 259 uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b) 260 { 261 CPU_FloatU fa, fb; 262 uint32_t r = 0; 263 264 fa.l = a; 265 fb.l = b; 266 267 if (float32_is_signaling_nan(fa.f, &env->fp_status) || 268 float32_is_signaling_nan(fb.f, &env->fp_status)) { 269 update_fpu_flags(env, float_flag_invalid); 270 r = 1; 271 } 272 273 if (float32_is_quiet_nan(fa.f, &env->fp_status) || 274 float32_is_quiet_nan(fb.f, &env->fp_status)) { 275 r = 1; 276 } 277 278 return r; 279 } 280 281 uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b) 282 { 283 CPU_FloatU fa, fb; 284 int r; 285 int flags; 286 287 set_float_exception_flags(0, &env->fp_status); 288 fa.l = a; 289 fb.l = b; 290 r = float32_lt(fb.f, fa.f, &env->fp_status); 291 flags = get_float_exception_flags(&env->fp_status); 292 update_fpu_flags(env, flags & float_flag_invalid); 293 294 return r; 295 } 296 297 uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b) 298 { 299 CPU_FloatU fa, fb; 300 int flags; 301 int r; 302 303 set_float_exception_flags(0, &env->fp_status); 304 fa.l = a; 305 fb.l = b; 306 r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); 307 flags = get_float_exception_flags(&env->fp_status); 308 update_fpu_flags(env, flags & float_flag_invalid); 309 310 return r; 311 } 312 313 uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b) 314 { 315 CPU_FloatU fa, fb; 316 int flags; 317 int r; 318 319 fa.l = a; 320 fb.l = b; 321 set_float_exception_flags(0, &env->fp_status); 322 r = float32_le(fa.f, fb.f, &env->fp_status); 323 flags = get_float_exception_flags(&env->fp_status); 324 update_fpu_flags(env, flags & float_flag_invalid); 325 326 327 return r; 328 } 329 330 uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b) 331 { 332 CPU_FloatU fa, fb; 333 int flags, r; 334 335 fa.l = a; 336 fb.l = b; 337 set_float_exception_flags(0, &env->fp_status); 338 r = float32_lt(fa.f, fb.f, &env->fp_status); 339 flags = get_float_exception_flags(&env->fp_status); 340 update_fpu_flags(env, flags & float_flag_invalid); 341 return r; 342 } 343 344 uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b) 345 { 346 CPU_FloatU fa, fb; 347 int flags, r; 348 349 fa.l = a; 350 fb.l = b; 351 set_float_exception_flags(0, &env->fp_status); 352 r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); 353 flags = get_float_exception_flags(&env->fp_status); 354 update_fpu_flags(env, flags & float_flag_invalid); 355 356 return r; 357 } 358 359 uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b) 360 { 361 CPU_FloatU fa, fb; 362 int flags, r; 363 364 fa.l = a; 365 fb.l = b; 366 set_float_exception_flags(0, &env->fp_status); 367 r = !float32_lt(fa.f, fb.f, &env->fp_status); 368 flags = get_float_exception_flags(&env->fp_status); 369 update_fpu_flags(env, flags & float_flag_invalid); 370 371 return r; 372 } 373 374 uint32_t helper_flt(CPUMBState *env, uint32_t a) 375 { 376 CPU_FloatU fd, fa; 377 378 fa.l = a; 379 fd.f = int32_to_float32(fa.l, &env->fp_status); 380 return fd.l; 381 } 382 383 uint32_t helper_fint(CPUMBState *env, uint32_t a) 384 { 385 CPU_FloatU fa; 386 uint32_t r; 387 int flags; 388 389 set_float_exception_flags(0, &env->fp_status); 390 fa.l = a; 391 r = float32_to_int32(fa.f, &env->fp_status); 392 flags = get_float_exception_flags(&env->fp_status); 393 update_fpu_flags(env, flags); 394 395 return r; 396 } 397 398 uint32_t helper_fsqrt(CPUMBState *env, uint32_t a) 399 { 400 CPU_FloatU fd, fa; 401 int flags; 402 403 set_float_exception_flags(0, &env->fp_status); 404 fa.l = a; 405 fd.l = float32_sqrt(fa.f, &env->fp_status); 406 flags = get_float_exception_flags(&env->fp_status); 407 update_fpu_flags(env, flags); 408 409 return fd.l; 410 } 411 412 uint32_t helper_pcmpbf(uint32_t a, uint32_t b) 413 { 414 unsigned int i; 415 uint32_t mask = 0xff000000; 416 417 for (i = 0; i < 4; i++) { 418 if ((a & mask) == (b & mask)) 419 return i + 1; 420 mask >>= 8; 421 } 422 return 0; 423 } 424 425 void helper_memalign(CPUMBState *env, target_ulong addr, 426 uint32_t dr, uint32_t wr, 427 uint32_t mask) 428 { 429 if (addr & mask) { 430 qemu_log_mask(CPU_LOG_INT, 431 "unaligned access addr=" TARGET_FMT_lx 432 " mask=%x, wr=%d dr=r%d\n", 433 addr, mask, wr, dr); 434 env->sregs[SR_EAR] = addr; 435 env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \ 436 | (dr & 31) << 5; 437 if (mask == 3) { 438 env->sregs[SR_ESR] |= 1 << 11; 439 } 440 if (!(env->sregs[SR_MSR] & MSR_EE)) { 441 return; 442 } 443 helper_raise_exception(env, EXCP_HW_EXCP); 444 } 445 } 446 447 void helper_stackprot(CPUMBState *env, target_ulong addr) 448 { 449 if (addr < env->slr || addr > env->shr) { 450 qemu_log_mask(CPU_LOG_INT, "Stack protector violation at " 451 TARGET_FMT_lx " %x %x\n", 452 addr, env->slr, env->shr); 453 env->sregs[SR_EAR] = addr; 454 env->sregs[SR_ESR] = ESR_EC_STACKPROT; 455 helper_raise_exception(env, EXCP_HW_EXCP); 456 } 457 } 458 459 #if !defined(CONFIG_USER_ONLY) 460 /* Writes/reads to the MMU's special regs end up here. */ 461 uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn) 462 { 463 return mmu_read(env, ext, rn); 464 } 465 466 void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v) 467 { 468 mmu_write(env, ext, rn, v); 469 } 470 471 void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, 472 unsigned size, MMUAccessType access_type, 473 int mmu_idx, MemTxAttrs attrs, 474 MemTxResult response, uintptr_t retaddr) 475 { 476 MicroBlazeCPU *cpu; 477 CPUMBState *env; 478 qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx 479 " physaddr 0x" TARGET_FMT_plx " size %d access type %s\n", 480 addr, physaddr, size, 481 access_type == MMU_INST_FETCH ? "INST_FETCH" : 482 (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE")); 483 cpu = MICROBLAZE_CPU(cs); 484 env = &cpu->env; 485 486 cpu_restore_state(cs, retaddr, true); 487 if (!(env->sregs[SR_MSR] & MSR_EE)) { 488 return; 489 } 490 491 env->sregs[SR_EAR] = addr; 492 if (access_type == MMU_INST_FETCH) { 493 if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { 494 env->sregs[SR_ESR] = ESR_EC_INSN_BUS; 495 helper_raise_exception(env, EXCP_HW_EXCP); 496 } 497 } else { 498 if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { 499 env->sregs[SR_ESR] = ESR_EC_DATA_BUS; 500 helper_raise_exception(env, EXCP_HW_EXCP); 501 } 502 } 503 } 504 #endif 505