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_NONE); 206 gen_set_pc(ctx, ret_addr); 207 tcg_gen_lookup_and_goto_ptr(); 208 ctx->base.is_jmp = DISAS_NORETURN; 209 } 210 211 return true; 212} 213 214static bool trans_cm_push(DisasContext *ctx, arg_cm_push *a) 215{ 216 REQUIRE_ZCMP(ctx); 217 218 uint32_t reg_bitmap = decode_push_pop_list(ctx, a->urlist); 219 if (reg_bitmap == 0) { 220 return false; 221 } 222 223 MemOp memop = get_ol(ctx) == MXL_RV32 ? MO_TEUL : MO_TEUQ; 224 int reg_size = memop_size(memop); 225 target_ulong stack_adj = ROUND_UP(ctpop32(reg_bitmap) * reg_size, 16) + 226 a->spimm; 227 TCGv sp = dest_gpr(ctx, xSP); 228 TCGv addr = tcg_temp_new(); 229 int i; 230 231 tcg_gen_subi_tl(addr, sp, reg_size); 232 233 for (i = X_Sn + 11; i >= 0; i--) { 234 if (reg_bitmap & (1 << i)) { 235 TCGv val = get_gpr(ctx, i, EXT_NONE); 236 tcg_gen_qemu_st_tl(val, addr, ctx->mem_idx, memop); 237 tcg_gen_subi_tl(addr, addr, reg_size); 238 } 239 } 240 241 tcg_gen_subi_tl(sp, sp, stack_adj); 242 gen_set_gpr(ctx, xSP, sp); 243 244 return true; 245} 246 247static bool trans_cm_pop(DisasContext *ctx, arg_cm_pop *a) 248{ 249 return gen_pop(ctx, a, false, false); 250} 251 252static bool trans_cm_popret(DisasContext *ctx, arg_cm_popret *a) 253{ 254 return gen_pop(ctx, a, true, false); 255} 256 257static bool trans_cm_popretz(DisasContext *ctx, arg_cm_popret *a) 258{ 259 return gen_pop(ctx, a, true, true); 260} 261 262static bool trans_cm_mva01s(DisasContext *ctx, arg_cm_mva01s *a) 263{ 264 REQUIRE_ZCMP(ctx); 265 266 TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); 267 TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); 268 269 gen_set_gpr(ctx, xA0, src1); 270 gen_set_gpr(ctx, xA1, src2); 271 272 return true; 273} 274 275static bool trans_cm_mvsa01(DisasContext *ctx, arg_cm_mvsa01 *a) 276{ 277 REQUIRE_ZCMP(ctx); 278 279 if (a->rs1 == a->rs2) { 280 return false; 281 } 282 283 TCGv a0 = get_gpr(ctx, xA0, EXT_NONE); 284 TCGv a1 = get_gpr(ctx, xA1, EXT_NONE); 285 286 gen_set_gpr(ctx, a->rs1, a0); 287 gen_set_gpr(ctx, a->rs2, a1); 288 289 return true; 290} 291 292static bool trans_cm_jalt(DisasContext *ctx, arg_cm_jalt *a) 293{ 294 REQUIRE_ZCMT(ctx); 295 296 /* 297 * Update pc to current for the non-unwinding exception 298 * that might come from cpu_ld*_code() in the helper. 299 */ 300 tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); 301 gen_helper_cm_jalt(cpu_pc, cpu_env, tcg_constant_i32(a->index)); 302 303 /* c.jt vs c.jalt depends on the index. */ 304 if (a->index >= 32) { 305 gen_set_gpri(ctx, xRA, ctx->pc_succ_insn); 306 } 307 308 tcg_gen_lookup_and_goto_ptr(); 309 ctx->base.is_jmp = DISAS_NORETURN; 310 return true; 311} 312