cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

op_helper.c (33930B)


      1/*
      2 *  Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
      3 *
      4 *  This program is free software; you can redistribute it and/or modify
      5 *  it under the terms of the GNU General Public License as published by
      6 *  the Free Software Foundation; either version 2 of the License, or
      7 *  (at your option) any later version.
      8 *
      9 *  This program is distributed in the hope that it will be useful,
     10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 *  GNU General Public License for more details.
     13 *
     14 *  You should have received a copy of the GNU General Public License
     15 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#include "qemu/osdep.h"
     19#include "qemu/log.h"
     20#include "exec/exec-all.h"
     21#include "exec/cpu_ldst.h"
     22#include "exec/helper-proto.h"
     23#include "fpu/softfloat.h"
     24#include "cpu.h"
     25#include "internal.h"
     26#include "macros.h"
     27#include "arch.h"
     28#include "hex_arch_types.h"
     29#include "fma_emu.h"
     30
     31#define SF_BIAS        127
     32#define SF_MANTBITS    23
     33
     34/* Exceptions processing helpers */
     35static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
     36                                                 uint32_t exception,
     37                                                 uintptr_t pc)
     38{
     39    CPUState *cs = env_cpu(env);
     40    qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
     41    cs->exception_index = exception;
     42    cpu_loop_exit_restore(cs, pc);
     43}
     44
     45void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
     46{
     47    do_raise_exception_err(env, excp, 0);
     48}
     49
     50static void log_reg_write(CPUHexagonState *env, int rnum,
     51                          target_ulong val, uint32_t slot)
     52{
     53    HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
     54                  rnum, val, val);
     55    if (val == env->gpr[rnum]) {
     56        HEX_DEBUG_LOG(" NO CHANGE");
     57    }
     58    HEX_DEBUG_LOG("\n");
     59
     60    env->new_value[rnum] = val;
     61    if (HEX_DEBUG) {
     62        /* Do this so HELPER(debug_commit_end) will know */
     63        env->reg_written[rnum] = 1;
     64    }
     65}
     66
     67static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
     68{
     69    HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
     70                  " (0x" TARGET_FMT_lx ")\n",
     71                  pnum, val, val);
     72
     73    /* Multiple writes to the same preg are and'ed together */
     74    if (env->pred_written & (1 << pnum)) {
     75        env->new_pred_value[pnum] &= val & 0xff;
     76    } else {
     77        env->new_pred_value[pnum] = val & 0xff;
     78        env->pred_written |= 1 << pnum;
     79    }
     80}
     81
     82static void log_store32(CPUHexagonState *env, target_ulong addr,
     83                        target_ulong val, int width, int slot)
     84{
     85    HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
     86                  ", %" PRId32 " [0x08%" PRIx32 "])\n",
     87                  width, addr, val, val);
     88    env->mem_log_stores[slot].va = addr;
     89    env->mem_log_stores[slot].width = width;
     90    env->mem_log_stores[slot].data32 = val;
     91}
     92
     93static void log_store64(CPUHexagonState *env, target_ulong addr,
     94                        int64_t val, int width, int slot)
     95{
     96    HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
     97                  ", %" PRId64 " [0x016%" PRIx64 "])\n",
     98                   width, addr, val, val);
     99    env->mem_log_stores[slot].va = addr;
    100    env->mem_log_stores[slot].width = width;
    101    env->mem_log_stores[slot].data64 = val;
    102}
    103
    104static void write_new_pc(CPUHexagonState *env, target_ulong addr)
    105{
    106    HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
    107
    108    /*
    109     * If more than one branch is taken in a packet, only the first one
    110     * is actually done.
    111     */
    112    if (env->branch_taken) {
    113        HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
    114                      "ignoring the second one\n");
    115    } else {
    116        fCHECK_PCALIGN(addr);
    117        env->branch_taken = 1;
    118        env->next_PC = addr;
    119    }
    120}
    121
    122/* Handy place to set a breakpoint */
    123void HELPER(debug_start_packet)(CPUHexagonState *env)
    124{
    125    HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
    126                  env->gpr[HEX_REG_PC]);
    127
    128    for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
    129        env->reg_written[i] = 0;
    130    }
    131}
    132
    133/* Checks for bookkeeping errors between disassembly context and runtime */
    134void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
    135{
    136    if (env->mem_log_stores[slot].width != check) {
    137        HEX_DEBUG_LOG("ERROR: %d != %d\n",
    138                      env->mem_log_stores[slot].width, check);
    139        g_assert_not_reached();
    140    }
    141}
    142
    143void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
    144{
    145    uintptr_t ra = GETPC();
    146    uint8_t width = env->mem_log_stores[slot_num].width;
    147    target_ulong va = env->mem_log_stores[slot_num].va;
    148
    149    switch (width) {
    150    case 1:
    151        cpu_stb_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
    152        break;
    153    case 2:
    154        cpu_stw_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
    155        break;
    156    case 4:
    157        cpu_stl_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
    158        break;
    159    case 8:
    160        cpu_stq_data_ra(env, va, env->mem_log_stores[slot_num].data64, ra);
    161        break;
    162    default:
    163        g_assert_not_reached();
    164    }
    165}
    166
    167static void print_store(CPUHexagonState *env, int slot)
    168{
    169    if (!(env->slot_cancelled & (1 << slot))) {
    170        uint8_t width = env->mem_log_stores[slot].width;
    171        if (width == 1) {
    172            uint32_t data = env->mem_log_stores[slot].data32 & 0xff;
    173            HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32
    174                          " (0x%02" PRIx32 ")\n",
    175                          env->mem_log_stores[slot].va, data, data);
    176        } else if (width == 2) {
    177            uint32_t data = env->mem_log_stores[slot].data32 & 0xffff;
    178            HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32
    179                          " (0x%04" PRIx32 ")\n",
    180                          env->mem_log_stores[slot].va, data, data);
    181        } else if (width == 4) {
    182            uint32_t data = env->mem_log_stores[slot].data32;
    183            HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32
    184                          " (0x%08" PRIx32 ")\n",
    185                          env->mem_log_stores[slot].va, data, data);
    186        } else if (width == 8) {
    187            HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64
    188                          " (0x%016" PRIx64 ")\n",
    189                          env->mem_log_stores[slot].va,
    190                          env->mem_log_stores[slot].data64,
    191                          env->mem_log_stores[slot].data64);
    192        } else {
    193            HEX_DEBUG_LOG("\tBad store width %d\n", width);
    194            g_assert_not_reached();
    195        }
    196    }
    197}
    198
    199/* This function is a handy place to set a breakpoint */
    200void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
    201{
    202    bool reg_printed = false;
    203    bool pred_printed = false;
    204    int i;
    205
    206    HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n",
    207                  env->this_PC);
    208    HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);
    209
    210    for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
    211        if (env->reg_written[i]) {
    212            if (!reg_printed) {
    213                HEX_DEBUG_LOG("Regs written\n");
    214                reg_printed = true;
    215            }
    216            HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
    217                          i, env->new_value[i], env->new_value[i]);
    218        }
    219    }
    220
    221    for (i = 0; i < NUM_PREGS; i++) {
    222        if (env->pred_written & (1 << i)) {
    223            if (!pred_printed) {
    224                HEX_DEBUG_LOG("Predicates written\n");
    225                pred_printed = true;
    226            }
    227            HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
    228                          i, env->new_pred_value[i]);
    229        }
    230    }
    231
    232    if (has_st0 || has_st1) {
    233        HEX_DEBUG_LOG("Stores\n");
    234        if (has_st0) {
    235            print_store(env, 0);
    236        }
    237        if (has_st1) {
    238            print_store(env, 1);
    239        }
    240    }
    241
    242    HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->next_PC);
    243    HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
    244                  ", insn = " TARGET_FMT_lx
    245                  "\n",
    246                  env->gpr[HEX_REG_QEMU_PKT_CNT],
    247                  env->gpr[HEX_REG_QEMU_INSN_CNT]);
    248
    249}
    250
    251int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
    252{
    253    int32_t K_const = sextract32(M, 24, 4);
    254    int32_t length = sextract32(M, 0, 17);
    255    uint32_t new_ptr = RxV + offset;
    256    uint32_t start_addr;
    257    uint32_t end_addr;
    258
    259    if (K_const == 0 && length >= 4) {
    260        start_addr = CS;
    261        end_addr = start_addr + length;
    262    } else {
    263        /*
    264         * Versions v3 and earlier used the K value to specify a power-of-2 size
    265         * 2^(K+2) that is greater than the buffer length
    266         */
    267        int32_t mask = (1 << (K_const + 2)) - 1;
    268        start_addr = RxV & (~mask);
    269        end_addr = start_addr | length;
    270    }
    271
    272    if (new_ptr >= end_addr) {
    273        new_ptr -= length;
    274    } else if (new_ptr < start_addr) {
    275        new_ptr += length;
    276    }
    277
    278    return new_ptr;
    279}
    280
    281uint32_t HELPER(fbrev)(uint32_t addr)
    282{
    283    /*
    284     *  Bit reverse the low 16 bits of the address
    285     */
    286    return deposit32(addr, 0, 16, revbit16(addr));
    287}
    288
    289static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
    290{
    291    return make_float32(
    292        ((sign & 1) << 31) |
    293        ((exp & 0xff) << SF_MANTBITS) |
    294        (mant & ((1 << SF_MANTBITS) - 1)));
    295}
    296
    297/*
    298 * sfrecipa, sfinvsqrta have two 32-bit results
    299 *     r0,p0=sfrecipa(r1,r2)
    300 *     r0,p0=sfinvsqrta(r1)
    301 *
    302 * Since helpers can only return a single value, we pack the two results
    303 * into a 64-bit value.
    304 */
    305uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
    306{
    307    int32_t PeV = 0;
    308    float32 RdV;
    309    int idx;
    310    int adjust;
    311    int mant;
    312    int exp;
    313
    314    arch_fpop_start(env);
    315    if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
    316        PeV = adjust;
    317        idx = (RtV >> 16) & 0x7f;
    318        mant = (recip_lookup_table[idx] << 15) | 1;
    319        exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
    320        RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
    321    }
    322    arch_fpop_end(env);
    323    return ((uint64_t)RdV << 32) | PeV;
    324}
    325
    326uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
    327{
    328    int PeV = 0;
    329    float32 RdV;
    330    int idx;
    331    int adjust;
    332    int mant;
    333    int exp;
    334
    335    arch_fpop_start(env);
    336    if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
    337        PeV = adjust;
    338        idx = (RsV >> 17) & 0x7f;
    339        mant = (invsqrt_lookup_table[idx] << 15);
    340        exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
    341        RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
    342    }
    343    arch_fpop_end(env);
    344    return ((uint64_t)RdV << 32) | PeV;
    345}
    346
    347int64_t HELPER(vacsh_val)(CPUHexagonState *env,
    348                           int64_t RxxV, int64_t RssV, int64_t RttV)
    349{
    350    for (int i = 0; i < 4; i++) {
    351        int xv = sextract64(RxxV, i * 16, 16);
    352        int sv = sextract64(RssV, i * 16, 16);
    353        int tv = sextract64(RttV, i * 16, 16);
    354        int max;
    355        xv = xv + tv;
    356        sv = sv - tv;
    357        max = xv > sv ? xv : sv;
    358        /* Note that fSATH can set the OVF bit in usr */
    359        RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
    360    }
    361    return RxxV;
    362}
    363
    364int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
    365                           int64_t RxxV, int64_t RssV, int64_t RttV)
    366{
    367    int32_t PeV = 0;
    368    for (int i = 0; i < 4; i++) {
    369        int xv = sextract64(RxxV, i * 16, 16);
    370        int sv = sextract64(RssV, i * 16, 16);
    371        int tv = sextract64(RttV, i * 16, 16);
    372        xv = xv + tv;
    373        sv = sv - tv;
    374        PeV = deposit32(PeV, i * 2, 1, (xv > sv));
    375        PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
    376    }
    377    return PeV;
    378}
    379
    380static void probe_store(CPUHexagonState *env, int slot, int mmu_idx)
    381{
    382    if (!(env->slot_cancelled & (1 << slot))) {
    383        size1u_t width = env->mem_log_stores[slot].width;
    384        target_ulong va = env->mem_log_stores[slot].va;
    385        uintptr_t ra = GETPC();
    386        probe_write(env, va, width, mmu_idx, ra);
    387    }
    388}
    389
    390/* Called during packet commit when there are two scalar stores */
    391void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int mmu_idx)
    392{
    393    probe_store(env, 0, mmu_idx);
    394}
    395
    396/*
    397 * mem_noshuf
    398 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
    399 *
    400 * If the load is in slot 0 and there is a store in slot1 (that
    401 * wasn't cancelled), we have to do the store first.
    402 */
    403static void check_noshuf(CPUHexagonState *env, uint32_t slot)
    404{
    405    if (slot == 0 && env->pkt_has_store_s1 &&
    406        ((env->slot_cancelled & (1 << 1)) == 0)) {
    407        HELPER(commit_store)(env, 1);
    408    }
    409}
    410
    411static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
    412                         target_ulong vaddr)
    413{
    414    uintptr_t ra = GETPC();
    415    check_noshuf(env, slot);
    416    return cpu_ldub_data_ra(env, vaddr, ra);
    417}
    418
    419static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
    420                          target_ulong vaddr)
    421{
    422    uintptr_t ra = GETPC();
    423    check_noshuf(env, slot);
    424    return cpu_lduw_data_ra(env, vaddr, ra);
    425}
    426
    427static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
    428                          target_ulong vaddr)
    429{
    430    uintptr_t ra = GETPC();
    431    check_noshuf(env, slot);
    432    return cpu_ldl_data_ra(env, vaddr, ra);
    433}
    434
    435static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
    436                          target_ulong vaddr)
    437{
    438    uintptr_t ra = GETPC();
    439    check_noshuf(env, slot);
    440    return cpu_ldq_data_ra(env, vaddr, ra);
    441}
    442
    443/* Floating point */
    444float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
    445{
    446    float64 out_f64;
    447    arch_fpop_start(env);
    448    out_f64 = float32_to_float64(RsV, &env->fp_status);
    449    arch_fpop_end(env);
    450    return out_f64;
    451}
    452
    453float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
    454{
    455    float32 out_f32;
    456    arch_fpop_start(env);
    457    out_f32 = float64_to_float32(RssV, &env->fp_status);
    458    arch_fpop_end(env);
    459    return out_f32;
    460}
    461
    462float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
    463{
    464    float32 RdV;
    465    arch_fpop_start(env);
    466    RdV = uint32_to_float32(RsV, &env->fp_status);
    467    arch_fpop_end(env);
    468    return RdV;
    469}
    470
    471float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
    472{
    473    float64 RddV;
    474    arch_fpop_start(env);
    475    RddV = uint32_to_float64(RsV, &env->fp_status);
    476    arch_fpop_end(env);
    477    return RddV;
    478}
    479
    480float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
    481{
    482    float32 RdV;
    483    arch_fpop_start(env);
    484    RdV = int32_to_float32(RsV, &env->fp_status);
    485    arch_fpop_end(env);
    486    return RdV;
    487}
    488
    489float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
    490{
    491    float64 RddV;
    492    arch_fpop_start(env);
    493    RddV = int32_to_float64(RsV, &env->fp_status);
    494    arch_fpop_end(env);
    495    return RddV;
    496}
    497
    498float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
    499{
    500    float32 RdV;
    501    arch_fpop_start(env);
    502    RdV = uint64_to_float32(RssV, &env->fp_status);
    503    arch_fpop_end(env);
    504    return RdV;
    505}
    506
    507float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
    508{
    509    float64 RddV;
    510    arch_fpop_start(env);
    511    RddV = uint64_to_float64(RssV, &env->fp_status);
    512    arch_fpop_end(env);
    513    return RddV;
    514}
    515
    516float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
    517{
    518    float32 RdV;
    519    arch_fpop_start(env);
    520    RdV = int64_to_float32(RssV, &env->fp_status);
    521    arch_fpop_end(env);
    522    return RdV;
    523}
    524
    525float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
    526{
    527    float64 RddV;
    528    arch_fpop_start(env);
    529    RddV = int64_to_float64(RssV, &env->fp_status);
    530    arch_fpop_end(env);
    531    return RddV;
    532}
    533
    534uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
    535{
    536    uint32_t RdV;
    537    arch_fpop_start(env);
    538    /* Hexagon checks the sign before rounding */
    539    if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
    540        float_raise(float_flag_invalid, &env->fp_status);
    541        RdV = 0;
    542    } else {
    543        RdV = float32_to_uint32(RsV, &env->fp_status);
    544    }
    545    arch_fpop_end(env);
    546    return RdV;
    547}
    548
    549int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
    550{
    551    int32_t RdV;
    552    arch_fpop_start(env);
    553    /* Hexagon returns -1 for NaN */
    554    if (float32_is_any_nan(RsV)) {
    555        float_raise(float_flag_invalid, &env->fp_status);
    556        RdV = -1;
    557    } else {
    558        RdV = float32_to_int32(RsV, &env->fp_status);
    559    }
    560    arch_fpop_end(env);
    561    return RdV;
    562}
    563
    564uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
    565{
    566    uint64_t RddV;
    567    arch_fpop_start(env);
    568    /* Hexagon checks the sign before rounding */
    569    if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
    570        float_raise(float_flag_invalid, &env->fp_status);
    571        RddV = 0;
    572    } else {
    573        RddV = float32_to_uint64(RsV, &env->fp_status);
    574    }
    575    arch_fpop_end(env);
    576    return RddV;
    577}
    578
    579int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
    580{
    581    int64_t RddV;
    582    arch_fpop_start(env);
    583    /* Hexagon returns -1 for NaN */
    584    if (float32_is_any_nan(RsV)) {
    585        float_raise(float_flag_invalid, &env->fp_status);
    586        RddV = -1;
    587    } else {
    588        RddV = float32_to_int64(RsV, &env->fp_status);
    589    }
    590    arch_fpop_end(env);
    591    return RddV;
    592}
    593
    594uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
    595{
    596    uint32_t RdV;
    597    arch_fpop_start(env);
    598    /* Hexagon checks the sign before rounding */
    599    if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
    600        float_raise(float_flag_invalid, &env->fp_status);
    601        RdV = 0;
    602    } else {
    603        RdV = float64_to_uint32(RssV, &env->fp_status);
    604    }
    605    arch_fpop_end(env);
    606    return RdV;
    607}
    608
    609int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
    610{
    611    int32_t RdV;
    612    arch_fpop_start(env);
    613    /* Hexagon returns -1 for NaN */
    614    if (float64_is_any_nan(RssV)) {
    615        float_raise(float_flag_invalid, &env->fp_status);
    616        RdV = -1;
    617    } else {
    618        RdV = float64_to_int32(RssV, &env->fp_status);
    619    }
    620    arch_fpop_end(env);
    621    return RdV;
    622}
    623
    624uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
    625{
    626    uint64_t RddV;
    627    arch_fpop_start(env);
    628    /* Hexagon checks the sign before rounding */
    629    if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
    630        float_raise(float_flag_invalid, &env->fp_status);
    631        RddV = 0;
    632    } else {
    633        RddV = float64_to_uint64(RssV, &env->fp_status);
    634    }
    635    arch_fpop_end(env);
    636    return RddV;
    637}
    638
    639int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
    640{
    641    int64_t RddV;
    642    arch_fpop_start(env);
    643    /* Hexagon returns -1 for NaN */
    644    if (float64_is_any_nan(RssV)) {
    645        float_raise(float_flag_invalid, &env->fp_status);
    646        RddV = -1;
    647    } else {
    648        RddV = float64_to_int64(RssV, &env->fp_status);
    649    }
    650    arch_fpop_end(env);
    651    return RddV;
    652}
    653
    654uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
    655{
    656    uint32_t RdV;
    657    arch_fpop_start(env);
    658    /* Hexagon checks the sign before rounding */
    659    if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
    660        float_raise(float_flag_invalid, &env->fp_status);
    661        RdV = 0;
    662    } else {
    663        RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
    664    }
    665    arch_fpop_end(env);
    666    return RdV;
    667}
    668
    669int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
    670{
    671    int32_t RdV;
    672    arch_fpop_start(env);
    673    /* Hexagon returns -1 for NaN */
    674    if (float32_is_any_nan(RsV)) {
    675        float_raise(float_flag_invalid, &env->fp_status);
    676        RdV = -1;
    677    } else {
    678        RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
    679    }
    680    arch_fpop_end(env);
    681    return RdV;
    682}
    683
    684uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
    685{
    686    uint64_t RddV;
    687    arch_fpop_start(env);
    688    /* Hexagon checks the sign before rounding */
    689    if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
    690        float_raise(float_flag_invalid, &env->fp_status);
    691        RddV = 0;
    692    } else {
    693        RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
    694    }
    695    arch_fpop_end(env);
    696    return RddV;
    697}
    698
    699int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
    700{
    701    int64_t RddV;
    702    arch_fpop_start(env);
    703    /* Hexagon returns -1 for NaN */
    704    if (float32_is_any_nan(RsV)) {
    705        float_raise(float_flag_invalid, &env->fp_status);
    706        RddV = -1;
    707    } else {
    708        RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
    709    }
    710    arch_fpop_end(env);
    711    return RddV;
    712}
    713
    714uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
    715{
    716    uint32_t RdV;
    717    arch_fpop_start(env);
    718    /* Hexagon checks the sign before rounding */
    719    if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
    720        float_raise(float_flag_invalid, &env->fp_status);
    721        RdV = 0;
    722    } else {
    723        RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
    724    }
    725    arch_fpop_end(env);
    726    return RdV;
    727}
    728
    729int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
    730{
    731    int32_t RdV;
    732    arch_fpop_start(env);
    733    /* Hexagon returns -1 for NaN */
    734    if (float64_is_any_nan(RssV)) {
    735        float_raise(float_flag_invalid, &env->fp_status);
    736        RdV = -1;
    737    } else {
    738        RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
    739    }
    740    arch_fpop_end(env);
    741    return RdV;
    742}
    743
    744uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
    745{
    746    uint64_t RddV;
    747    arch_fpop_start(env);
    748    /* Hexagon checks the sign before rounding */
    749    if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
    750        float_raise(float_flag_invalid, &env->fp_status);
    751        RddV = 0;
    752    } else {
    753        RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
    754    }
    755    arch_fpop_end(env);
    756    return RddV;
    757}
    758
    759int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
    760{
    761    int64_t RddV;
    762    arch_fpop_start(env);
    763    /* Hexagon returns -1 for NaN */
    764    if (float64_is_any_nan(RssV)) {
    765        float_raise(float_flag_invalid, &env->fp_status);
    766        RddV = -1;
    767    } else {
    768        RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
    769    }
    770    arch_fpop_end(env);
    771    return RddV;
    772}
    773
    774float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
    775{
    776    float32 RdV;
    777    arch_fpop_start(env);
    778    RdV = float32_add(RsV, RtV, &env->fp_status);
    779    arch_fpop_end(env);
    780    return RdV;
    781}
    782
    783float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
    784{
    785    float32 RdV;
    786    arch_fpop_start(env);
    787    RdV = float32_sub(RsV, RtV, &env->fp_status);
    788    arch_fpop_end(env);
    789    return RdV;
    790}
    791
    792int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
    793{
    794    int32_t PdV;
    795    arch_fpop_start(env);
    796    PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
    797    arch_fpop_end(env);
    798    return PdV;
    799}
    800
    801int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
    802{
    803    int cmp;
    804    int32_t PdV;
    805    arch_fpop_start(env);
    806    cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
    807    PdV = f8BITSOF(cmp == float_relation_greater);
    808    arch_fpop_end(env);
    809    return PdV;
    810}
    811
    812int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
    813{
    814    int cmp;
    815    int32_t PdV;
    816    arch_fpop_start(env);
    817    cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
    818    PdV = f8BITSOF(cmp == float_relation_greater ||
    819                   cmp == float_relation_equal);
    820    arch_fpop_end(env);
    821    return PdV;
    822}
    823
    824int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
    825{
    826    int32_t PdV;
    827    arch_fpop_start(env);
    828    PdV = f8BITSOF(float32_is_any_nan(RsV) ||
    829                   float32_is_any_nan(RtV));
    830    arch_fpop_end(env);
    831    return PdV;
    832}
    833
    834float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
    835{
    836    float32 RdV;
    837    arch_fpop_start(env);
    838    RdV = float32_maxnum(RsV, RtV, &env->fp_status);
    839    arch_fpop_end(env);
    840    return RdV;
    841}
    842
    843float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
    844{
    845    float32 RdV;
    846    arch_fpop_start(env);
    847    RdV = float32_minnum(RsV, RtV, &env->fp_status);
    848    arch_fpop_end(env);
    849    return RdV;
    850}
    851
    852int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
    853{
    854    int32_t PdV = 0;
    855    arch_fpop_start(env);
    856    if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
    857        PdV = 0xff;
    858    }
    859    if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
    860        PdV = 0xff;
    861    }
    862    if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
    863        PdV = 0xff;
    864    }
    865    if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
    866        PdV = 0xff;
    867    }
    868    if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
    869        PdV = 0xff;
    870    }
    871    set_float_exception_flags(0, &env->fp_status);
    872    arch_fpop_end(env);
    873    return PdV;
    874}
    875
    876float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
    877{
    878    float32 RdV = 0;
    879    int adjust;
    880    arch_fpop_start(env);
    881    arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
    882    RdV = RsV;
    883    arch_fpop_end(env);
    884    return RdV;
    885}
    886
    887float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
    888{
    889    float32 RdV = 0;
    890    int adjust;
    891    arch_fpop_start(env);
    892    arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
    893    RdV = RtV;
    894    arch_fpop_end(env);
    895    return RdV;
    896}
    897
    898float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
    899{
    900    float32 RdV = 0;
    901    int adjust;
    902    arch_fpop_start(env);
    903    arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
    904    RdV = RsV;
    905    arch_fpop_end(env);
    906    return RdV;
    907}
    908
    909float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
    910{
    911    float64 RddV;
    912    arch_fpop_start(env);
    913    RddV = float64_add(RssV, RttV, &env->fp_status);
    914    arch_fpop_end(env);
    915    return RddV;
    916}
    917
    918float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
    919{
    920    float64 RddV;
    921    arch_fpop_start(env);
    922    RddV = float64_sub(RssV, RttV, &env->fp_status);
    923    arch_fpop_end(env);
    924    return RddV;
    925}
    926
    927float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
    928{
    929    float64 RddV;
    930    arch_fpop_start(env);
    931    RddV = float64_maxnum(RssV, RttV, &env->fp_status);
    932    if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
    933        float_raise(float_flag_invalid, &env->fp_status);
    934    }
    935    arch_fpop_end(env);
    936    return RddV;
    937}
    938
    939float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
    940{
    941    float64 RddV;
    942    arch_fpop_start(env);
    943    RddV = float64_minnum(RssV, RttV, &env->fp_status);
    944    if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
    945        float_raise(float_flag_invalid, &env->fp_status);
    946    }
    947    arch_fpop_end(env);
    948    return RddV;
    949}
    950
    951int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
    952{
    953    int32_t PdV;
    954    arch_fpop_start(env);
    955    PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
    956    arch_fpop_end(env);
    957    return PdV;
    958}
    959
    960int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
    961{
    962    int cmp;
    963    int32_t PdV;
    964    arch_fpop_start(env);
    965    cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
    966    PdV = f8BITSOF(cmp == float_relation_greater);
    967    arch_fpop_end(env);
    968    return PdV;
    969}
    970
    971int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
    972{
    973    int cmp;
    974    int32_t PdV;
    975    arch_fpop_start(env);
    976    cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
    977    PdV = f8BITSOF(cmp == float_relation_greater ||
    978                   cmp == float_relation_equal);
    979    arch_fpop_end(env);
    980    return PdV;
    981}
    982
    983int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
    984{
    985    int32_t PdV;
    986    arch_fpop_start(env);
    987    PdV = f8BITSOF(float64_is_any_nan(RssV) ||
    988                   float64_is_any_nan(RttV));
    989    arch_fpop_end(env);
    990    return PdV;
    991}
    992
    993int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
    994{
    995    int32_t PdV = 0;
    996    arch_fpop_start(env);
    997    if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
    998        PdV = 0xff;
    999    }
   1000    if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
   1001        PdV = 0xff;
   1002    }
   1003    if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
   1004        PdV = 0xff;
   1005    }
   1006    if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
   1007        PdV = 0xff;
   1008    }
   1009    if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
   1010        PdV = 0xff;
   1011    }
   1012    set_float_exception_flags(0, &env->fp_status);
   1013    arch_fpop_end(env);
   1014    return PdV;
   1015}
   1016
   1017float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
   1018{
   1019    float32 RdV;
   1020    arch_fpop_start(env);
   1021    RdV = internal_mpyf(RsV, RtV, &env->fp_status);
   1022    arch_fpop_end(env);
   1023    return RdV;
   1024}
   1025
   1026float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
   1027                      float32 RsV, float32 RtV)
   1028{
   1029    arch_fpop_start(env);
   1030    RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
   1031    arch_fpop_end(env);
   1032    return RxV;
   1033}
   1034
   1035static bool is_zero_prod(float32 a, float32 b)
   1036{
   1037    return ((float32_is_zero(a) && is_finite(b)) ||
   1038            (float32_is_zero(b) && is_finite(a)));
   1039}
   1040
   1041static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
   1042{
   1043    float32 ret = dst;
   1044    if (float32_is_any_nan(x)) {
   1045        if (extract32(x, 22, 1) == 0) {
   1046            float_raise(float_flag_invalid, fp_status);
   1047        }
   1048        ret = make_float32(0xffffffff);    /* nan */
   1049    }
   1050    return ret;
   1051}
   1052
   1053float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
   1054                         float32 RsV, float32 RtV, float32 PuV)
   1055{
   1056    size4s_t tmp;
   1057    arch_fpop_start(env);
   1058    RxV = check_nan(RxV, RxV, &env->fp_status);
   1059    RxV = check_nan(RxV, RsV, &env->fp_status);
   1060    RxV = check_nan(RxV, RtV, &env->fp_status);
   1061    tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
   1062    if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
   1063        RxV = tmp;
   1064    }
   1065    arch_fpop_end(env);
   1066    return RxV;
   1067}
   1068
   1069float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
   1070                      float32 RsV, float32 RtV)
   1071{
   1072    float32 neg_RsV;
   1073    arch_fpop_start(env);
   1074    neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
   1075    RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
   1076    arch_fpop_end(env);
   1077    return RxV;
   1078}
   1079
   1080static bool is_inf_prod(int32_t a, int32_t b)
   1081{
   1082    return (float32_is_infinity(a) && float32_is_infinity(b)) ||
   1083           (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
   1084           (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
   1085}
   1086
   1087float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
   1088                          float32 RsV, float32 RtV)
   1089{
   1090    bool infinp;
   1091    bool infminusinf;
   1092    float32 tmp;
   1093
   1094    arch_fpop_start(env);
   1095    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
   1096    infminusinf = float32_is_infinity(RxV) &&
   1097                  is_inf_prod(RsV, RtV) &&
   1098                  (fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
   1099    infinp = float32_is_infinity(RxV) ||
   1100             float32_is_infinity(RtV) ||
   1101             float32_is_infinity(RsV);
   1102    RxV = check_nan(RxV, RxV, &env->fp_status);
   1103    RxV = check_nan(RxV, RsV, &env->fp_status);
   1104    RxV = check_nan(RxV, RtV, &env->fp_status);
   1105    tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
   1106    if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
   1107        RxV = tmp;
   1108    }
   1109    set_float_exception_flags(0, &env->fp_status);
   1110    if (float32_is_infinity(RxV) && !infinp) {
   1111        RxV = RxV - 1;
   1112    }
   1113    if (infminusinf) {
   1114        RxV = 0;
   1115    }
   1116    arch_fpop_end(env);
   1117    return RxV;
   1118}
   1119
   1120float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
   1121                          float32 RsV, float32 RtV)
   1122{
   1123    bool infinp;
   1124    bool infminusinf;
   1125    float32 tmp;
   1126
   1127    arch_fpop_start(env);
   1128    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
   1129    infminusinf = float32_is_infinity(RxV) &&
   1130                  is_inf_prod(RsV, RtV) &&
   1131                  (fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
   1132    infinp = float32_is_infinity(RxV) ||
   1133             float32_is_infinity(RtV) ||
   1134             float32_is_infinity(RsV);
   1135    RxV = check_nan(RxV, RxV, &env->fp_status);
   1136    RxV = check_nan(RxV, RsV, &env->fp_status);
   1137    RxV = check_nan(RxV, RtV, &env->fp_status);
   1138    float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
   1139    tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
   1140    if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
   1141        RxV = tmp;
   1142    }
   1143    set_float_exception_flags(0, &env->fp_status);
   1144    if (float32_is_infinity(RxV) && !infinp) {
   1145        RxV = RxV - 1;
   1146    }
   1147    if (infminusinf) {
   1148        RxV = 0;
   1149    }
   1150    arch_fpop_end(env);
   1151    return RxV;
   1152}
   1153
   1154float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
   1155{
   1156    int64_t RddV;
   1157    arch_fpop_start(env);
   1158    if (float64_is_denormal(RssV) &&
   1159        (float64_getexp(RttV) >= 512) &&
   1160        float64_is_normal(RttV)) {
   1161        RddV = float64_mul(RssV, make_float64(0x4330000000000000),
   1162                           &env->fp_status);
   1163    } else if (float64_is_denormal(RttV) &&
   1164               (float64_getexp(RssV) >= 512) &&
   1165               float64_is_normal(RssV)) {
   1166        RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
   1167                           &env->fp_status);
   1168    } else {
   1169        RddV = RssV;
   1170    }
   1171    arch_fpop_end(env);
   1172    return RddV;
   1173}
   1174
   1175float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
   1176                        float64 RssV, float64 RttV)
   1177{
   1178    arch_fpop_start(env);
   1179    RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
   1180    arch_fpop_end(env);
   1181    return RxxV;
   1182}
   1183
   1184static void cancel_slot(CPUHexagonState *env, uint32_t slot)
   1185{
   1186    HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
   1187    env->slot_cancelled |= (1 << slot);
   1188}
   1189
   1190/* These macros can be referenced in the generated helper functions */
   1191#define warn(...) /* Nothing */
   1192#define fatal(...) g_assert_not_reached();
   1193
   1194#define BOGUS_HELPER(tag) \
   1195    printf("ERROR: bogus helper: " #tag "\n")
   1196
   1197#include "helper_funcs_generated.c.inc"