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(float32_minnum(frs1, frs2, &env->fp_status));
 178}
 179
 180uint64_t helper_fmax_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 181{
 182    float32 frs1 = check_nanbox_s(rs1);
 183    float32 frs2 = check_nanbox_s(rs2);
 184    return nanbox_s(float32_maxnum(frs1, frs2, &env->fp_status));
 185}
 186
 187uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t rs1)
 188{
 189    float32 frs1 = check_nanbox_s(rs1);
 190    return nanbox_s(float32_sqrt(frs1, &env->fp_status));
 191}
 192
 193target_ulong helper_fle_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 194{
 195    float32 frs1 = check_nanbox_s(rs1);
 196    float32 frs2 = check_nanbox_s(rs2);
 197    return float32_le(frs1, frs2, &env->fp_status);
 198}
 199
 200target_ulong helper_flt_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 201{
 202    float32 frs1 = check_nanbox_s(rs1);
 203    float32 frs2 = check_nanbox_s(rs2);
 204    return float32_lt(frs1, frs2, &env->fp_status);
 205}
 206
 207target_ulong helper_feq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 208{
 209    float32 frs1 = check_nanbox_s(rs1);
 210    float32 frs2 = check_nanbox_s(rs2);
 211    return float32_eq_quiet(frs1, frs2, &env->fp_status);
 212}
 213
 214target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t rs1)
 215{
 216    float32 frs1 = check_nanbox_s(rs1);
 217    return float32_to_int32(frs1, &env->fp_status);
 218}
 219
 220target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1)
 221{
 222    float32 frs1 = check_nanbox_s(rs1);
 223    return (int32_t)float32_to_uint32(frs1, &env->fp_status);
 224}
 225
 226uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1)
 227{
 228    float32 frs1 = check_nanbox_s(rs1);
 229    return float32_to_int64(frs1, &env->fp_status);
 230}
 231
 232uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1)
 233{
 234    float32 frs1 = check_nanbox_s(rs1);
 235    return float32_to_uint64(frs1, &env->fp_status);
 236}
 237
 238uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1)
 239{
 240    return nanbox_s(int32_to_float32((int32_t)rs1, &env->fp_status));
 241}
 242
 243uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1)
 244{
 245    return nanbox_s(uint32_to_float32((uint32_t)rs1, &env->fp_status));
 246}
 247
 248uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1)
 249{
 250    return nanbox_s(int64_to_float32(rs1, &env->fp_status));
 251}
 252
 253uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1)
 254{
 255    return nanbox_s(uint64_to_float32(rs1, &env->fp_status));
 256}
 257
 258target_ulong helper_fclass_s(uint64_t rs1)
 259{
 260    float32 frs1 = check_nanbox_s(rs1);
 261    return fclass_s(frs1);
 262}
 263
 264uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 265{
 266    return float64_add(frs1, frs2, &env->fp_status);
 267}
 268
 269uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 270{
 271    return float64_sub(frs1, frs2, &env->fp_status);
 272}
 273
 274uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 275{
 276    return float64_mul(frs1, frs2, &env->fp_status);
 277}
 278
 279uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 280{
 281    return float64_div(frs1, frs2, &env->fp_status);
 282}
 283
 284uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 285{
 286    return float64_minnum(frs1, frs2, &env->fp_status);
 287}
 288
 289uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 290{
 291    return float64_maxnum(frs1, frs2, &env->fp_status);
 292}
 293
 294uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1)
 295{
 296    return nanbox_s(float64_to_float32(rs1, &env->fp_status));
 297}
 298
 299uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1)
 300{
 301    float32 frs1 = check_nanbox_s(rs1);
 302    return float32_to_float64(frs1, &env->fp_status);
 303}
 304
 305uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)
 306{
 307    return float64_sqrt(frs1, &env->fp_status);
 308}
 309
 310target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 311{
 312    return float64_le(frs1, frs2, &env->fp_status);
 313}
 314
 315target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 316{
 317    return float64_lt(frs1, frs2, &env->fp_status);
 318}
 319
 320target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 321{
 322    return float64_eq_quiet(frs1, frs2, &env->fp_status);
 323}
 324
 325target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1)
 326{
 327    return float64_to_int32(frs1, &env->fp_status);
 328}
 329
 330target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1)
 331{
 332    return (int32_t)float64_to_uint32(frs1, &env->fp_status);
 333}
 334
 335uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
 336{
 337    return float64_to_int64(frs1, &env->fp_status);
 338}
 339
 340uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
 341{
 342    return float64_to_uint64(frs1, &env->fp_status);
 343}
 344
 345uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1)
 346{
 347    return int32_to_float64((int32_t)rs1, &env->fp_status);
 348}
 349
 350uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1)
 351{
 352    return uint32_to_float64((uint32_t)rs1, &env->fp_status);
 353}
 354
 355uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1)
 356{
 357    return int64_to_float64(rs1, &env->fp_status);
 358}
 359
 360uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1)
 361{
 362    return uint64_to_float64(rs1, &env->fp_status);
 363}
 364
 365target_ulong helper_fclass_d(uint64_t frs1)
 366{
 367    return fclass_d(frs1);
 368}
 369