diff options
Diffstat (limited to 'target/riscv/insn_trans/trans_rvzce.c.inc')
| -rw-r--r-- | target/riscv/insn_trans/trans_rvzce.c.inc | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/target/riscv/insn_trans/trans_rvzce.c.inc b/target/riscv/insn_trans/trans_rvzce.c.inc new file mode 100644 index 0000000000..a727169a4b --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzce.c.inc @@ -0,0 +1,311 @@ +/* + * RISC-V translation routines for the Zc[b,mp,mt] Standard Extensions. + * + * Copyright (c) 2021-2022 PLCT Lab + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define REQUIRE_ZCB(ctx) do { \ + if (!ctx->cfg_ptr->ext_zcb) \ + return false; \ +} while (0) + +#define REQUIRE_ZCMP(ctx) do { \ + if (!ctx->cfg_ptr->ext_zcmp) \ + return false; \ +} while (0) + +#define REQUIRE_ZCMT(ctx) do { \ + if (!ctx->cfg_ptr->ext_zcmt) \ + return false; \ +} while (0) + +static bool trans_c_zext_b(DisasContext *ctx, arg_c_zext_b *a) +{ + REQUIRE_ZCB(ctx); + return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8u_tl); +} + +static bool trans_c_zext_h(DisasContext *ctx, arg_c_zext_h *a) +{ + REQUIRE_ZCB(ctx); + REQUIRE_ZBB(ctx); + return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16u_tl); +} + +static bool trans_c_sext_b(DisasContext *ctx, arg_c_sext_b *a) +{ + REQUIRE_ZCB(ctx); + REQUIRE_ZBB(ctx); + return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8s_tl); +} + +static bool trans_c_sext_h(DisasContext *ctx, arg_c_sext_h *a) +{ + REQUIRE_ZCB(ctx); + REQUIRE_ZBB(ctx); + return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16s_tl); +} + +static bool trans_c_zext_w(DisasContext *ctx, arg_c_zext_w *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZCB(ctx); + REQUIRE_ZBA(ctx); + return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext32u_tl); +} + +static bool trans_c_not(DisasContext *ctx, arg_c_not *a) +{ + REQUIRE_ZCB(ctx); + return gen_unary(ctx, a, EXT_NONE, tcg_gen_not_tl); +} + +static bool trans_c_mul(DisasContext *ctx, arg_c_mul *a) +{ + REQUIRE_ZCB(ctx); + REQUIRE_M_OR_ZMMUL(ctx); + return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, NULL); +} + +static bool trans_c_lbu(DisasContext *ctx, arg_c_lbu *a) +{ + REQUIRE_ZCB(ctx); + return gen_load(ctx, a, MO_UB); +} + +static bool trans_c_lhu(DisasContext *ctx, arg_c_lhu *a) +{ + REQUIRE_ZCB(ctx); + return gen_load(ctx, a, MO_UW); +} + +static bool trans_c_lh(DisasContext *ctx, arg_c_lh *a) +{ + REQUIRE_ZCB(ctx); + return gen_load(ctx, a, MO_SW); +} + +static bool trans_c_sb(DisasContext *ctx, arg_c_sb *a) +{ + REQUIRE_ZCB(ctx); + return gen_store(ctx, a, MO_UB); +} + +static bool trans_c_sh(DisasContext *ctx, arg_c_sh *a) +{ + REQUIRE_ZCB(ctx); + return gen_store(ctx, a, MO_UW); +} + +#define X_S0 8 +#define X_S1 9 +#define X_Sn 16 + +static uint32_t decode_push_pop_list(DisasContext *ctx, target_ulong rlist) +{ + uint32_t reg_bitmap = 0; + + if (has_ext(ctx, RVE) && rlist > 6) { + return 0; + } + + switch (rlist) { + case 15: + reg_bitmap |= 1 << (X_Sn + 11) ; + reg_bitmap |= 1 << (X_Sn + 10) ; + /* FALL THROUGH */ + case 14: + reg_bitmap |= 1 << (X_Sn + 9) ; + /* FALL THROUGH */ + case 13: + reg_bitmap |= 1 << (X_Sn + 8) ; + /* FALL THROUGH */ + case 12: + reg_bitmap |= 1 << (X_Sn + 7) ; + /* FALL THROUGH */ + case 11: + reg_bitmap |= 1 << (X_Sn + 6) ; + /* FALL THROUGH */ + case 10: + reg_bitmap |= 1 << (X_Sn + 5) ; + /* FALL THROUGH */ + case 9: + reg_bitmap |= 1 << (X_Sn + 4) ; + /* FALL THROUGH */ + case 8: + reg_bitmap |= 1 << (X_Sn + 3) ; + /* FALL THROUGH */ + case 7: + reg_bitmap |= 1 << (X_Sn + 2) ; + /* FALL THROUGH */ + case 6: + reg_bitmap |= 1 << X_S1 ; + /* FALL THROUGH */ + case 5: + reg_bitmap |= 1 << X_S0; + /* FALL THROUGH */ + case 4: + reg_bitmap |= 1 << xRA; + break; + default: + break; + } + + return reg_bitmap; +} + +static bool gen_pop(DisasContext *ctx, arg_cmpp *a, bool ret, bool ret_val) +{ + REQUIRE_ZCMP(ctx); + + uint32_t reg_bitmap = decode_push_pop_list(ctx, a->urlist); + if (reg_bitmap == 0) { + return false; + } + + MemOp memop = get_ol(ctx) == MXL_RV32 ? MO_TEUL : MO_TEUQ; + int reg_size = memop_size(memop); + target_ulong stack_adj = ROUND_UP(ctpop32(reg_bitmap) * reg_size, 16) + + a->spimm; + TCGv sp = dest_gpr(ctx, xSP); + TCGv addr = tcg_temp_new(); + int i; + + tcg_gen_addi_tl(addr, sp, stack_adj - reg_size); + + for (i = X_Sn + 11; i >= 0; i--) { + if (reg_bitmap & (1 << i)) { + TCGv dest = dest_gpr(ctx, i); + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop); + gen_set_gpr(ctx, i, dest); + tcg_gen_subi_tl(addr, addr, reg_size); + } + } + + tcg_gen_addi_tl(sp, sp, stack_adj); + gen_set_gpr(ctx, xSP, sp); + + if (ret_val) { + gen_set_gpr(ctx, xA0, ctx->zero); + } + + if (ret) { + TCGv ret_addr = get_gpr(ctx, xRA, EXT_NONE); + gen_set_pc(ctx, ret_addr); + tcg_gen_lookup_and_goto_ptr(); + ctx->base.is_jmp = DISAS_NORETURN; + } + + return true; +} + +static bool trans_cm_push(DisasContext *ctx, arg_cm_push *a) +{ + REQUIRE_ZCMP(ctx); + + uint32_t reg_bitmap = decode_push_pop_list(ctx, a->urlist); + if (reg_bitmap == 0) { + return false; + } + + MemOp memop = get_ol(ctx) == MXL_RV32 ? MO_TEUL : MO_TEUQ; + int reg_size = memop_size(memop); + target_ulong stack_adj = ROUND_UP(ctpop32(reg_bitmap) * reg_size, 16) + + a->spimm; + TCGv sp = dest_gpr(ctx, xSP); + TCGv addr = tcg_temp_new(); + int i; + + tcg_gen_subi_tl(addr, sp, reg_size); + + for (i = X_Sn + 11; i >= 0; i--) { + if (reg_bitmap & (1 << i)) { + TCGv val = get_gpr(ctx, i, EXT_NONE); + tcg_gen_qemu_st_tl(val, addr, ctx->mem_idx, memop); + tcg_gen_subi_tl(addr, addr, reg_size); + } + } + + tcg_gen_subi_tl(sp, sp, stack_adj); + gen_set_gpr(ctx, xSP, sp); + + return true; +} + +static bool trans_cm_pop(DisasContext *ctx, arg_cm_pop *a) +{ + return gen_pop(ctx, a, false, false); +} + +static bool trans_cm_popret(DisasContext *ctx, arg_cm_popret *a) +{ + return gen_pop(ctx, a, true, false); +} + +static bool trans_cm_popretz(DisasContext *ctx, arg_cm_popret *a) +{ + return gen_pop(ctx, a, true, true); +} + +static bool trans_cm_mva01s(DisasContext *ctx, arg_cm_mva01s *a) +{ + REQUIRE_ZCMP(ctx); + + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); + + gen_set_gpr(ctx, xA0, src1); + gen_set_gpr(ctx, xA1, src2); + + return true; +} + +static bool trans_cm_mvsa01(DisasContext *ctx, arg_cm_mvsa01 *a) +{ + REQUIRE_ZCMP(ctx); + + if (a->rs1 == a->rs2) { + return false; + } + + TCGv a0 = get_gpr(ctx, xA0, EXT_NONE); + TCGv a1 = get_gpr(ctx, xA1, EXT_NONE); + + gen_set_gpr(ctx, a->rs1, a0); + gen_set_gpr(ctx, a->rs2, a1); + + return true; +} + +static bool trans_cm_jalt(DisasContext *ctx, arg_cm_jalt *a) +{ + REQUIRE_ZCMT(ctx); + + /* + * Update pc to current for the non-unwinding exception + * that might come from cpu_ld*_code() in the helper. + */ + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + gen_helper_cm_jalt(cpu_pc, cpu_env, tcg_constant_i32(a->index)); + + /* c.jt vs c.jalt depends on the index. */ + if (a->index >= 32) { + gen_set_gpri(ctx, xRA, ctx->pc_succ_insn); + } + + tcg_gen_lookup_and_goto_ptr(); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} |