qemu/target/riscv/fpu_helper.c
<<
>>
Prefs
   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#include "fpu/softfloat.h"
  25
  26target_ulong riscv_cpu_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
  40void riscv_cpu_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
  53void 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        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
  78    }
  79
  80    set_float_rounding_mode(softrm, &env->fp_status);
  81}
  82
  83uint64_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
  89uint64_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
  95uint64_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
 102uint64_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
 109uint64_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
 116uint64_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
 123uint64_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
 130uint64_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
 137uint64_t helper_fadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 138{
 139    return float32_add(frs1, frs2, &env->fp_status);
 140}
 141
 142uint64_t helper_fsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 143{
 144    return float32_sub(frs1, frs2, &env->fp_status);
 145}
 146
 147uint64_t helper_fmul_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 148{
 149    return float32_mul(frs1, frs2, &env->fp_status);
 150}
 151
 152uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 153{
 154    return float32_div(frs1, frs2, &env->fp_status);
 155}
 156
 157uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 158{
 159    return float32_minnum(frs1, frs2, &env->fp_status);
 160}
 161
 162uint64_t helper_fmax_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 163{
 164    return float32_maxnum(frs1, frs2, &env->fp_status);
 165}
 166
 167uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t frs1)
 168{
 169    return float32_sqrt(frs1, &env->fp_status);
 170}
 171
 172target_ulong helper_fle_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 173{
 174    return float32_le(frs1, frs2, &env->fp_status);
 175}
 176
 177target_ulong helper_flt_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 178{
 179    return float32_lt(frs1, frs2, &env->fp_status);
 180}
 181
 182target_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
 187target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t frs1)
 188{
 189    return float32_to_int32(frs1, &env->fp_status);
 190}
 191
 192target_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)
 198uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t frs1)
 199{
 200    return float32_to_int64(frs1, &env->fp_status);
 201}
 202
 203uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t frs1)
 204{
 205    return float32_to_uint64(frs1, &env->fp_status);
 206}
 207#endif
 208
 209uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1)
 210{
 211    return int32_to_float32((int32_t)rs1, &env->fp_status);
 212}
 213
 214uint64_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)
 220uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1)
 221{
 222    return int64_to_float32(rs1, &env->fp_status);
 223}
 224
 225uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1)
 226{
 227    return uint64_to_float32(rs1, &env->fp_status);
 228}
 229#endif
 230
 231target_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
 250uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 251{
 252    return float64_add(frs1, frs2, &env->fp_status);
 253}
 254
 255uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 256{
 257    return float64_sub(frs1, frs2, &env->fp_status);
 258}
 259
 260uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 261{
 262    return float64_mul(frs1, frs2, &env->fp_status);
 263}
 264
 265uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 266{
 267    return float64_div(frs1, frs2, &env->fp_status);
 268}
 269
 270uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 271{
 272    return float64_minnum(frs1, frs2, &env->fp_status);
 273}
 274
 275uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 276{
 277    return float64_maxnum(frs1, frs2, &env->fp_status);
 278}
 279
 280uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1)
 281{
 282    return float64_to_float32(rs1, &env->fp_status);
 283}
 284
 285uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1)
 286{
 287    return float32_to_float64(rs1, &env->fp_status);
 288}
 289
 290uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)
 291{
 292    return float64_sqrt(frs1, &env->fp_status);
 293}
 294
 295target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 296{
 297    return float64_le(frs1, frs2, &env->fp_status);
 298}
 299
 300target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 301{
 302    return float64_lt(frs1, frs2, &env->fp_status);
 303}
 304
 305target_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
 310target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1)
 311{
 312    return float64_to_int32(frs1, &env->fp_status);
 313}
 314
 315target_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)
 321uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
 322{
 323    return float64_to_int64(frs1, &env->fp_status);
 324}
 325
 326uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
 327{
 328    return float64_to_uint64(frs1, &env->fp_status);
 329}
 330#endif
 331
 332uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1)
 333{
 334    return int32_to_float64((int32_t)rs1, &env->fp_status);
 335}
 336
 337uint64_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)
 343uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1)
 344{
 345    return int64_to_float64(rs1, &env->fp_status);
 346}
 347
 348uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1)
 349{
 350    return uint64_to_float64(rs1, &env->fp_status);
 351}
 352#endif
 353
 354target_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