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