1*5c23704eSSong Gao/* SPDX-License-Identifier: GPL-2.0-or-later */ 2*5c23704eSSong Gao/* 3*5c23704eSSong Gao * Copyright (c) 2021 Loongson Technology Corporation Limited 4*5c23704eSSong Gao */ 5*5c23704eSSong Gao 6*5c23704eSSong Gaostatic bool gen_rrr(DisasContext *ctx, arg_rrr *a, 7*5c23704eSSong Gao DisasExtend src1_ext, DisasExtend src2_ext, 8*5c23704eSSong Gao DisasExtend dst_ext, void (*func)(TCGv, TCGv, TCGv)) 9*5c23704eSSong Gao{ 10*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, dst_ext); 11*5c23704eSSong Gao TCGv src1 = gpr_src(ctx, a->rj, src1_ext); 12*5c23704eSSong Gao TCGv src2 = gpr_src(ctx, a->rk, src2_ext); 13*5c23704eSSong Gao 14*5c23704eSSong Gao func(dest, src1, src2); 15*5c23704eSSong Gao gen_set_gpr(a->rd, dest, dst_ext); 16*5c23704eSSong Gao 17*5c23704eSSong Gao return true; 18*5c23704eSSong Gao} 19*5c23704eSSong Gao 20*5c23704eSSong Gaostatic bool gen_rri_v(DisasContext *ctx, arg_rr_i *a, 21*5c23704eSSong Gao DisasExtend src_ext, DisasExtend dst_ext, 22*5c23704eSSong Gao void (*func)(TCGv, TCGv, TCGv)) 23*5c23704eSSong Gao{ 24*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, dst_ext); 25*5c23704eSSong Gao TCGv src1 = gpr_src(ctx, a->rj, src_ext); 26*5c23704eSSong Gao TCGv src2 = tcg_constant_tl(a->imm); 27*5c23704eSSong Gao 28*5c23704eSSong Gao func(dest, src1, src2); 29*5c23704eSSong Gao gen_set_gpr(a->rd, dest, dst_ext); 30*5c23704eSSong Gao 31*5c23704eSSong Gao return true; 32*5c23704eSSong Gao} 33*5c23704eSSong Gao 34*5c23704eSSong Gaostatic bool gen_rri_c(DisasContext *ctx, arg_rr_i *a, 35*5c23704eSSong Gao DisasExtend src_ext, DisasExtend dst_ext, 36*5c23704eSSong Gao void (*func)(TCGv, TCGv, target_long)) 37*5c23704eSSong Gao{ 38*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, dst_ext); 39*5c23704eSSong Gao TCGv src1 = gpr_src(ctx, a->rj, src_ext); 40*5c23704eSSong Gao 41*5c23704eSSong Gao func(dest, src1, a->imm); 42*5c23704eSSong Gao gen_set_gpr(a->rd, dest, dst_ext); 43*5c23704eSSong Gao 44*5c23704eSSong Gao return true; 45*5c23704eSSong Gao} 46*5c23704eSSong Gao 47*5c23704eSSong Gaostatic bool gen_rrr_sa(DisasContext *ctx, arg_rrr_sa *a, 48*5c23704eSSong Gao DisasExtend src_ext, DisasExtend dst_ext, 49*5c23704eSSong Gao void (*func)(TCGv, TCGv, TCGv, target_long)) 50*5c23704eSSong Gao{ 51*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, dst_ext); 52*5c23704eSSong Gao TCGv src1 = gpr_src(ctx, a->rj, src_ext); 53*5c23704eSSong Gao TCGv src2 = gpr_src(ctx, a->rk, src_ext); 54*5c23704eSSong Gao 55*5c23704eSSong Gao func(dest, src1, src2, a->sa); 56*5c23704eSSong Gao gen_set_gpr(a->rd, dest, dst_ext); 57*5c23704eSSong Gao 58*5c23704eSSong Gao return true; 59*5c23704eSSong Gao} 60*5c23704eSSong Gao 61*5c23704eSSong Gaostatic bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) 62*5c23704eSSong Gao{ 63*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); 64*5c23704eSSong Gao 65*5c23704eSSong Gao tcg_gen_movi_tl(dest, a->imm << 12); 66*5c23704eSSong Gao gen_set_gpr(a->rd, dest, EXT_NONE); 67*5c23704eSSong Gao 68*5c23704eSSong Gao return true; 69*5c23704eSSong Gao} 70*5c23704eSSong Gao 71*5c23704eSSong Gaostatic bool gen_pc(DisasContext *ctx, arg_r_i *a, 72*5c23704eSSong Gao target_ulong (*func)(target_ulong, int)) 73*5c23704eSSong Gao{ 74*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); 75*5c23704eSSong Gao target_ulong addr = make_address_pc(ctx, func(ctx->base.pc_next, a->imm)); 76*5c23704eSSong Gao 77*5c23704eSSong Gao tcg_gen_movi_tl(dest, addr); 78*5c23704eSSong Gao gen_set_gpr(a->rd, dest, EXT_NONE); 79*5c23704eSSong Gao 80*5c23704eSSong Gao return true; 81*5c23704eSSong Gao} 82*5c23704eSSong Gao 83*5c23704eSSong Gaostatic void gen_slt(TCGv dest, TCGv src1, TCGv src2) 84*5c23704eSSong Gao{ 85*5c23704eSSong Gao tcg_gen_setcond_tl(TCG_COND_LT, dest, src1, src2); 86*5c23704eSSong Gao} 87*5c23704eSSong Gao 88*5c23704eSSong Gaostatic void gen_sltu(TCGv dest, TCGv src1, TCGv src2) 89*5c23704eSSong Gao{ 90*5c23704eSSong Gao tcg_gen_setcond_tl(TCG_COND_LTU, dest, src1, src2); 91*5c23704eSSong Gao} 92*5c23704eSSong Gao 93*5c23704eSSong Gaostatic void gen_mulh_w(TCGv dest, TCGv src1, TCGv src2) 94*5c23704eSSong Gao{ 95*5c23704eSSong Gao tcg_gen_mul_i64(dest, src1, src2); 96*5c23704eSSong Gao tcg_gen_sari_i64(dest, dest, 32); 97*5c23704eSSong Gao} 98*5c23704eSSong Gao 99*5c23704eSSong Gaostatic void gen_mulh_d(TCGv dest, TCGv src1, TCGv src2) 100*5c23704eSSong Gao{ 101*5c23704eSSong Gao TCGv discard = tcg_temp_new(); 102*5c23704eSSong Gao tcg_gen_muls2_tl(discard, dest, src1, src2); 103*5c23704eSSong Gao} 104*5c23704eSSong Gao 105*5c23704eSSong Gaostatic void gen_mulh_du(TCGv dest, TCGv src1, TCGv src2) 106*5c23704eSSong Gao{ 107*5c23704eSSong Gao TCGv discard = tcg_temp_new(); 108*5c23704eSSong Gao tcg_gen_mulu2_tl(discard, dest, src1, src2); 109*5c23704eSSong Gao} 110*5c23704eSSong Gao 111*5c23704eSSong Gaostatic void prep_divisor_d(TCGv ret, TCGv src1, TCGv src2) 112*5c23704eSSong Gao{ 113*5c23704eSSong Gao TCGv t0 = tcg_temp_new(); 114*5c23704eSSong Gao TCGv t1 = tcg_temp_new(); 115*5c23704eSSong Gao TCGv zero = tcg_constant_tl(0); 116*5c23704eSSong Gao 117*5c23704eSSong Gao /* 118*5c23704eSSong Gao * If min / -1, set the divisor to 1. 119*5c23704eSSong Gao * This avoids potential host overflow trap and produces min. 120*5c23704eSSong Gao * If x / 0, set the divisor to 1. 121*5c23704eSSong Gao * This avoids potential host overflow trap; 122*5c23704eSSong Gao * the required result is undefined. 123*5c23704eSSong Gao */ 124*5c23704eSSong Gao tcg_gen_setcondi_tl(TCG_COND_EQ, ret, src1, INT64_MIN); 125*5c23704eSSong Gao tcg_gen_setcondi_tl(TCG_COND_EQ, t0, src2, -1); 126*5c23704eSSong Gao tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src2, 0); 127*5c23704eSSong Gao tcg_gen_and_tl(ret, ret, t0); 128*5c23704eSSong Gao tcg_gen_or_tl(ret, ret, t1); 129*5c23704eSSong Gao tcg_gen_movcond_tl(TCG_COND_NE, ret, ret, zero, ret, src2); 130*5c23704eSSong Gao} 131*5c23704eSSong Gao 132*5c23704eSSong Gaostatic void prep_divisor_du(TCGv ret, TCGv src2) 133*5c23704eSSong Gao{ 134*5c23704eSSong Gao TCGv zero = tcg_constant_tl(0); 135*5c23704eSSong Gao TCGv one = tcg_constant_tl(1); 136*5c23704eSSong Gao 137*5c23704eSSong Gao /* 138*5c23704eSSong Gao * If x / 0, set the divisor to 1. 139*5c23704eSSong Gao * This avoids potential host overflow trap; 140*5c23704eSSong Gao * the required result is undefined. 141*5c23704eSSong Gao */ 142*5c23704eSSong Gao tcg_gen_movcond_tl(TCG_COND_EQ, ret, src2, zero, one, src2); 143*5c23704eSSong Gao} 144*5c23704eSSong Gao 145*5c23704eSSong Gaostatic void gen_div_d(TCGv dest, TCGv src1, TCGv src2) 146*5c23704eSSong Gao{ 147*5c23704eSSong Gao TCGv t0 = tcg_temp_new(); 148*5c23704eSSong Gao prep_divisor_d(t0, src1, src2); 149*5c23704eSSong Gao tcg_gen_div_tl(dest, src1, t0); 150*5c23704eSSong Gao} 151*5c23704eSSong Gao 152*5c23704eSSong Gaostatic void gen_rem_d(TCGv dest, TCGv src1, TCGv src2) 153*5c23704eSSong Gao{ 154*5c23704eSSong Gao TCGv t0 = tcg_temp_new(); 155*5c23704eSSong Gao prep_divisor_d(t0, src1, src2); 156*5c23704eSSong Gao tcg_gen_rem_tl(dest, src1, t0); 157*5c23704eSSong Gao} 158*5c23704eSSong Gao 159*5c23704eSSong Gaostatic void gen_div_du(TCGv dest, TCGv src1, TCGv src2) 160*5c23704eSSong Gao{ 161*5c23704eSSong Gao TCGv t0 = tcg_temp_new(); 162*5c23704eSSong Gao prep_divisor_du(t0, src2); 163*5c23704eSSong Gao tcg_gen_divu_tl(dest, src1, t0); 164*5c23704eSSong Gao} 165*5c23704eSSong Gao 166*5c23704eSSong Gaostatic void gen_rem_du(TCGv dest, TCGv src1, TCGv src2) 167*5c23704eSSong Gao{ 168*5c23704eSSong Gao TCGv t0 = tcg_temp_new(); 169*5c23704eSSong Gao prep_divisor_du(t0, src2); 170*5c23704eSSong Gao tcg_gen_remu_tl(dest, src1, t0); 171*5c23704eSSong Gao} 172*5c23704eSSong Gao 173*5c23704eSSong Gaostatic void gen_div_w(TCGv dest, TCGv src1, TCGv src2) 174*5c23704eSSong Gao{ 175*5c23704eSSong Gao TCGv t0 = tcg_temp_new(); 176*5c23704eSSong Gao /* We need not check for integer overflow for div_w. */ 177*5c23704eSSong Gao prep_divisor_du(t0, src2); 178*5c23704eSSong Gao tcg_gen_div_tl(dest, src1, t0); 179*5c23704eSSong Gao} 180*5c23704eSSong Gao 181*5c23704eSSong Gaostatic void gen_rem_w(TCGv dest, TCGv src1, TCGv src2) 182*5c23704eSSong Gao{ 183*5c23704eSSong Gao TCGv t0 = tcg_temp_new(); 184*5c23704eSSong Gao /* We need not check for integer overflow for rem_w. */ 185*5c23704eSSong Gao prep_divisor_du(t0, src2); 186*5c23704eSSong Gao tcg_gen_rem_tl(dest, src1, t0); 187*5c23704eSSong Gao} 188*5c23704eSSong Gao 189*5c23704eSSong Gaostatic void gen_alsl(TCGv dest, TCGv src1, TCGv src2, target_long sa) 190*5c23704eSSong Gao{ 191*5c23704eSSong Gao TCGv t0 = tcg_temp_new(); 192*5c23704eSSong Gao tcg_gen_shli_tl(t0, src1, sa); 193*5c23704eSSong Gao tcg_gen_add_tl(dest, t0, src2); 194*5c23704eSSong Gao} 195*5c23704eSSong Gao 196*5c23704eSSong Gaostatic bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) 197*5c23704eSSong Gao{ 198*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); 199*5c23704eSSong Gao TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); 200*5c23704eSSong Gao TCGv src2 = tcg_constant_tl(a->imm); 201*5c23704eSSong Gao 202*5c23704eSSong Gao if (!avail_64(ctx)) { 203*5c23704eSSong Gao return false; 204*5c23704eSSong Gao } 205*5c23704eSSong Gao 206*5c23704eSSong Gao tcg_gen_deposit_tl(dest, src1, src2, 32, 32); 207*5c23704eSSong Gao gen_set_gpr(a->rd, dest, EXT_NONE); 208*5c23704eSSong Gao 209*5c23704eSSong Gao return true; 210*5c23704eSSong Gao} 211*5c23704eSSong Gao 212*5c23704eSSong Gaostatic bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) 213*5c23704eSSong Gao{ 214*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); 215*5c23704eSSong Gao TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); 216*5c23704eSSong Gao TCGv src2 = tcg_constant_tl(a->imm); 217*5c23704eSSong Gao 218*5c23704eSSong Gao if (!avail_64(ctx)) { 219*5c23704eSSong Gao return false; 220*5c23704eSSong Gao } 221*5c23704eSSong Gao 222*5c23704eSSong Gao tcg_gen_deposit_tl(dest, src1, src2, 52, 12); 223*5c23704eSSong Gao gen_set_gpr(a->rd, dest, EXT_NONE); 224*5c23704eSSong Gao 225*5c23704eSSong Gao return true; 226*5c23704eSSong Gao} 227*5c23704eSSong Gao 228*5c23704eSSong Gaostatic target_ulong gen_pcaddi(target_ulong pc, int imm) 229*5c23704eSSong Gao{ 230*5c23704eSSong Gao return pc + (imm << 2); 231*5c23704eSSong Gao} 232*5c23704eSSong Gao 233*5c23704eSSong Gaostatic target_ulong gen_pcalau12i(target_ulong pc, int imm) 234*5c23704eSSong Gao{ 235*5c23704eSSong Gao return (pc + (imm << 12)) & ~0xfff; 236*5c23704eSSong Gao} 237*5c23704eSSong Gao 238*5c23704eSSong Gaostatic target_ulong gen_pcaddu12i(target_ulong pc, int imm) 239*5c23704eSSong Gao{ 240*5c23704eSSong Gao return pc + (imm << 12); 241*5c23704eSSong Gao} 242*5c23704eSSong Gao 243*5c23704eSSong Gaostatic target_ulong gen_pcaddu18i(target_ulong pc, int imm) 244*5c23704eSSong Gao{ 245*5c23704eSSong Gao return pc + ((target_ulong)(imm) << 18); 246*5c23704eSSong Gao} 247*5c23704eSSong Gao 248*5c23704eSSong Gaostatic bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) 249*5c23704eSSong Gao{ 250*5c23704eSSong Gao TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); 251*5c23704eSSong Gao TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); 252*5c23704eSSong Gao 253*5c23704eSSong Gao if (!avail_64(ctx)) { 254*5c23704eSSong Gao return false; 255*5c23704eSSong Gao } 256*5c23704eSSong Gao 257*5c23704eSSong Gao tcg_gen_addi_tl(dest, src1, a->imm << 16); 258*5c23704eSSong Gao gen_set_gpr(a->rd, dest, EXT_NONE); 259*5c23704eSSong Gao 260*5c23704eSSong Gao return true; 261*5c23704eSSong Gao} 262*5c23704eSSong Gao 263*5c23704eSSong GaoTRANS(add_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl) 264*5c23704eSSong GaoTRANS(add_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) 265*5c23704eSSong GaoTRANS(sub_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl) 266*5c23704eSSong GaoTRANS(sub_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) 267*5c23704eSSong GaoTRANS(and, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl) 268*5c23704eSSong GaoTRANS(or, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl) 269*5c23704eSSong GaoTRANS(xor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl) 270*5c23704eSSong GaoTRANS(nor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl) 271*5c23704eSSong GaoTRANS(andn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl) 272*5c23704eSSong GaoTRANS(orn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl) 273*5c23704eSSong GaoTRANS(slt, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt) 274*5c23704eSSong GaoTRANS(sltu, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu) 275*5c23704eSSong GaoTRANS(mul_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl) 276*5c23704eSSong GaoTRANS(mul_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) 277*5c23704eSSong GaoTRANS(mulh_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w) 278*5c23704eSSong GaoTRANS(mulh_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w) 279*5c23704eSSong GaoTRANS(mulh_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) 280*5c23704eSSong GaoTRANS(mulh_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) 281*5c23704eSSong GaoTRANS(mulw_d_w, 64, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) 282*5c23704eSSong GaoTRANS(mulw_d_wu, 64, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) 283*5c23704eSSong GaoTRANS(div_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w) 284*5c23704eSSong GaoTRANS(mod_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w) 285*5c23704eSSong GaoTRANS(div_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du) 286*5c23704eSSong GaoTRANS(mod_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du) 287*5c23704eSSong GaoTRANS(div_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) 288*5c23704eSSong GaoTRANS(mod_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) 289*5c23704eSSong GaoTRANS(div_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) 290*5c23704eSSong GaoTRANS(mod_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) 291*5c23704eSSong GaoTRANS(slti, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt) 292*5c23704eSSong GaoTRANS(sltui, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu) 293*5c23704eSSong GaoTRANS(addi_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl) 294*5c23704eSSong GaoTRANS(addi_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) 295*5c23704eSSong GaoTRANS(alsl_w, ALL, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl) 296*5c23704eSSong GaoTRANS(alsl_wu, 64, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) 297*5c23704eSSong GaoTRANS(alsl_d, 64, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) 298*5c23704eSSong GaoTRANS(pcaddi, ALL, gen_pc, gen_pcaddi) 299*5c23704eSSong GaoTRANS(pcalau12i, ALL, gen_pc, gen_pcalau12i) 300*5c23704eSSong GaoTRANS(pcaddu12i, ALL, gen_pc, gen_pcaddu12i) 301*5c23704eSSong GaoTRANS(pcaddu18i, 64, gen_pc, gen_pcaddu18i) 302*5c23704eSSong GaoTRANS(andi, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl) 303*5c23704eSSong GaoTRANS(ori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl) 304*5c23704eSSong GaoTRANS(xori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl) 305