1/* 2 * RISC-V translation routines for the Zc[b,mp,mt] Standard Extensions. 3 * 4 * Copyright (c) 2021-2022 PLCT Lab 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2 or later, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19#define REQUIRE_ZCB(ctx) do { \ 20 if (!ctx->cfg_ptr->ext_zcb) \ 21 return false; \ 22} while (0) 23 24#define REQUIRE_ZCMP(ctx) do { \ 25 if (!ctx->cfg_ptr->ext_zcmp) \ 26 return false; \ 27} while (0) 28 29#define REQUIRE_ZCMT(ctx) do { \ 30 if (!ctx->cfg_ptr->ext_zcmt) \ 31 return false; \ 32} while (0) 33 34static bool trans_c_zext_b(DisasContext *ctx, arg_c_zext_b *a) 35{ 36 REQUIRE_ZCB(ctx); 37 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8u_tl); 38} 39 40static bool trans_c_zext_h(DisasContext *ctx, arg_c_zext_h *a) 41{ 42 REQUIRE_ZCB(ctx); 43 REQUIRE_ZBB(ctx); 44 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16u_tl); 45} 46 47static bool trans_c_sext_b(DisasContext *ctx, arg_c_sext_b *a) 48{ 49 REQUIRE_ZCB(ctx); 50 REQUIRE_ZBB(ctx); 51 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8s_tl); 52} 53 54static bool trans_c_sext_h(DisasContext *ctx, arg_c_sext_h *a) 55{ 56 REQUIRE_ZCB(ctx); 57 REQUIRE_ZBB(ctx); 58 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16s_tl); 59} 60 61static bool trans_c_zext_w(DisasContext *ctx, arg_c_zext_w *a) 62{ 63 REQUIRE_64BIT(ctx); 64 REQUIRE_ZCB(ctx); 65 REQUIRE_ZBA(ctx); 66 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext32u_tl); 67} 68 69static bool trans_c_not(DisasContext *ctx, arg_c_not *a) 70{ 71 REQUIRE_ZCB(ctx); 72 return gen_unary(ctx, a, EXT_NONE, tcg_gen_not_tl); 73} 74 75static bool trans_c_mul(DisasContext *ctx, arg_c_mul *a) 76{ 77 REQUIRE_ZCB(ctx); 78 REQUIRE_M_OR_ZMMUL(ctx); 79 return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, NULL); 80} 81 82static bool trans_c_lbu(DisasContext *ctx, arg_c_lbu *a) 83{ 84 REQUIRE_ZCB(ctx); 85 return gen_load(ctx, a, MO_UB); 86} 87 88static bool trans_c_lhu(DisasContext *ctx, arg_c_lhu *a) 89{ 90 REQUIRE_ZCB(ctx); 91 return gen_load(ctx, a, MO_UW); 92} 93 94static bool trans_c_lh(DisasContext *ctx, arg_c_lh *a) 95{ 96 REQUIRE_ZCB(ctx); 97 return gen_load(ctx, a, MO_SW); 98} 99 100static bool trans_c_sb(DisasContext *ctx, arg_c_sb *a) 101{ 102 REQUIRE_ZCB(ctx); 103 return gen_store(ctx, a, MO_UB); 104} 105 106static bool trans_c_sh(DisasContext *ctx, arg_c_sh *a) 107{ 108 REQUIRE_ZCB(ctx); 109 return gen_store(ctx, a, MO_UW); 110} 111 112#define X_S0 8 113#define X_S1 9 114#define X_Sn 16 115 116static uint32_t decode_push_pop_list(DisasContext *ctx, target_ulong rlist) 117{ 118 uint32_t reg_bitmap = 0; 119 120 if (has_ext(ctx, RVE) && rlist > 6) { 121 return 0; 122 } 123 124 switch (rlist) { 125 case 15: 126 reg_bitmap |= 1 << (X_Sn + 11) ; 127 reg_bitmap |= 1 << (X_Sn + 10) ; 128 /* FALL THROUGH */ 129 case 14: 130 reg_bitmap |= 1 << (X_Sn + 9) ; 131 /* FALL THROUGH */ 132 case 13: 133 reg_bitmap |= 1 << (X_Sn + 8) ; 134 /* FALL THROUGH */ 135 case 12: 136 reg_bitmap |= 1 << (X_Sn + 7) ; 137 /* FALL THROUGH */ 138 case 11: 139 reg_bitmap |= 1 << (X_Sn + 6) ; 140 /* FALL THROUGH */ 141 case 10: 142 reg_bitmap |= 1 << (X_Sn + 5) ; 143 /* FALL THROUGH */ 144 case 9: 145 reg_bitmap |= 1 << (X_Sn + 4) ; 146 /* FALL THROUGH */ 147 case 8: 148 reg_bitmap |= 1 << (X_Sn + 3) ; 149 /* FALL THROUGH */ 150 case 7: 151 reg_bitmap |= 1 << (X_Sn + 2) ; 152 /* FALL THROUGH */ 153 case 6: 154 reg_bitmap |= 1 << X_S1 ; 155 /* FALL THROUGH */ 156 case 5: 157 reg_bitmap |= 1 << X_S0; 158 /* FALL THROUGH */ 159 case 4: 160 reg_bitmap |= 1 << xRA; 161 break; 162 default: 163 break; 164 } 165 166 return reg_bitmap; 167} 168 169static bool gen_pop(DisasContext *ctx, arg_cmpp *a, bool ret, bool ret_val) 170{ 171 REQUIRE_ZCMP(ctx); 172 173 uint32_t reg_bitmap = decode_push_pop_list(ctx, a->urlist); 174 if (reg_bitmap == 0) { 175 return false; 176 } 177 178 MemOp memop = get_ol(ctx) == MXL_RV32 ? MO_TEUL : MO_TEUQ; 179 int reg_size = memop_size(memop); 180 target_ulong stack_adj = ROUND_UP(ctpop32(reg_bitmap) * reg_size, 16) + 181 a->spimm; 182 TCGv sp = dest_gpr(ctx, xSP); 183 TCGv addr = tcg_temp_new(); 184 int i; 185 186 tcg_gen_addi_tl(addr, sp, stack_adj - reg_size); 187 188 for (i = X_Sn + 11; i >= 0; i--) { 189 if (reg_bitmap & (1 << i)) { 190 TCGv dest = dest_gpr(ctx, i); 191 tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop); 192 gen_set_gpr(ctx, i, dest); 193 tcg_gen_subi_tl(addr, addr, reg_size); 194 } 195 } 196 197 tcg_gen_addi_tl(sp, sp, stack_adj); 198 gen_set_gpr(ctx, xSP, sp); 199 200 if (ret_val) { 201 gen_set_gpr(ctx, xA0, ctx->zero); 202 } 203 204 if (ret) { 205 TCGv ret_addr = get_gpr(ctx, xRA, EXT_SIGN); 206#ifndef CONFIG_USER_ONLY 207 if (ctx->cfg_ptr->ext_smctr || ctx->cfg_ptr->ext_ssctr) { 208 TCGv type = tcg_constant_tl(CTRDATA_TYPE_RETURN); 209 TCGv src = tcg_temp_new(); 210 gen_pc_plus_diff(src, ctx, 0); 211 gen_helper_ctr_add_entry(tcg_env, src, ret_addr, type); 212 } 213#endif 214 tcg_gen_mov_tl(cpu_pc, ret_addr); 215 tcg_gen_lookup_and_goto_ptr(); 216 ctx->base.is_jmp = DISAS_NORETURN; 217 } 218 219 return true; 220} 221 222static bool trans_cm_push(DisasContext *ctx, arg_cm_push *a) 223{ 224 REQUIRE_ZCMP(ctx); 225 226 uint32_t reg_bitmap = decode_push_pop_list(ctx, a->urlist); 227 if (reg_bitmap == 0) { 228 return false; 229 } 230 231 MemOp memop = get_ol(ctx) == MXL_RV32 ? MO_TEUL : MO_TEUQ; 232 int reg_size = memop_size(memop); 233 target_ulong stack_adj = ROUND_UP(ctpop32(reg_bitmap) * reg_size, 16) + 234 a->spimm; 235 TCGv sp = dest_gpr(ctx, xSP); 236 TCGv addr = tcg_temp_new(); 237 int i; 238 239 tcg_gen_subi_tl(addr, sp, reg_size); 240 241 for (i = X_Sn + 11; i >= 0; i--) { 242 if (reg_bitmap & (1 << i)) { 243 TCGv val = get_gpr(ctx, i, EXT_NONE); 244 tcg_gen_qemu_st_tl(val, addr, ctx->mem_idx, memop); 245 tcg_gen_subi_tl(addr, addr, reg_size); 246 } 247 } 248 249 tcg_gen_subi_tl(sp, sp, stack_adj); 250 gen_set_gpr(ctx, xSP, sp); 251 252 return true; 253} 254 255static bool trans_cm_pop(DisasContext *ctx, arg_cm_pop *a) 256{ 257 return gen_pop(ctx, a, false, false); 258} 259 260static bool trans_cm_popret(DisasContext *ctx, arg_cm_popret *a) 261{ 262 return gen_pop(ctx, a, true, false); 263} 264 265static bool trans_cm_popretz(DisasContext *ctx, arg_cm_popret *a) 266{ 267 return gen_pop(ctx, a, true, true); 268} 269 270static bool trans_cm_mva01s(DisasContext *ctx, arg_cm_mva01s *a) 271{ 272 REQUIRE_ZCMP(ctx); 273 274 TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); 275 TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); 276 277 gen_set_gpr(ctx, xA0, src1); 278 gen_set_gpr(ctx, xA1, src2); 279 280 return true; 281} 282 283static bool trans_cm_mvsa01(DisasContext *ctx, arg_cm_mvsa01 *a) 284{ 285 REQUIRE_ZCMP(ctx); 286 287 if (a->rs1 == a->rs2) { 288 return false; 289 } 290 291 TCGv a0 = get_gpr(ctx, xA0, EXT_NONE); 292 TCGv a1 = get_gpr(ctx, xA1, EXT_NONE); 293 294 gen_set_gpr(ctx, a->rs1, a0); 295 gen_set_gpr(ctx, a->rs2, a1); 296 297 return true; 298} 299 300static bool trans_cm_jalt(DisasContext *ctx, arg_cm_jalt *a) 301{ 302 REQUIRE_ZCMT(ctx); 303 304 TCGv addr = tcg_temp_new(); 305 306 /* 307 * Update pc to current for the non-unwinding exception 308 * that might come from cpu_ld*_code() in the helper. 309 */ 310 gen_update_pc(ctx, 0); 311 gen_helper_cm_jalt(addr, tcg_env, tcg_constant_i32(a->index)); 312 313 /* c.jt vs c.jalt depends on the index. */ 314 if (a->index >= 32) { 315 TCGv succ_pc = dest_gpr(ctx, xRA); 316 gen_pc_plus_diff(succ_pc, ctx, ctx->cur_insn_len); 317 gen_set_gpr(ctx, xRA, succ_pc); 318 } 319 320#ifndef CONFIG_USER_ONLY 321 if (ctx->cfg_ptr->ext_smctr || ctx->cfg_ptr->ext_ssctr) { 322 if (a->index >= 32) { 323 TCGv type = tcg_constant_tl(CTRDATA_TYPE_DIRECT_CALL); 324 gen_helper_ctr_add_entry(tcg_env, cpu_pc, addr, type); 325 } else { 326 TCGv type = tcg_constant_tl(CTRDATA_TYPE_DIRECT_JUMP); 327 gen_helper_ctr_add_entry(tcg_env, cpu_pc, addr, type); 328 } 329 } 330#endif 331 332 333 tcg_gen_mov_tl(cpu_pc, addr); 334 335 tcg_gen_lookup_and_goto_ptr(); 336 ctx->base.is_jmp = DISAS_NORETURN; 337 return true; 338} 339