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