1 /* 2 * Helpers for HPPA FPU 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.1 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 "fpu/softfloat.h" 25 26 void HELPER(loaded_fr0)(CPUHPPAState *env) 27 { 28 uint32_t shadow = env->fr[0] >> 32; 29 int rm, d; 30 31 env->fr0_shadow = shadow; 32 33 switch (FIELD_EX32(shadow, FPSR, RM)) { 34 default: 35 rm = float_round_nearest_even; 36 break; 37 case 1: 38 rm = float_round_to_zero; 39 break; 40 case 2: 41 rm = float_round_up; 42 break; 43 case 3: 44 rm = float_round_down; 45 break; 46 } 47 set_float_rounding_mode(rm, &env->fp_status); 48 49 d = FIELD_EX32(shadow, FPSR, D); 50 set_flush_to_zero(d, &env->fp_status); 51 set_flush_inputs_to_zero(d, &env->fp_status); 52 53 /* 54 * TODO: we only need to do this at CPU reset, but currently 55 * HPPA does note implement a CPU reset method at all... 56 */ 57 set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status); 58 } 59 60 void cpu_hppa_loaded_fr0(CPUHPPAState *env) 61 { 62 helper_loaded_fr0(env); 63 } 64 65 #define CONVERT_BIT(X, SRC, DST) \ 66 ((unsigned)(SRC) > (unsigned)(DST) \ 67 ? (X) / ((SRC) / (DST)) & (DST) \ 68 : ((X) & (SRC)) * ((DST) / (SRC))) 69 70 static void update_fr0_op(CPUHPPAState *env, uintptr_t ra) 71 { 72 uint32_t soft_exp = get_float_exception_flags(&env->fp_status); 73 uint32_t hard_exp = 0; 74 uint32_t shadow = env->fr0_shadow; 75 76 if (likely(soft_exp == 0)) { 77 env->fr[0] = (uint64_t)shadow << 32; 78 return; 79 } 80 set_float_exception_flags(0, &env->fp_status); 81 82 hard_exp |= CONVERT_BIT(soft_exp, float_flag_inexact, R_FPSR_ENA_I_MASK); 83 hard_exp |= CONVERT_BIT(soft_exp, float_flag_underflow, R_FPSR_ENA_U_MASK); 84 hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, R_FPSR_ENA_O_MASK); 85 hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, R_FPSR_ENA_Z_MASK); 86 hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, R_FPSR_ENA_V_MASK); 87 shadow |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT); 88 env->fr0_shadow = shadow; 89 env->fr[0] = (uint64_t)shadow << 32; 90 91 if (hard_exp & shadow) { 92 hppa_dynamic_excp(env, EXCP_ASSIST, ra); 93 } 94 } 95 96 float32 HELPER(fsqrt_s)(CPUHPPAState *env, float32 arg) 97 { 98 float32 ret = float32_sqrt(arg, &env->fp_status); 99 update_fr0_op(env, GETPC()); 100 return ret; 101 } 102 103 float32 HELPER(frnd_s)(CPUHPPAState *env, float32 arg) 104 { 105 float32 ret = float32_round_to_int(arg, &env->fp_status); 106 update_fr0_op(env, GETPC()); 107 return ret; 108 } 109 110 float32 HELPER(fadd_s)(CPUHPPAState *env, float32 a, float32 b) 111 { 112 float32 ret = float32_add(a, b, &env->fp_status); 113 update_fr0_op(env, GETPC()); 114 return ret; 115 } 116 117 float32 HELPER(fsub_s)(CPUHPPAState *env, float32 a, float32 b) 118 { 119 float32 ret = float32_sub(a, b, &env->fp_status); 120 update_fr0_op(env, GETPC()); 121 return ret; 122 } 123 124 float32 HELPER(fmpy_s)(CPUHPPAState *env, float32 a, float32 b) 125 { 126 float32 ret = float32_mul(a, b, &env->fp_status); 127 update_fr0_op(env, GETPC()); 128 return ret; 129 } 130 131 float32 HELPER(fdiv_s)(CPUHPPAState *env, float32 a, float32 b) 132 { 133 float32 ret = float32_div(a, b, &env->fp_status); 134 update_fr0_op(env, GETPC()); 135 return ret; 136 } 137 138 float64 HELPER(fsqrt_d)(CPUHPPAState *env, float64 arg) 139 { 140 float64 ret = float64_sqrt(arg, &env->fp_status); 141 update_fr0_op(env, GETPC()); 142 return ret; 143 } 144 145 float64 HELPER(frnd_d)(CPUHPPAState *env, float64 arg) 146 { 147 float64 ret = float64_round_to_int(arg, &env->fp_status); 148 update_fr0_op(env, GETPC()); 149 return ret; 150 } 151 152 float64 HELPER(fadd_d)(CPUHPPAState *env, float64 a, float64 b) 153 { 154 float64 ret = float64_add(a, b, &env->fp_status); 155 update_fr0_op(env, GETPC()); 156 return ret; 157 } 158 159 float64 HELPER(fsub_d)(CPUHPPAState *env, float64 a, float64 b) 160 { 161 float64 ret = float64_sub(a, b, &env->fp_status); 162 update_fr0_op(env, GETPC()); 163 return ret; 164 } 165 166 float64 HELPER(fmpy_d)(CPUHPPAState *env, float64 a, float64 b) 167 { 168 float64 ret = float64_mul(a, b, &env->fp_status); 169 update_fr0_op(env, GETPC()); 170 return ret; 171 } 172 173 float64 HELPER(fdiv_d)(CPUHPPAState *env, float64 a, float64 b) 174 { 175 float64 ret = float64_div(a, b, &env->fp_status); 176 update_fr0_op(env, GETPC()); 177 return ret; 178 } 179 180 float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg) 181 { 182 float64 ret = float32_to_float64(arg, &env->fp_status); 183 update_fr0_op(env, GETPC()); 184 return ret; 185 } 186 187 float32 HELPER(fcnv_d_s)(CPUHPPAState *env, float64 arg) 188 { 189 float32 ret = float64_to_float32(arg, &env->fp_status); 190 update_fr0_op(env, GETPC()); 191 return ret; 192 } 193 194 float32 HELPER(fcnv_w_s)(CPUHPPAState *env, int32_t arg) 195 { 196 float32 ret = int32_to_float32(arg, &env->fp_status); 197 update_fr0_op(env, GETPC()); 198 return ret; 199 } 200 201 float32 HELPER(fcnv_dw_s)(CPUHPPAState *env, int64_t arg) 202 { 203 float32 ret = int64_to_float32(arg, &env->fp_status); 204 update_fr0_op(env, GETPC()); 205 return ret; 206 } 207 208 float64 HELPER(fcnv_w_d)(CPUHPPAState *env, int32_t arg) 209 { 210 float64 ret = int32_to_float64(arg, &env->fp_status); 211 update_fr0_op(env, GETPC()); 212 return ret; 213 } 214 215 float64 HELPER(fcnv_dw_d)(CPUHPPAState *env, int64_t arg) 216 { 217 float64 ret = int64_to_float64(arg, &env->fp_status); 218 update_fr0_op(env, GETPC()); 219 return ret; 220 } 221 222 int32_t HELPER(fcnv_s_w)(CPUHPPAState *env, float32 arg) 223 { 224 int32_t ret = float32_to_int32(arg, &env->fp_status); 225 update_fr0_op(env, GETPC()); 226 return ret; 227 } 228 229 int32_t HELPER(fcnv_d_w)(CPUHPPAState *env, float64 arg) 230 { 231 int32_t ret = float64_to_int32(arg, &env->fp_status); 232 update_fr0_op(env, GETPC()); 233 return ret; 234 } 235 236 int64_t HELPER(fcnv_s_dw)(CPUHPPAState *env, float32 arg) 237 { 238 int64_t ret = float32_to_int64(arg, &env->fp_status); 239 update_fr0_op(env, GETPC()); 240 return ret; 241 } 242 243 int64_t HELPER(fcnv_d_dw)(CPUHPPAState *env, float64 arg) 244 { 245 int64_t ret = float64_to_int64(arg, &env->fp_status); 246 update_fr0_op(env, GETPC()); 247 return ret; 248 } 249 250 int32_t HELPER(fcnv_t_s_w)(CPUHPPAState *env, float32 arg) 251 { 252 int32_t ret = float32_to_int32_round_to_zero(arg, &env->fp_status); 253 update_fr0_op(env, GETPC()); 254 return ret; 255 } 256 257 int32_t HELPER(fcnv_t_d_w)(CPUHPPAState *env, float64 arg) 258 { 259 int32_t ret = float64_to_int32_round_to_zero(arg, &env->fp_status); 260 update_fr0_op(env, GETPC()); 261 return ret; 262 } 263 264 int64_t HELPER(fcnv_t_s_dw)(CPUHPPAState *env, float32 arg) 265 { 266 int64_t ret = float32_to_int64_round_to_zero(arg, &env->fp_status); 267 update_fr0_op(env, GETPC()); 268 return ret; 269 } 270 271 int64_t HELPER(fcnv_t_d_dw)(CPUHPPAState *env, float64 arg) 272 { 273 int64_t ret = float64_to_int64_round_to_zero(arg, &env->fp_status); 274 update_fr0_op(env, GETPC()); 275 return ret; 276 } 277 278 float32 HELPER(fcnv_uw_s)(CPUHPPAState *env, uint32_t arg) 279 { 280 float32 ret = uint32_to_float32(arg, &env->fp_status); 281 update_fr0_op(env, GETPC()); 282 return ret; 283 } 284 285 float32 HELPER(fcnv_udw_s)(CPUHPPAState *env, uint64_t arg) 286 { 287 float32 ret = uint64_to_float32(arg, &env->fp_status); 288 update_fr0_op(env, GETPC()); 289 return ret; 290 } 291 292 float64 HELPER(fcnv_uw_d)(CPUHPPAState *env, uint32_t arg) 293 { 294 float64 ret = uint32_to_float64(arg, &env->fp_status); 295 update_fr0_op(env, GETPC()); 296 return ret; 297 } 298 299 float64 HELPER(fcnv_udw_d)(CPUHPPAState *env, uint64_t arg) 300 { 301 float64 ret = uint64_to_float64(arg, &env->fp_status); 302 update_fr0_op(env, GETPC()); 303 return ret; 304 } 305 306 uint32_t HELPER(fcnv_s_uw)(CPUHPPAState *env, float32 arg) 307 { 308 uint32_t ret = float32_to_uint32(arg, &env->fp_status); 309 update_fr0_op(env, GETPC()); 310 return ret; 311 } 312 313 uint32_t HELPER(fcnv_d_uw)(CPUHPPAState *env, float64 arg) 314 { 315 uint32_t ret = float64_to_uint32(arg, &env->fp_status); 316 update_fr0_op(env, GETPC()); 317 return ret; 318 } 319 320 uint64_t HELPER(fcnv_s_udw)(CPUHPPAState *env, float32 arg) 321 { 322 uint64_t ret = float32_to_uint64(arg, &env->fp_status); 323 update_fr0_op(env, GETPC()); 324 return ret; 325 } 326 327 uint64_t HELPER(fcnv_d_udw)(CPUHPPAState *env, float64 arg) 328 { 329 uint64_t ret = float64_to_uint64(arg, &env->fp_status); 330 update_fr0_op(env, GETPC()); 331 return ret; 332 } 333 334 uint32_t HELPER(fcnv_t_s_uw)(CPUHPPAState *env, float32 arg) 335 { 336 uint32_t ret = float32_to_uint32_round_to_zero(arg, &env->fp_status); 337 update_fr0_op(env, GETPC()); 338 return ret; 339 } 340 341 uint32_t HELPER(fcnv_t_d_uw)(CPUHPPAState *env, float64 arg) 342 { 343 uint32_t ret = float64_to_uint32_round_to_zero(arg, &env->fp_status); 344 update_fr0_op(env, GETPC()); 345 return ret; 346 } 347 348 uint64_t HELPER(fcnv_t_s_udw)(CPUHPPAState *env, float32 arg) 349 { 350 uint64_t ret = float32_to_uint64_round_to_zero(arg, &env->fp_status); 351 update_fr0_op(env, GETPC()); 352 return ret; 353 } 354 355 uint64_t HELPER(fcnv_t_d_udw)(CPUHPPAState *env, float64 arg) 356 { 357 uint64_t ret = float64_to_uint64_round_to_zero(arg, &env->fp_status); 358 update_fr0_op(env, GETPC()); 359 return ret; 360 } 361 362 static void update_fr0_cmp(CPUHPPAState *env, uint32_t y, 363 uint32_t c, FloatRelation r) 364 { 365 uint32_t shadow = env->fr0_shadow; 366 367 switch (r) { 368 case float_relation_greater: 369 c = extract32(c, 4, 1); 370 break; 371 case float_relation_less: 372 c = extract32(c, 3, 1); 373 break; 374 case float_relation_equal: 375 c = extract32(c, 2, 1); 376 break; 377 case float_relation_unordered: 378 c = extract32(c, 1, 1); 379 break; 380 default: 381 g_assert_not_reached(); 382 } 383 384 if (y) { 385 /* targeted comparison */ 386 /* set fpsr[ca[y - 1]] to current compare */ 387 shadow = deposit32(shadow, R_FPSR_CA0_SHIFT - (y - 1), 1, c); 388 } else { 389 /* queued comparison */ 390 /* shift cq right by one place */ 391 shadow = (shadow & ~R_FPSR_CQ_MASK) | ((shadow >> 1) & R_FPSR_CQ_MASK); 392 /* move fpsr[c] to fpsr[cq[0]] */ 393 shadow = FIELD_DP32(shadow, FPSR, CQ0, FIELD_EX32(shadow, FPSR, C)); 394 /* set fpsr[c] to current compare */ 395 shadow = FIELD_DP32(shadow, FPSR, C, c); 396 } 397 398 env->fr0_shadow = shadow; 399 env->fr[0] = (uint64_t)shadow << 32; 400 } 401 402 void HELPER(fcmp_s)(CPUHPPAState *env, float32 a, float32 b, 403 uint32_t y, uint32_t c) 404 { 405 FloatRelation r; 406 if (c & 1) { 407 r = float32_compare(a, b, &env->fp_status); 408 } else { 409 r = float32_compare_quiet(a, b, &env->fp_status); 410 } 411 update_fr0_op(env, GETPC()); 412 update_fr0_cmp(env, y, c, r); 413 } 414 415 void HELPER(fcmp_d)(CPUHPPAState *env, float64 a, float64 b, 416 uint32_t y, uint32_t c) 417 { 418 FloatRelation r; 419 if (c & 1) { 420 r = float64_compare(a, b, &env->fp_status); 421 } else { 422 r = float64_compare_quiet(a, b, &env->fp_status); 423 } 424 update_fr0_op(env, GETPC()); 425 update_fr0_cmp(env, y, c, r); 426 } 427 428 float32 HELPER(fmpyfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c) 429 { 430 float32 ret = float32_muladd(a, b, c, 0, &env->fp_status); 431 update_fr0_op(env, GETPC()); 432 return ret; 433 } 434 435 float32 HELPER(fmpynfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c) 436 { 437 float32 ret = float32_muladd(a, b, c, float_muladd_negate_product, 438 &env->fp_status); 439 update_fr0_op(env, GETPC()); 440 return ret; 441 } 442 443 float64 HELPER(fmpyfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c) 444 { 445 float64 ret = float64_muladd(a, b, c, 0, &env->fp_status); 446 update_fr0_op(env, GETPC()); 447 return ret; 448 } 449 450 float64 HELPER(fmpynfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c) 451 { 452 float64 ret = float64_muladd(a, b, c, float_muladd_negate_product, 453 &env->fp_status); 454 update_fr0_op(env, GETPC()); 455 return ret; 456 } 457