1 /* 2 * RISC-V FPU Emulation Helpers for QEMU. 3 * 4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2 or later, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "qemu/osdep.h" 20 #include "cpu.h" 21 #include "qemu/host-utils.h" 22 #include "exec/exec-all.h" 23 #include "exec/helper-proto.h" 24 25 target_ulong cpu_riscv_get_fflags(CPURISCVState *env) 26 { 27 int soft = get_float_exception_flags(&env->fp_status); 28 target_ulong hard = 0; 29 30 hard |= (soft & float_flag_inexact) ? FPEXC_NX : 0; 31 hard |= (soft & float_flag_underflow) ? FPEXC_UF : 0; 32 hard |= (soft & float_flag_overflow) ? FPEXC_OF : 0; 33 hard |= (soft & float_flag_divbyzero) ? FPEXC_DZ : 0; 34 hard |= (soft & float_flag_invalid) ? FPEXC_NV : 0; 35 36 return hard; 37 } 38 39 void cpu_riscv_set_fflags(CPURISCVState *env, target_ulong hard) 40 { 41 int soft = 0; 42 43 soft |= (hard & FPEXC_NX) ? float_flag_inexact : 0; 44 soft |= (hard & FPEXC_UF) ? float_flag_underflow : 0; 45 soft |= (hard & FPEXC_OF) ? float_flag_overflow : 0; 46 soft |= (hard & FPEXC_DZ) ? float_flag_divbyzero : 0; 47 soft |= (hard & FPEXC_NV) ? float_flag_invalid : 0; 48 49 set_float_exception_flags(soft, &env->fp_status); 50 } 51 52 void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm) 53 { 54 int softrm; 55 56 if (rm == 7) { 57 rm = env->frm; 58 } 59 switch (rm) { 60 case 0: 61 softrm = float_round_nearest_even; 62 break; 63 case 1: 64 softrm = float_round_to_zero; 65 break; 66 case 2: 67 softrm = float_round_down; 68 break; 69 case 3: 70 softrm = float_round_up; 71 break; 72 case 4: 73 softrm = float_round_ties_away; 74 break; 75 default: 76 do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 77 } 78 79 set_float_rounding_mode(softrm, &env->fp_status); 80 } 81 82 uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, 83 uint64_t frs3) 84 { 85 return float32_muladd(frs1, frs2, frs3, 0, &env->fp_status); 86 } 87 88 uint64_t helper_fmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, 89 uint64_t frs3) 90 { 91 return float64_muladd(frs1, frs2, frs3, 0, &env->fp_status); 92 } 93 94 uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, 95 uint64_t frs3) 96 { 97 return float32_muladd(frs1, frs2, frs3, float_muladd_negate_c, 98 &env->fp_status); 99 } 100 101 uint64_t helper_fmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, 102 uint64_t frs3) 103 { 104 return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c, 105 &env->fp_status); 106 } 107 108 uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, 109 uint64_t frs3) 110 { 111 return float32_muladd(frs1, frs2, frs3, float_muladd_negate_product, 112 &env->fp_status); 113 } 114 115 uint64_t helper_fnmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, 116 uint64_t frs3) 117 { 118 return float64_muladd(frs1, frs2, frs3, float_muladd_negate_product, 119 &env->fp_status); 120 } 121 122 uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, 123 uint64_t frs3) 124 { 125 return float32_muladd(frs1, frs2, frs3, float_muladd_negate_c | 126 float_muladd_negate_product, &env->fp_status); 127 } 128 129 uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, 130 uint64_t frs3) 131 { 132 return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c | 133 float_muladd_negate_product, &env->fp_status); 134 } 135 136 uint64_t helper_fadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 137 { 138 return float32_add(frs1, frs2, &env->fp_status); 139 } 140 141 uint64_t helper_fsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 142 { 143 return float32_sub(frs1, frs2, &env->fp_status); 144 } 145 146 uint64_t helper_fmul_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 147 { 148 return float32_mul(frs1, frs2, &env->fp_status); 149 } 150 151 uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 152 { 153 return float32_div(frs1, frs2, &env->fp_status); 154 } 155 156 uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 157 { 158 return float32_minnum(frs1, frs2, &env->fp_status); 159 } 160 161 uint64_t helper_fmax_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 162 { 163 return float32_maxnum(frs1, frs2, &env->fp_status); 164 } 165 166 uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t frs1) 167 { 168 return float32_sqrt(frs1, &env->fp_status); 169 } 170 171 target_ulong helper_fle_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 172 { 173 return float32_le(frs1, frs2, &env->fp_status); 174 } 175 176 target_ulong helper_flt_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 177 { 178 return float32_lt(frs1, frs2, &env->fp_status); 179 } 180 181 target_ulong helper_feq_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 182 { 183 return float32_eq_quiet(frs1, frs2, &env->fp_status); 184 } 185 186 target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t frs1) 187 { 188 return float32_to_int32(frs1, &env->fp_status); 189 } 190 191 target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t frs1) 192 { 193 return (int32_t)float32_to_uint32(frs1, &env->fp_status); 194 } 195 196 #if defined(TARGET_RISCV64) 197 uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t frs1) 198 { 199 return float32_to_int64(frs1, &env->fp_status); 200 } 201 202 uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t frs1) 203 { 204 return float32_to_uint64(frs1, &env->fp_status); 205 } 206 #endif 207 208 uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1) 209 { 210 return int32_to_float32((int32_t)rs1, &env->fp_status); 211 } 212 213 uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1) 214 { 215 return uint32_to_float32((uint32_t)rs1, &env->fp_status); 216 } 217 218 #if defined(TARGET_RISCV64) 219 uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1) 220 { 221 return int64_to_float32(rs1, &env->fp_status); 222 } 223 224 uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1) 225 { 226 return uint64_to_float32(rs1, &env->fp_status); 227 } 228 #endif 229 230 target_ulong helper_fclass_s(uint64_t frs1) 231 { 232 float32 f = frs1; 233 bool sign = float32_is_neg(f); 234 235 if (float32_is_infinity(f)) { 236 return sign ? 1 << 0 : 1 << 7; 237 } else if (float32_is_zero(f)) { 238 return sign ? 1 << 3 : 1 << 4; 239 } else if (float32_is_zero_or_denormal(f)) { 240 return sign ? 1 << 2 : 1 << 5; 241 } else if (float32_is_any_nan(f)) { 242 float_status s = { }; /* for snan_bit_is_one */ 243 return float32_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; 244 } else { 245 return sign ? 1 << 1 : 1 << 6; 246 } 247 } 248 249 uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 250 { 251 return float64_add(frs1, frs2, &env->fp_status); 252 } 253 254 uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 255 { 256 return float64_sub(frs1, frs2, &env->fp_status); 257 } 258 259 uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 260 { 261 return float64_mul(frs1, frs2, &env->fp_status); 262 } 263 264 uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 265 { 266 return float64_div(frs1, frs2, &env->fp_status); 267 } 268 269 uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 270 { 271 return float64_minnum(frs1, frs2, &env->fp_status); 272 } 273 274 uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 275 { 276 return float64_maxnum(frs1, frs2, &env->fp_status); 277 } 278 279 uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1) 280 { 281 return float64_to_float32(rs1, &env->fp_status); 282 } 283 284 uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1) 285 { 286 return float32_to_float64(rs1, &env->fp_status); 287 } 288 289 uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1) 290 { 291 return float64_sqrt(frs1, &env->fp_status); 292 } 293 294 target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 295 { 296 return float64_le(frs1, frs2, &env->fp_status); 297 } 298 299 target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 300 { 301 return float64_lt(frs1, frs2, &env->fp_status); 302 } 303 304 target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2) 305 { 306 return float64_eq_quiet(frs1, frs2, &env->fp_status); 307 } 308 309 target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1) 310 { 311 return float64_to_int32(frs1, &env->fp_status); 312 } 313 314 target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1) 315 { 316 return (int32_t)float64_to_uint32(frs1, &env->fp_status); 317 } 318 319 #if defined(TARGET_RISCV64) 320 uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1) 321 { 322 return float64_to_int64(frs1, &env->fp_status); 323 } 324 325 uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1) 326 { 327 return float64_to_uint64(frs1, &env->fp_status); 328 } 329 #endif 330 331 uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1) 332 { 333 return int32_to_float64((int32_t)rs1, &env->fp_status); 334 } 335 336 uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1) 337 { 338 return uint32_to_float64((uint32_t)rs1, &env->fp_status); 339 } 340 341 #if defined(TARGET_RISCV64) 342 uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1) 343 { 344 return int64_to_float64(rs1, &env->fp_status); 345 } 346 347 uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1) 348 { 349 return uint64_to_float64(rs1, &env->fp_status); 350 } 351 #endif 352 353 target_ulong helper_fclass_d(uint64_t frs1) 354 { 355 float64 f = frs1; 356 bool sign = float64_is_neg(f); 357 358 if (float64_is_infinity(f)) { 359 return sign ? 1 << 0 : 1 << 7; 360 } else if (float64_is_zero(f)) { 361 return sign ? 1 << 3 : 1 << 4; 362 } else if (float64_is_zero_or_denormal(f)) { 363 return sign ? 1 << 2 : 1 << 5; 364 } else if (float64_is_any_nan(f)) { 365 float_status s = { }; /* for snan_bit_is_one */ 366 return float64_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; 367 } else { 368 return sign ? 1 << 1 : 1 << 6; 369 } 370 } 371