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