1 /* 2 * Helpers for HPPA instructions. 3 * 4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net> 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 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 #include "qemu/osdep.h" 21 #include "cpu.h" 22 #include "exec/exec-all.h" 23 #include "exec/helper-proto.h" 24 #include "exec/cpu_ldst.h" 25 26 void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp) 27 { 28 HPPACPU *cpu = hppa_env_get_cpu(env); 29 CPUState *cs = CPU(cpu); 30 31 cs->exception_index = excp; 32 cpu_loop_exit(cs); 33 } 34 35 static void QEMU_NORETURN dynexcp(CPUHPPAState *env, int excp, uintptr_t ra) 36 { 37 HPPACPU *cpu = hppa_env_get_cpu(env); 38 CPUState *cs = CPU(cpu); 39 40 cs->exception_index = excp; 41 cpu_loop_exit_restore(cs, ra); 42 } 43 44 void HELPER(tsv)(CPUHPPAState *env, target_ulong cond) 45 { 46 if (unlikely((target_long)cond < 0)) { 47 dynexcp(env, EXCP_SIGFPE, GETPC()); 48 } 49 } 50 51 void HELPER(tcond)(CPUHPPAState *env, target_ulong cond) 52 { 53 if (unlikely(cond)) { 54 dynexcp(env, EXCP_SIGFPE, GETPC()); 55 } 56 } 57 58 static void atomic_store_3(CPUHPPAState *env, target_ulong addr, uint32_t val, 59 uint32_t mask, uintptr_t ra) 60 { 61 uint32_t old, new, cmp; 62 63 #ifdef CONFIG_USER_ONLY 64 uint32_t *haddr = g2h(addr - 1); 65 old = *haddr; 66 while (1) { 67 new = (old & ~mask) | (val & mask); 68 cmp = atomic_cmpxchg(haddr, old, new); 69 if (cmp == old) { 70 return; 71 } 72 old = cmp; 73 } 74 #else 75 #error "Not implemented." 76 #endif 77 } 78 79 void HELPER(stby_b)(CPUHPPAState *env, target_ulong addr, target_ulong val) 80 { 81 uintptr_t ra = GETPC(); 82 83 switch (addr & 3) { 84 case 3: 85 cpu_stb_data_ra(env, addr, val, ra); 86 break; 87 case 2: 88 cpu_stw_data_ra(env, addr, val, ra); 89 break; 90 case 1: 91 /* The 3 byte store must appear atomic. */ 92 if (parallel_cpus) { 93 atomic_store_3(env, addr, val, 0x00ffffffu, ra); 94 } else { 95 cpu_stb_data_ra(env, addr, val >> 16, ra); 96 cpu_stw_data_ra(env, addr + 1, val, ra); 97 } 98 break; 99 default: 100 cpu_stl_data_ra(env, addr, val, ra); 101 break; 102 } 103 } 104 105 void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ulong val) 106 { 107 uintptr_t ra = GETPC(); 108 109 switch (addr & 3) { 110 case 3: 111 /* The 3 byte store must appear atomic. */ 112 if (parallel_cpus) { 113 atomic_store_3(env, addr - 3, val, 0xffffff00u, ra); 114 } else { 115 cpu_stw_data_ra(env, addr - 3, val >> 16, ra); 116 cpu_stb_data_ra(env, addr - 1, val >> 8, ra); 117 } 118 break; 119 case 2: 120 cpu_stw_data_ra(env, addr - 2, val >> 16, ra); 121 break; 122 case 1: 123 cpu_stb_data_ra(env, addr - 1, val >> 24, ra); 124 break; 125 default: 126 /* Nothing is stored, but protection is checked and the 127 cacheline is marked dirty. */ 128 #ifndef CONFIG_USER_ONLY 129 probe_write(env, addr, cpu_mmu_index(env, 0), ra); 130 #endif 131 break; 132 } 133 } 134 135 target_ulong HELPER(probe_r)(target_ulong addr) 136 { 137 return page_check_range(addr, 1, PAGE_READ); 138 } 139 140 target_ulong HELPER(probe_w)(target_ulong addr) 141 { 142 return page_check_range(addr, 1, PAGE_WRITE); 143 } 144 145 void HELPER(loaded_fr0)(CPUHPPAState *env) 146 { 147 uint32_t shadow = env->fr[0] >> 32; 148 int rm, d; 149 150 env->fr0_shadow = shadow; 151 152 switch (extract32(shadow, 9, 2)) { 153 default: 154 rm = float_round_nearest_even; 155 break; 156 case 1: 157 rm = float_round_to_zero; 158 break; 159 case 2: 160 rm = float_round_up; 161 break; 162 case 3: 163 rm = float_round_down; 164 break; 165 } 166 set_float_rounding_mode(rm, &env->fp_status); 167 168 d = extract32(shadow, 5, 1); 169 set_flush_to_zero(d, &env->fp_status); 170 set_flush_inputs_to_zero(d, &env->fp_status); 171 } 172 173 void cpu_hppa_loaded_fr0(CPUHPPAState *env) 174 { 175 helper_loaded_fr0(env); 176 } 177 178 #define CONVERT_BIT(X, SRC, DST) \ 179 ((SRC) > (DST) \ 180 ? (X) / ((SRC) / (DST)) & (DST) \ 181 : ((X) & (SRC)) * ((DST) / (SRC))) 182 183 static void update_fr0_op(CPUHPPAState *env, uintptr_t ra) 184 { 185 uint32_t soft_exp = get_float_exception_flags(&env->fp_status); 186 uint32_t hard_exp = 0; 187 uint32_t shadow = env->fr0_shadow; 188 189 if (likely(soft_exp == 0)) { 190 env->fr[0] = (uint64_t)shadow << 32; 191 return; 192 } 193 set_float_exception_flags(0, &env->fp_status); 194 195 hard_exp |= CONVERT_BIT(soft_exp, float_flag_inexact, 1u << 0); 196 hard_exp |= CONVERT_BIT(soft_exp, float_flag_underflow, 1u << 1); 197 hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, 1u << 2); 198 hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, 1u << 3); 199 hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, 1u << 4); 200 shadow |= hard_exp << (32 - 5); 201 env->fr0_shadow = shadow; 202 env->fr[0] = (uint64_t)shadow << 32; 203 204 if (hard_exp & shadow) { 205 dynexcp(env, EXCP_SIGFPE, ra); 206 } 207 } 208 209 float32 HELPER(fsqrt_s)(CPUHPPAState *env, float32 arg) 210 { 211 float32 ret = float32_sqrt(arg, &env->fp_status); 212 update_fr0_op(env, GETPC()); 213 return ret; 214 } 215 216 float32 HELPER(frnd_s)(CPUHPPAState *env, float32 arg) 217 { 218 float32 ret = float32_round_to_int(arg, &env->fp_status); 219 update_fr0_op(env, GETPC()); 220 return ret; 221 } 222 223 float32 HELPER(fadd_s)(CPUHPPAState *env, float32 a, float32 b) 224 { 225 float32 ret = float32_add(a, b, &env->fp_status); 226 update_fr0_op(env, GETPC()); 227 return ret; 228 } 229 230 float32 HELPER(fsub_s)(CPUHPPAState *env, float32 a, float32 b) 231 { 232 float32 ret = float32_sub(a, b, &env->fp_status); 233 update_fr0_op(env, GETPC()); 234 return ret; 235 } 236 237 float32 HELPER(fmpy_s)(CPUHPPAState *env, float32 a, float32 b) 238 { 239 float32 ret = float32_mul(a, b, &env->fp_status); 240 update_fr0_op(env, GETPC()); 241 return ret; 242 } 243 244 float32 HELPER(fdiv_s)(CPUHPPAState *env, float32 a, float32 b) 245 { 246 float32 ret = float32_div(a, b, &env->fp_status); 247 update_fr0_op(env, GETPC()); 248 return ret; 249 } 250 251 float64 HELPER(fsqrt_d)(CPUHPPAState *env, float64 arg) 252 { 253 float64 ret = float64_sqrt(arg, &env->fp_status); 254 update_fr0_op(env, GETPC()); 255 return ret; 256 } 257 258 float64 HELPER(frnd_d)(CPUHPPAState *env, float64 arg) 259 { 260 float64 ret = float64_round_to_int(arg, &env->fp_status); 261 update_fr0_op(env, GETPC()); 262 return ret; 263 } 264 265 float64 HELPER(fadd_d)(CPUHPPAState *env, float64 a, float64 b) 266 { 267 float64 ret = float64_add(a, b, &env->fp_status); 268 update_fr0_op(env, GETPC()); 269 return ret; 270 } 271 272 float64 HELPER(fsub_d)(CPUHPPAState *env, float64 a, float64 b) 273 { 274 float64 ret = float64_sub(a, b, &env->fp_status); 275 update_fr0_op(env, GETPC()); 276 return ret; 277 } 278 279 float64 HELPER(fmpy_d)(CPUHPPAState *env, float64 a, float64 b) 280 { 281 float64 ret = float64_mul(a, b, &env->fp_status); 282 update_fr0_op(env, GETPC()); 283 return ret; 284 } 285 286 float64 HELPER(fdiv_d)(CPUHPPAState *env, float64 a, float64 b) 287 { 288 float64 ret = float64_div(a, b, &env->fp_status); 289 update_fr0_op(env, GETPC()); 290 return ret; 291 } 292 293 float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg) 294 { 295 float64 ret = float32_to_float64(arg, &env->fp_status); 296 ret = float64_maybe_silence_nan(ret, &env->fp_status); 297 update_fr0_op(env, GETPC()); 298 return ret; 299 } 300 301 float32 HELPER(fcnv_d_s)(CPUHPPAState *env, float64 arg) 302 { 303 float32 ret = float64_to_float32(arg, &env->fp_status); 304 ret = float32_maybe_silence_nan(ret, &env->fp_status); 305 update_fr0_op(env, GETPC()); 306 return ret; 307 } 308 309 float32 HELPER(fcnv_w_s)(CPUHPPAState *env, int32_t arg) 310 { 311 float32 ret = int32_to_float32(arg, &env->fp_status); 312 update_fr0_op(env, GETPC()); 313 return ret; 314 } 315 316 float32 HELPER(fcnv_dw_s)(CPUHPPAState *env, int64_t arg) 317 { 318 float32 ret = int64_to_float32(arg, &env->fp_status); 319 update_fr0_op(env, GETPC()); 320 return ret; 321 } 322 323 float64 HELPER(fcnv_w_d)(CPUHPPAState *env, int32_t arg) 324 { 325 float64 ret = int32_to_float64(arg, &env->fp_status); 326 update_fr0_op(env, GETPC()); 327 return ret; 328 } 329 330 float64 HELPER(fcnv_dw_d)(CPUHPPAState *env, int64_t arg) 331 { 332 float64 ret = int64_to_float64(arg, &env->fp_status); 333 update_fr0_op(env, GETPC()); 334 return ret; 335 } 336 337 int32_t HELPER(fcnv_s_w)(CPUHPPAState *env, float32 arg) 338 { 339 int32_t ret = float32_to_int32(arg, &env->fp_status); 340 update_fr0_op(env, GETPC()); 341 return ret; 342 } 343 344 int32_t HELPER(fcnv_d_w)(CPUHPPAState *env, float64 arg) 345 { 346 int32_t ret = float64_to_int32(arg, &env->fp_status); 347 update_fr0_op(env, GETPC()); 348 return ret; 349 } 350 351 int64_t HELPER(fcnv_s_dw)(CPUHPPAState *env, float32 arg) 352 { 353 int64_t ret = float32_to_int64(arg, &env->fp_status); 354 update_fr0_op(env, GETPC()); 355 return ret; 356 } 357 358 int64_t HELPER(fcnv_d_dw)(CPUHPPAState *env, float64 arg) 359 { 360 int64_t ret = float64_to_int64(arg, &env->fp_status); 361 update_fr0_op(env, GETPC()); 362 return ret; 363 } 364 365 int32_t HELPER(fcnv_t_s_w)(CPUHPPAState *env, float32 arg) 366 { 367 int32_t ret = float32_to_int32_round_to_zero(arg, &env->fp_status); 368 update_fr0_op(env, GETPC()); 369 return ret; 370 } 371 372 int32_t HELPER(fcnv_t_d_w)(CPUHPPAState *env, float64 arg) 373 { 374 int32_t ret = float64_to_int32_round_to_zero(arg, &env->fp_status); 375 update_fr0_op(env, GETPC()); 376 return ret; 377 } 378 379 int64_t HELPER(fcnv_t_s_dw)(CPUHPPAState *env, float32 arg) 380 { 381 int64_t ret = float32_to_int64_round_to_zero(arg, &env->fp_status); 382 update_fr0_op(env, GETPC()); 383 return ret; 384 } 385 386 int64_t HELPER(fcnv_t_d_dw)(CPUHPPAState *env, float64 arg) 387 { 388 int64_t ret = float64_to_int64_round_to_zero(arg, &env->fp_status); 389 update_fr0_op(env, GETPC()); 390 return ret; 391 } 392 393 float32 HELPER(fcnv_uw_s)(CPUHPPAState *env, uint32_t arg) 394 { 395 float32 ret = uint32_to_float32(arg, &env->fp_status); 396 update_fr0_op(env, GETPC()); 397 return ret; 398 } 399 400 float32 HELPER(fcnv_udw_s)(CPUHPPAState *env, uint64_t arg) 401 { 402 float32 ret = uint64_to_float32(arg, &env->fp_status); 403 update_fr0_op(env, GETPC()); 404 return ret; 405 } 406 407 float64 HELPER(fcnv_uw_d)(CPUHPPAState *env, uint32_t arg) 408 { 409 float64 ret = uint32_to_float64(arg, &env->fp_status); 410 update_fr0_op(env, GETPC()); 411 return ret; 412 } 413 414 float64 HELPER(fcnv_udw_d)(CPUHPPAState *env, uint64_t arg) 415 { 416 float64 ret = uint64_to_float64(arg, &env->fp_status); 417 update_fr0_op(env, GETPC()); 418 return ret; 419 } 420 421 uint32_t HELPER(fcnv_s_uw)(CPUHPPAState *env, float32 arg) 422 { 423 uint32_t ret = float32_to_uint32(arg, &env->fp_status); 424 update_fr0_op(env, GETPC()); 425 return ret; 426 } 427 428 uint32_t HELPER(fcnv_d_uw)(CPUHPPAState *env, float64 arg) 429 { 430 uint32_t ret = float64_to_uint32(arg, &env->fp_status); 431 update_fr0_op(env, GETPC()); 432 return ret; 433 } 434 435 uint64_t HELPER(fcnv_s_udw)(CPUHPPAState *env, float32 arg) 436 { 437 uint64_t ret = float32_to_uint64(arg, &env->fp_status); 438 update_fr0_op(env, GETPC()); 439 return ret; 440 } 441 442 uint64_t HELPER(fcnv_d_udw)(CPUHPPAState *env, float64 arg) 443 { 444 uint64_t ret = float64_to_uint64(arg, &env->fp_status); 445 update_fr0_op(env, GETPC()); 446 return ret; 447 } 448 449 uint32_t HELPER(fcnv_t_s_uw)(CPUHPPAState *env, float32 arg) 450 { 451 uint32_t ret = float32_to_uint32_round_to_zero(arg, &env->fp_status); 452 update_fr0_op(env, GETPC()); 453 return ret; 454 } 455 456 uint32_t HELPER(fcnv_t_d_uw)(CPUHPPAState *env, float64 arg) 457 { 458 uint32_t ret = float64_to_uint32_round_to_zero(arg, &env->fp_status); 459 update_fr0_op(env, GETPC()); 460 return ret; 461 } 462 463 uint64_t HELPER(fcnv_t_s_udw)(CPUHPPAState *env, float32 arg) 464 { 465 uint64_t ret = float32_to_uint64_round_to_zero(arg, &env->fp_status); 466 update_fr0_op(env, GETPC()); 467 return ret; 468 } 469 470 uint64_t HELPER(fcnv_t_d_udw)(CPUHPPAState *env, float64 arg) 471 { 472 uint64_t ret = float64_to_uint64_round_to_zero(arg, &env->fp_status); 473 update_fr0_op(env, GETPC()); 474 return ret; 475 } 476 477 static void update_fr0_cmp(CPUHPPAState *env, uint32_t y, uint32_t c, int r) 478 { 479 uint32_t shadow = env->fr0_shadow; 480 481 switch (r) { 482 case float_relation_greater: 483 c = extract32(c, 4, 1); 484 break; 485 case float_relation_less: 486 c = extract32(c, 3, 1); 487 break; 488 case float_relation_equal: 489 c = extract32(c, 2, 1); 490 break; 491 case float_relation_unordered: 492 c = extract32(c, 1, 1); 493 break; 494 default: 495 g_assert_not_reached(); 496 } 497 498 if (y) { 499 /* targeted comparison */ 500 /* set fpsr[ca[y - 1]] to current compare */ 501 shadow = deposit32(shadow, 21 - (y - 1), 1, c); 502 } else { 503 /* queued comparison */ 504 /* shift cq right by one place */ 505 shadow = deposit32(shadow, 11, 10, extract32(shadow, 12, 10)); 506 /* move fpsr[c] to fpsr[cq[0]] */ 507 shadow = deposit32(shadow, 21, 1, extract32(shadow, 26, 1)); 508 /* set fpsr[c] to current compare */ 509 shadow = deposit32(shadow, 26, 1, c); 510 } 511 512 env->fr0_shadow = shadow; 513 env->fr[0] = (uint64_t)shadow << 32; 514 } 515 516 void HELPER(fcmp_s)(CPUHPPAState *env, float32 a, float32 b, 517 uint32_t y, uint32_t c) 518 { 519 int r; 520 if (c & 1) { 521 r = float32_compare(a, b, &env->fp_status); 522 } else { 523 r = float32_compare_quiet(a, b, &env->fp_status); 524 } 525 update_fr0_op(env, GETPC()); 526 update_fr0_cmp(env, y, c, r); 527 } 528 529 void HELPER(fcmp_d)(CPUHPPAState *env, float64 a, float64 b, 530 uint32_t y, uint32_t c) 531 { 532 int r; 533 if (c & 1) { 534 r = float64_compare(a, b, &env->fp_status); 535 } else { 536 r = float64_compare_quiet(a, b, &env->fp_status); 537 } 538 update_fr0_op(env, GETPC()); 539 update_fr0_cmp(env, y, c, r); 540 } 541 542 float32 HELPER(fmpyfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c) 543 { 544 float32 ret = float32_muladd(a, b, c, 0, &env->fp_status); 545 update_fr0_op(env, GETPC()); 546 return ret; 547 } 548 549 float32 HELPER(fmpynfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c) 550 { 551 float32 ret = float32_muladd(a, b, c, float_muladd_negate_product, 552 &env->fp_status); 553 update_fr0_op(env, GETPC()); 554 return ret; 555 } 556 557 float64 HELPER(fmpyfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c) 558 { 559 float64 ret = float64_muladd(a, b, c, 0, &env->fp_status); 560 update_fr0_op(env, GETPC()); 561 return ret; 562 } 563 564 float64 HELPER(fmpynfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c) 565 { 566 float64 ret = float64_muladd(a, b, c, float_muladd_negate_product, 567 &env->fp_status); 568 update_fr0_op(env, GETPC()); 569 return ret; 570 } 571