1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2/* 3 * Copyright (c) 2021 Loongson Technology Corporation Limited 4 */ 5 6static const uint32_t fcsr_mask[4] = { 7 UINT32_MAX, FCSR0_M1, FCSR0_M2, FCSR0_M3 8}; 9 10static bool trans_fsel(DisasContext *ctx, arg_fsel *a) 11{ 12 TCGv zero = tcg_constant_tl(0); 13 TCGv dest = get_fpr(ctx, a->fd); 14 TCGv src1 = get_fpr(ctx, a->fj); 15 TCGv src2 = get_fpr(ctx, a->fk); 16 TCGv cond; 17 18 if (!avail_FP(ctx)) { 19 return false; 20 } 21 22 CHECK_FPE; 23 24 cond = tcg_temp_new(); 25 tcg_gen_ld8u_tl(cond, tcg_env, offsetof(CPULoongArchState, cf[a->ca])); 26 tcg_gen_movcond_tl(TCG_COND_EQ, dest, cond, zero, src1, src2); 27 set_fpr(a->fd, dest); 28 29 return true; 30} 31 32static bool gen_f2f(DisasContext *ctx, arg_ff *a, 33 void (*func)(TCGv, TCGv), bool nanbox) 34{ 35 TCGv dest = get_fpr(ctx, a->fd); 36 TCGv src = get_fpr(ctx, a->fj); 37 38 CHECK_FPE; 39 40 func(dest, src); 41 if (nanbox) { 42 gen_nanbox_s(dest, dest); 43 } 44 set_fpr(a->fd, dest); 45 46 return true; 47} 48 49static bool gen_r2f(DisasContext *ctx, arg_fr *a, 50 void (*func)(TCGv, TCGv)) 51{ 52 TCGv src = gpr_src(ctx, a->rj, EXT_NONE); 53 TCGv dest = get_fpr(ctx, a->fd); 54 55 if (!avail_FP(ctx)) { 56 return false; 57 } 58 59 CHECK_FPE; 60 61 func(dest, src); 62 set_fpr(a->fd, dest); 63 64 return true; 65} 66 67static bool gen_f2r(DisasContext *ctx, arg_rf *a, 68 void (*func)(TCGv, TCGv)) 69{ 70 TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); 71 TCGv src = get_fpr(ctx, a->fj); 72 73 if (!avail_FP(ctx)) { 74 return false; 75 } 76 77 CHECK_FPE; 78 79 func(dest, src); 80 gen_set_gpr(a->rd, dest, EXT_NONE); 81 82 return true; 83} 84 85static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) 86{ 87 uint32_t mask = fcsr_mask[a->fcsrd]; 88 TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE); 89 90 if (!avail_FP(ctx)) { 91 return false; 92 } 93 94 CHECK_FPE; 95 96 if (mask == UINT32_MAX) { 97 tcg_gen_st32_i64(Rj, tcg_env, offsetof(CPULoongArchState, fcsr0)); 98 } else { 99 TCGv_i32 fcsr0 = tcg_temp_new_i32(); 100 TCGv_i32 temp = tcg_temp_new_i32(); 101 102 tcg_gen_ld_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0)); 103 tcg_gen_extrl_i64_i32(temp, Rj); 104 tcg_gen_andi_i32(temp, temp, mask); 105 tcg_gen_andi_i32(fcsr0, fcsr0, ~mask); 106 tcg_gen_or_i32(fcsr0, fcsr0, temp); 107 tcg_gen_st_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0)); 108 } 109 110 /* 111 * Install the new rounding mode to fpu_status, if changed. 112 * Note that FCSR3 is exactly the rounding mode field. 113 */ 114 if (mask & FCSR0_M3) { 115 gen_helper_set_rounding_mode(tcg_env); 116 } 117 return true; 118} 119 120static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) 121{ 122 TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); 123 124 if (!avail_FP(ctx)) { 125 return false; 126 } 127 128 CHECK_FPE; 129 130 tcg_gen_ld32u_i64(dest, tcg_env, offsetof(CPULoongArchState, fcsr0)); 131 tcg_gen_andi_i64(dest, dest, fcsr_mask[a->fcsrs]); 132 gen_set_gpr(a->rd, dest, EXT_NONE); 133 134 return true; 135} 136 137static void gen_movgr2fr_w(TCGv dest, TCGv src) 138{ 139 tcg_gen_deposit_i64(dest, dest, src, 0, 32); 140} 141 142static void gen_movgr2frh_w(TCGv dest, TCGv src) 143{ 144 tcg_gen_deposit_i64(dest, dest, src, 32, 32); 145} 146 147static void gen_movfrh2gr_s(TCGv dest, TCGv src) 148{ 149 tcg_gen_sextract_tl(dest, src, 32, 32); 150} 151 152static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) 153{ 154 TCGv t0; 155 TCGv src = get_fpr(ctx, a->fj); 156 157 if (!avail_FP(ctx)) { 158 return false; 159 } 160 161 CHECK_FPE; 162 163 t0 = tcg_temp_new(); 164 tcg_gen_andi_tl(t0, src, 0x1); 165 tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); 166 167 return true; 168} 169 170static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) 171{ 172 TCGv dest = get_fpr(ctx, a->fd); 173 174 if (!avail_FP(ctx)) { 175 return false; 176 } 177 178 CHECK_FPE; 179 180 tcg_gen_ld8u_tl(dest, tcg_env, 181 offsetof(CPULoongArchState, cf[a->cj & 0x7])); 182 set_fpr(a->fd, dest); 183 184 return true; 185} 186 187static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) 188{ 189 TCGv t0; 190 191 if (!avail_FP(ctx)) { 192 return false; 193 } 194 195 CHECK_FPE; 196 197 t0 = tcg_temp_new(); 198 tcg_gen_andi_tl(t0, gpr_src(ctx, a->rj, EXT_NONE), 0x1); 199 tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); 200 201 return true; 202} 203 204static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) 205{ 206 if (!avail_FP(ctx)) { 207 return false; 208 } 209 210 CHECK_FPE; 211 212 tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), tcg_env, 213 offsetof(CPULoongArchState, cf[a->cj & 0x7])); 214 return true; 215} 216 217TRANS(fmov_s, FP_SP, gen_f2f, tcg_gen_mov_tl, true) 218TRANS(fmov_d, FP_DP, gen_f2f, tcg_gen_mov_tl, false) 219TRANS(movgr2fr_w, FP_SP, gen_r2f, gen_movgr2fr_w) 220TRANS(movgr2fr_d, 64, gen_r2f, tcg_gen_mov_tl) 221TRANS(movgr2frh_w, FP_DP, gen_r2f, gen_movgr2frh_w) 222TRANS(movfr2gr_s, FP_SP, gen_f2r, tcg_gen_ext32s_tl) 223TRANS(movfr2gr_d, 64, gen_f2r, tcg_gen_mov_tl) 224TRANS(movfrh2gr_s, FP_DP, gen_f2r, gen_movfrh2gr_s) 225