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