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