qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

fpu_helper.c (13420B)


      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/log.h"
     30 #include "qemu/main-loop.h"
     31 #include "cpu.h"
     32 #include "exec/helper-proto.h"
     33 #include "qemu/host-utils.h"
     34 #include "exec/exec-all.h"
     35 #include "fpu/softfloat.h"
     36 
     37 enum {
     38     XTENSA_FP_I = 0x1,
     39     XTENSA_FP_U = 0x2,
     40     XTENSA_FP_O = 0x4,
     41     XTENSA_FP_Z = 0x8,
     42     XTENSA_FP_V = 0x10,
     43 };
     44 
     45 enum {
     46     XTENSA_FCR_FLAGS_SHIFT = 2,
     47     XTENSA_FSR_FLAGS_SHIFT = 7,
     48 };
     49 
     50 static const struct {
     51     uint32_t xtensa_fp_flag;
     52     int softfloat_fp_flag;
     53 } xtensa_fp_flag_map[] = {
     54     { XTENSA_FP_I, float_flag_inexact, },
     55     { XTENSA_FP_U, float_flag_underflow, },
     56     { XTENSA_FP_O, float_flag_overflow, },
     57     { XTENSA_FP_Z, float_flag_divbyzero, },
     58     { XTENSA_FP_V, float_flag_invalid, },
     59 };
     60 
     61 void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
     62 {
     63     static const int rounding_mode[] = {
     64         float_round_nearest_even,
     65         float_round_to_zero,
     66         float_round_up,
     67         float_round_down,
     68     };
     69 
     70     env->uregs[FCR] = v & 0xfffff07f;
     71     set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
     72 }
     73 
     74 void HELPER(wur_fpu_fcr)(CPUXtensaState *env, uint32_t v)
     75 {
     76     static const int rounding_mode[] = {
     77         float_round_nearest_even,
     78         float_round_to_zero,
     79         float_round_up,
     80         float_round_down,
     81     };
     82 
     83     if (v & 0xfffff000) {
     84         qemu_log_mask(LOG_GUEST_ERROR,
     85                       "MBZ field of FCR is written non-zero: %08x\n", v);
     86     }
     87     env->uregs[FCR] = v & 0x0000007f;
     88     set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
     89 }
     90 
     91 void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v)
     92 {
     93     uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT;
     94     int fef = 0;
     95     unsigned i;
     96 
     97     if (v & 0xfffff000) {
     98         qemu_log_mask(LOG_GUEST_ERROR,
     99                       "MBZ field of FSR is written non-zero: %08x\n", v);
    100     }
    101     env->uregs[FSR] = v & 0x00000f80;
    102     for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
    103         if (flags & xtensa_fp_flag_map[i].xtensa_fp_flag) {
    104             fef |= xtensa_fp_flag_map[i].softfloat_fp_flag;
    105         }
    106     }
    107     set_float_exception_flags(fef, &env->fp_status);
    108 }
    109 
    110 uint32_t HELPER(rur_fpu_fsr)(CPUXtensaState *env)
    111 {
    112     uint32_t flags = 0;
    113     int fef = get_float_exception_flags(&env->fp_status);
    114     unsigned i;
    115 
    116     for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
    117         if (fef & xtensa_fp_flag_map[i].softfloat_fp_flag) {
    118             flags |= xtensa_fp_flag_map[i].xtensa_fp_flag;
    119         }
    120     }
    121     env->uregs[FSR] = flags << XTENSA_FSR_FLAGS_SHIFT;
    122     return flags << XTENSA_FSR_FLAGS_SHIFT;
    123 }
    124 
    125 float64 HELPER(abs_d)(float64 v)
    126 {
    127     return float64_abs(v);
    128 }
    129 
    130 float32 HELPER(abs_s)(float32 v)
    131 {
    132     return float32_abs(v);
    133 }
    134 
    135 float64 HELPER(neg_d)(float64 v)
    136 {
    137     return float64_chs(v);
    138 }
    139 
    140 float32 HELPER(neg_s)(float32 v)
    141 {
    142     return float32_chs(v);
    143 }
    144 
    145 float32 HELPER(fpu2k_add_s)(CPUXtensaState *env, float32 a, float32 b)
    146 {
    147     return float32_add(a, b, &env->fp_status);
    148 }
    149 
    150 float32 HELPER(fpu2k_sub_s)(CPUXtensaState *env, float32 a, float32 b)
    151 {
    152     return float32_sub(a, b, &env->fp_status);
    153 }
    154 
    155 float32 HELPER(fpu2k_mul_s)(CPUXtensaState *env, float32 a, float32 b)
    156 {
    157     return float32_mul(a, b, &env->fp_status);
    158 }
    159 
    160 float32 HELPER(fpu2k_madd_s)(CPUXtensaState *env,
    161                              float32 a, float32 b, float32 c)
    162 {
    163     return float32_muladd(b, c, a, 0, &env->fp_status);
    164 }
    165 
    166 float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env,
    167                              float32 a, float32 b, float32 c)
    168 {
    169     return float32_muladd(b, c, a, float_muladd_negate_product,
    170                           &env->fp_status);
    171 }
    172 
    173 float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b)
    174 {
    175     set_use_first_nan(true, &env->fp_status);
    176     return float64_add(a, b, &env->fp_status);
    177 }
    178 
    179 float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
    180 {
    181     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    182     return float32_add(a, b, &env->fp_status);
    183 }
    184 
    185 float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b)
    186 {
    187     set_use_first_nan(true, &env->fp_status);
    188     return float64_sub(a, b, &env->fp_status);
    189 }
    190 
    191 float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
    192 {
    193     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    194     return float32_sub(a, b, &env->fp_status);
    195 }
    196 
    197 float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b)
    198 {
    199     set_use_first_nan(true, &env->fp_status);
    200     return float64_mul(a, b, &env->fp_status);
    201 }
    202 
    203 float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
    204 {
    205     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    206     return float32_mul(a, b, &env->fp_status);
    207 }
    208 
    209 float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
    210 {
    211     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    212     return float64_muladd(b, c, a, 0, &env->fp_status);
    213 }
    214 
    215 float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
    216 {
    217     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    218     return float32_muladd(b, c, a, 0, &env->fp_status);
    219 }
    220 
    221 float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
    222 {
    223     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    224     return float64_muladd(b, c, a, float_muladd_negate_product,
    225                           &env->fp_status);
    226 }
    227 
    228 float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
    229 {
    230     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    231     return float32_muladd(b, c, a, float_muladd_negate_product,
    232                           &env->fp_status);
    233 }
    234 
    235 float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b)
    236 {
    237     set_use_first_nan(true, &env->fp_status);
    238     return float64_div(b, a, &env->fp_status);
    239 }
    240 
    241 float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b)
    242 {
    243     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    244     return float32_div(b, a, &env->fp_status);
    245 }
    246 
    247 float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v)
    248 {
    249     set_use_first_nan(true, &env->fp_status);
    250     return float64_sqrt(v, &env->fp_status);
    251 }
    252 
    253 float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v)
    254 {
    255     set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    256     return float32_sqrt(v, &env->fp_status);
    257 }
    258 
    259 uint32_t HELPER(ftoi_d)(CPUXtensaState *env, float64 v,
    260                         uint32_t rounding_mode, uint32_t scale)
    261 {
    262     float_status fp_status = env->fp_status;
    263     uint32_t res;
    264 
    265     set_float_rounding_mode(rounding_mode, &fp_status);
    266     res = float64_to_int32(float64_scalbn(v, scale, &fp_status), &fp_status);
    267     set_float_exception_flags(get_float_exception_flags(&fp_status),
    268                               &env->fp_status);
    269     return res;
    270 }
    271 
    272 uint32_t HELPER(ftoi_s)(CPUXtensaState *env, float32 v,
    273                         uint32_t rounding_mode, uint32_t scale)
    274 {
    275     float_status fp_status = env->fp_status;
    276     uint32_t res;
    277 
    278     set_float_rounding_mode(rounding_mode, &fp_status);
    279     res = float32_to_int32(float32_scalbn(v, scale, &fp_status), &fp_status);
    280     set_float_exception_flags(get_float_exception_flags(&fp_status),
    281                               &env->fp_status);
    282     return res;
    283 }
    284 
    285 uint32_t HELPER(ftoui_d)(CPUXtensaState *env, float64 v,
    286                          uint32_t rounding_mode, uint32_t scale)
    287 {
    288     float_status fp_status = env->fp_status;
    289     float64 res;
    290     uint32_t rv;
    291 
    292     set_float_rounding_mode(rounding_mode, &fp_status);
    293 
    294     res = float64_scalbn(v, scale, &fp_status);
    295 
    296     if (float64_is_neg(v) && !float64_is_any_nan(v)) {
    297         set_float_exception_flags(float_flag_invalid, &fp_status);
    298         rv = float64_to_int32(res, &fp_status);
    299     } else {
    300         rv = float64_to_uint32(res, &fp_status);
    301     }
    302     set_float_exception_flags(get_float_exception_flags(&fp_status),
    303                               &env->fp_status);
    304     return rv;
    305 }
    306 
    307 uint32_t HELPER(ftoui_s)(CPUXtensaState *env, float32 v,
    308                          uint32_t rounding_mode, uint32_t scale)
    309 {
    310     float_status fp_status = env->fp_status;
    311     float32 res;
    312     uint32_t rv;
    313 
    314     set_float_rounding_mode(rounding_mode, &fp_status);
    315 
    316     res = float32_scalbn(v, scale, &fp_status);
    317 
    318     if (float32_is_neg(v) && !float32_is_any_nan(v)) {
    319         rv = float32_to_int32(res, &fp_status);
    320         if (rv) {
    321             set_float_exception_flags(float_flag_invalid, &fp_status);
    322         }
    323     } else {
    324         rv = float32_to_uint32(res, &fp_status);
    325     }
    326     set_float_exception_flags(get_float_exception_flags(&fp_status),
    327                               &env->fp_status);
    328     return rv;
    329 }
    330 
    331 float64 HELPER(itof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
    332 {
    333     return float64_scalbn(int32_to_float64(v, &env->fp_status),
    334                           (int32_t)scale, &env->fp_status);
    335 }
    336 
    337 float32 HELPER(itof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
    338 {
    339     return float32_scalbn(int32_to_float32(v, &env->fp_status),
    340                           (int32_t)scale, &env->fp_status);
    341 }
    342 
    343 float64 HELPER(uitof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
    344 {
    345     return float64_scalbn(uint32_to_float64(v, &env->fp_status),
    346                           (int32_t)scale, &env->fp_status);
    347 }
    348 
    349 float32 HELPER(uitof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
    350 {
    351     return float32_scalbn(uint32_to_float32(v, &env->fp_status),
    352                           (int32_t)scale, &env->fp_status);
    353 }
    354 
    355 float64 HELPER(cvtd_s)(CPUXtensaState *env, float32 v)
    356 {
    357     return float32_to_float64(v, &env->fp_status);
    358 }
    359 
    360 float32 HELPER(cvts_d)(CPUXtensaState *env, float64 v)
    361 {
    362     return float64_to_float32(v, &env->fp_status);
    363 }
    364 
    365 uint32_t HELPER(un_d)(CPUXtensaState *env, float64 a, float64 b)
    366 {
    367     return float64_unordered_quiet(a, b, &env->fp_status);
    368 }
    369 
    370 uint32_t HELPER(un_s)(CPUXtensaState *env, float32 a, float32 b)
    371 {
    372     return float32_unordered_quiet(a, b, &env->fp_status);
    373 }
    374 
    375 uint32_t HELPER(oeq_d)(CPUXtensaState *env, float64 a, float64 b)
    376 {
    377     return float64_eq_quiet(a, b, &env->fp_status);
    378 }
    379 
    380 uint32_t HELPER(oeq_s)(CPUXtensaState *env, float32 a, float32 b)
    381 {
    382     return float32_eq_quiet(a, b, &env->fp_status);
    383 }
    384 
    385 uint32_t HELPER(ueq_d)(CPUXtensaState *env, float64 a, float64 b)
    386 {
    387     FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
    388 
    389     return v == float_relation_equal ||
    390            v == float_relation_unordered;
    391 }
    392 
    393 uint32_t HELPER(ueq_s)(CPUXtensaState *env, float32 a, float32 b)
    394 {
    395     FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
    396 
    397     return v == float_relation_equal ||
    398            v == float_relation_unordered;
    399 }
    400 
    401 uint32_t HELPER(olt_d)(CPUXtensaState *env, float64 a, float64 b)
    402 {
    403     return float64_lt(a, b, &env->fp_status);
    404 }
    405 
    406 uint32_t HELPER(olt_s)(CPUXtensaState *env, float32 a, float32 b)
    407 {
    408     return float32_lt(a, b, &env->fp_status);
    409 }
    410 
    411 uint32_t HELPER(ult_d)(CPUXtensaState *env, float64 a, float64 b)
    412 {
    413     FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
    414 
    415     return v == float_relation_less ||
    416            v == float_relation_unordered;
    417 }
    418 
    419 uint32_t HELPER(ult_s)(CPUXtensaState *env, float32 a, float32 b)
    420 {
    421     FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
    422 
    423     return v == float_relation_less ||
    424            v == float_relation_unordered;
    425 }
    426 
    427 uint32_t HELPER(ole_d)(CPUXtensaState *env, float64 a, float64 b)
    428 {
    429     return float64_le(a, b, &env->fp_status);
    430 }
    431 
    432 uint32_t HELPER(ole_s)(CPUXtensaState *env, float32 a, float32 b)
    433 {
    434     return float32_le(a, b, &env->fp_status);
    435 }
    436 
    437 uint32_t HELPER(ule_d)(CPUXtensaState *env, float64 a, float64 b)
    438 {
    439     FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
    440 
    441     return v != float_relation_greater;
    442 }
    443 
    444 uint32_t HELPER(ule_s)(CPUXtensaState *env, float32 a, float32 b)
    445 {
    446     FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
    447 
    448     return v != float_relation_greater;
    449 }