qemu/target/xtensa/fpu_helper.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab.
   3 * All rights reserved.
   4 *
   5 * Redistribution and use in source and binary forms, with or without
   6 * modification, are permitted provided that the following conditions are met:
   7 *     * Redistributions of source code must retain the above copyright
   8 *       notice, this list of conditions and the following disclaimer.
   9 *     * Redistributions in binary form must reproduce the above copyright
  10 *       notice, this list of conditions and the following disclaimer in the
  11 *       documentation and/or other materials provided with the distribution.
  12 *     * Neither the name of the Open Source and Linux Lab nor the
  13 *       names of its contributors may be used to endorse or promote products
  14 *       derived from this software without specific prior written permission.
  15 *
  16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "qemu/main-loop.h"
  30#include "cpu.h"
  31#include "exec/helper-proto.h"
  32#include "qemu/host-utils.h"
  33#include "exec/exec-all.h"
  34#include "fpu/softfloat.h"
  35
  36enum {
  37    XTENSA_FP_I = 0x1,
  38    XTENSA_FP_U = 0x2,
  39    XTENSA_FP_O = 0x4,
  40    XTENSA_FP_Z = 0x8,
  41    XTENSA_FP_V = 0x10,
  42};
  43
  44enum {
  45    XTENSA_FCR_FLAGS_SHIFT = 2,
  46    XTENSA_FSR_FLAGS_SHIFT = 7,
  47};
  48
  49static const struct {
  50    uint32_t xtensa_fp_flag;
  51    int softfloat_fp_flag;
  52} xtensa_fp_flag_map[] = {
  53    { XTENSA_FP_I, float_flag_inexact, },
  54    { XTENSA_FP_U, float_flag_underflow, },
  55    { XTENSA_FP_O, float_flag_overflow, },
  56    { XTENSA_FP_Z, float_flag_divbyzero, },
  57    { XTENSA_FP_V, float_flag_invalid, },
  58};
  59
  60void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
  61{
  62    static const int rounding_mode[] = {
  63        float_round_nearest_even,
  64        float_round_to_zero,
  65        float_round_up,
  66        float_round_down,
  67    };
  68
  69    env->uregs[FCR] = v & 0xfffff07f;
  70    set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
  71}
  72
  73void HELPER(wur_fpu_fcr)(CPUXtensaState *env, uint32_t v)
  74{
  75    static const int rounding_mode[] = {
  76        float_round_nearest_even,
  77        float_round_to_zero,
  78        float_round_up,
  79        float_round_down,
  80    };
  81
  82    if (v & 0xfffff000) {
  83        qemu_log_mask(LOG_GUEST_ERROR,
  84                      "MBZ field of FCR is written non-zero: %08x\n", v);
  85    }
  86    env->uregs[FCR] = v & 0x0000007f;
  87    set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
  88}
  89
  90void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v)
  91{
  92    uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT;
  93    int fef = 0;
  94    unsigned i;
  95
  96    if (v & 0xfffff000) {
  97        qemu_log_mask(LOG_GUEST_ERROR,
  98                      "MBZ field of FSR is written non-zero: %08x\n", v);
  99    }
 100    env->uregs[FSR] = v & 0x00000f80;
 101    for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
 102        if (flags & xtensa_fp_flag_map[i].xtensa_fp_flag) {
 103            fef |= xtensa_fp_flag_map[i].softfloat_fp_flag;
 104        }
 105    }
 106    set_float_exception_flags(fef, &env->fp_status);
 107}
 108
 109uint32_t HELPER(rur_fpu_fsr)(CPUXtensaState *env)
 110{
 111    uint32_t flags = 0;
 112    int fef = get_float_exception_flags(&env->fp_status);
 113    unsigned i;
 114
 115    for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
 116        if (fef & xtensa_fp_flag_map[i].softfloat_fp_flag) {
 117            flags |= xtensa_fp_flag_map[i].xtensa_fp_flag;
 118        }
 119    }
 120    env->uregs[FSR] = flags << XTENSA_FSR_FLAGS_SHIFT;
 121    return flags << XTENSA_FSR_FLAGS_SHIFT;
 122}
 123
 124float64 HELPER(abs_d)(float64 v)
 125{
 126    return float64_abs(v);
 127}
 128
 129float32 HELPER(abs_s)(float32 v)
 130{
 131    return float32_abs(v);
 132}
 133
 134float64 HELPER(neg_d)(float64 v)
 135{
 136    return float64_chs(v);
 137}
 138
 139float32 HELPER(neg_s)(float32 v)
 140{
 141    return float32_chs(v);
 142}
 143
 144float32 HELPER(fpu2k_add_s)(CPUXtensaState *env, float32 a, float32 b)
 145{
 146    return float32_add(a, b, &env->fp_status);
 147}
 148
 149float32 HELPER(fpu2k_sub_s)(CPUXtensaState *env, float32 a, float32 b)
 150{
 151    return float32_sub(a, b, &env->fp_status);
 152}
 153
 154float32 HELPER(fpu2k_mul_s)(CPUXtensaState *env, float32 a, float32 b)
 155{
 156    return float32_mul(a, b, &env->fp_status);
 157}
 158
 159float32 HELPER(fpu2k_madd_s)(CPUXtensaState *env,
 160                             float32 a, float32 b, float32 c)
 161{
 162    return float32_muladd(b, c, a, 0, &env->fp_status);
 163}
 164
 165float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env,
 166                             float32 a, float32 b, float32 c)
 167{
 168    return float32_muladd(b, c, a, float_muladd_negate_product,
 169                          &env->fp_status);
 170}
 171
 172float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b)
 173{
 174    set_use_first_nan(true, &env->fp_status);
 175    return float64_add(a, b, &env->fp_status);
 176}
 177
 178float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
 179{
 180    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 181    return float32_add(a, b, &env->fp_status);
 182}
 183
 184float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b)
 185{
 186    set_use_first_nan(true, &env->fp_status);
 187    return float64_sub(a, b, &env->fp_status);
 188}
 189
 190float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
 191{
 192    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 193    return float32_sub(a, b, &env->fp_status);
 194}
 195
 196float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b)
 197{
 198    set_use_first_nan(true, &env->fp_status);
 199    return float64_mul(a, b, &env->fp_status);
 200}
 201
 202float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
 203{
 204    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 205    return float32_mul(a, b, &env->fp_status);
 206}
 207
 208float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
 209{
 210    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 211    return float64_muladd(b, c, a, 0, &env->fp_status);
 212}
 213
 214float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 215{
 216    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 217    return float32_muladd(b, c, a, 0, &env->fp_status);
 218}
 219
 220float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
 221{
 222    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 223    return float64_muladd(b, c, a, float_muladd_negate_product,
 224                          &env->fp_status);
 225}
 226
 227float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 228{
 229    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 230    return float32_muladd(b, c, a, float_muladd_negate_product,
 231                          &env->fp_status);
 232}
 233
 234float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b)
 235{
 236    set_use_first_nan(true, &env->fp_status);
 237    return float64_div(b, a, &env->fp_status);
 238}
 239
 240float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b)
 241{
 242    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 243    return float32_div(b, a, &env->fp_status);
 244}
 245
 246float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v)
 247{
 248    set_use_first_nan(true, &env->fp_status);
 249    return float64_sqrt(v, &env->fp_status);
 250}
 251
 252float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v)
 253{
 254    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
 255    return float32_sqrt(v, &env->fp_status);
 256}
 257
 258uint32_t HELPER(ftoi_d)(CPUXtensaState *env, float64 v,
 259                        uint32_t rounding_mode, uint32_t scale)
 260{
 261    float_status fp_status = env->fp_status;
 262    uint32_t res;
 263
 264    set_float_rounding_mode(rounding_mode, &fp_status);
 265    res = float64_to_int32(float64_scalbn(v, scale, &fp_status), &fp_status);
 266    set_float_exception_flags(get_float_exception_flags(&fp_status),
 267                              &env->fp_status);
 268    return res;
 269}
 270
 271uint32_t HELPER(ftoi_s)(CPUXtensaState *env, float32 v,
 272                        uint32_t rounding_mode, uint32_t scale)
 273{
 274    float_status fp_status = env->fp_status;
 275    uint32_t res;
 276
 277    set_float_rounding_mode(rounding_mode, &fp_status);
 278    res = float32_to_int32(float32_scalbn(v, scale, &fp_status), &fp_status);
 279    set_float_exception_flags(get_float_exception_flags(&fp_status),
 280                              &env->fp_status);
 281    return res;
 282}
 283
 284uint32_t HELPER(ftoui_d)(CPUXtensaState *env, float64 v,
 285                         uint32_t rounding_mode, uint32_t scale)
 286{
 287    float_status fp_status = env->fp_status;
 288    float64 res;
 289    uint32_t rv;
 290
 291    set_float_rounding_mode(rounding_mode, &fp_status);
 292
 293    res = float64_scalbn(v, scale, &fp_status);
 294
 295    if (float64_is_neg(v) && !float64_is_any_nan(v)) {
 296        set_float_exception_flags(float_flag_invalid, &fp_status);
 297        rv = float64_to_int32(res, &fp_status);
 298    } else {
 299        rv = float64_to_uint32(res, &fp_status);
 300    }
 301    set_float_exception_flags(get_float_exception_flags(&fp_status),
 302                              &env->fp_status);
 303    return rv;
 304}
 305
 306uint32_t HELPER(ftoui_s)(CPUXtensaState *env, float32 v,
 307                         uint32_t rounding_mode, uint32_t scale)
 308{
 309    float_status fp_status = env->fp_status;
 310    float32 res;
 311    uint32_t rv;
 312
 313    set_float_rounding_mode(rounding_mode, &fp_status);
 314
 315    res = float32_scalbn(v, scale, &fp_status);
 316
 317    if (float32_is_neg(v) && !float32_is_any_nan(v)) {
 318        rv = float32_to_int32(res, &fp_status);
 319        if (rv) {
 320            set_float_exception_flags(float_flag_invalid, &fp_status);
 321        }
 322    } else {
 323        rv = float32_to_uint32(res, &fp_status);
 324    }
 325    set_float_exception_flags(get_float_exception_flags(&fp_status),
 326                              &env->fp_status);
 327    return rv;
 328}
 329
 330float64 HELPER(itof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
 331{
 332    return float64_scalbn(int32_to_float64(v, &env->fp_status),
 333                          (int32_t)scale, &env->fp_status);
 334}
 335
 336float32 HELPER(itof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
 337{
 338    return float32_scalbn(int32_to_float32(v, &env->fp_status),
 339                          (int32_t)scale, &env->fp_status);
 340}
 341
 342float64 HELPER(uitof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
 343{
 344    return float64_scalbn(uint32_to_float64(v, &env->fp_status),
 345                          (int32_t)scale, &env->fp_status);
 346}
 347
 348float32 HELPER(uitof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
 349{
 350    return float32_scalbn(uint32_to_float32(v, &env->fp_status),
 351                          (int32_t)scale, &env->fp_status);
 352}
 353
 354float64 HELPER(cvtd_s)(CPUXtensaState *env, float32 v)
 355{
 356    return float32_to_float64(v, &env->fp_status);
 357}
 358
 359float32 HELPER(cvts_d)(CPUXtensaState *env, float64 v)
 360{
 361    return float64_to_float32(v, &env->fp_status);
 362}
 363
 364uint32_t HELPER(un_d)(CPUXtensaState *env, float64 a, float64 b)
 365{
 366    return float64_unordered_quiet(a, b, &env->fp_status);
 367}
 368
 369uint32_t HELPER(un_s)(CPUXtensaState *env, float32 a, float32 b)
 370{
 371    return float32_unordered_quiet(a, b, &env->fp_status);
 372}
 373
 374uint32_t HELPER(oeq_d)(CPUXtensaState *env, float64 a, float64 b)
 375{
 376    return float64_eq_quiet(a, b, &env->fp_status);
 377}
 378
 379uint32_t HELPER(oeq_s)(CPUXtensaState *env, float32 a, float32 b)
 380{
 381    return float32_eq_quiet(a, b, &env->fp_status);
 382}
 383
 384uint32_t HELPER(ueq_d)(CPUXtensaState *env, float64 a, float64 b)
 385{
 386    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
 387
 388    return v == float_relation_equal ||
 389           v == float_relation_unordered;
 390}
 391
 392uint32_t HELPER(ueq_s)(CPUXtensaState *env, float32 a, float32 b)
 393{
 394    FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
 395
 396    return v == float_relation_equal ||
 397           v == float_relation_unordered;
 398}
 399
 400uint32_t HELPER(olt_d)(CPUXtensaState *env, float64 a, float64 b)
 401{
 402    return float64_lt(a, b, &env->fp_status);
 403}
 404
 405uint32_t HELPER(olt_s)(CPUXtensaState *env, float32 a, float32 b)
 406{
 407    return float32_lt(a, b, &env->fp_status);
 408}
 409
 410uint32_t HELPER(ult_d)(CPUXtensaState *env, float64 a, float64 b)
 411{
 412    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
 413
 414    return v == float_relation_less ||
 415           v == float_relation_unordered;
 416}
 417
 418uint32_t HELPER(ult_s)(CPUXtensaState *env, float32 a, float32 b)
 419{
 420    FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
 421
 422    return v == float_relation_less ||
 423           v == float_relation_unordered;
 424}
 425
 426uint32_t HELPER(ole_d)(CPUXtensaState *env, float64 a, float64 b)
 427{
 428    return float64_le(a, b, &env->fp_status);
 429}
 430
 431uint32_t HELPER(ole_s)(CPUXtensaState *env, float32 a, float32 b)
 432{
 433    return float32_le(a, b, &env->fp_status);
 434}
 435
 436uint32_t HELPER(ule_d)(CPUXtensaState *env, float64 a, float64 b)
 437{
 438    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
 439
 440    return v != float_relation_greater;
 441}
 442
 443uint32_t HELPER(ule_s)(CPUXtensaState *env, float32 a, float32 b)
 444{
 445    FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
 446
 447    return v != float_relation_greater;
 448}
 449