aboutsummaryrefslogtreecommitdiff
path: root/target/riscv/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/riscv/translate.c')
-rw-r--r--target/riscv/translate.c689
1 files changed, 147 insertions, 542 deletions
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 6983be5..e356fc6 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -39,15 +39,25 @@ static TCGv load_val;
#include "exec/gen-icount.h"
+/*
+ * If an operation is being performed on less than TARGET_LONG_BITS,
+ * it may require the inputs to be sign- or zero-extended; which will
+ * depend on the exact operation being performed.
+ */
+typedef enum {
+ EXT_NONE,
+ EXT_SIGN,
+ EXT_ZERO,
+} DisasExtend;
+
typedef struct DisasContext {
DisasContextBase base;
/* pc_succ_insn points to the instruction following base.pc_next */
target_ulong pc_succ_insn;
target_ulong priv_ver;
- bool virt_enabled;
+ target_ulong misa;
uint32_t opcode;
uint32_t mstatus_fs;
- target_ulong misa;
uint32_t mem_idx;
/* Remember the rounding mode encoded in the previous fp instruction,
which we have already installed into env->fp_status. Or -1 for
@@ -55,6 +65,8 @@ typedef struct DisasContext {
to any system register, which includes CSR_FRM, so we do not have
to reset this known value. */
int frm;
+ bool w;
+ bool virt_enabled;
bool ext_ifencei;
bool hlsx;
/* vector extension */
@@ -64,7 +76,11 @@ typedef struct DisasContext {
uint16_t vlen;
uint16_t mlen;
bool vl_eq_vlmax;
+ uint8_t ntemp;
CPUState *cs;
+ TCGv zero;
+ /* Space for 3 operands plus 1 extra for address computation. */
+ TCGv temp[4];
} DisasContext;
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -83,6 +99,13 @@ static inline bool is_32bit(DisasContext *ctx)
}
#endif
+/* The word size for this operation. */
+static inline int oper_len(DisasContext *ctx)
+{
+ return ctx->w ? 32 : TARGET_LONG_BITS;
+}
+
+
/*
* RISC-V requires NaN-boxing of narrower width floating point values.
* This applies when a 32-bit value is assigned to a 64-bit FP register.
@@ -104,20 +127,16 @@ static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in)
*/
static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in)
{
- TCGv_i64 t_max = tcg_const_i64(0xffffffff00000000ull);
- TCGv_i64 t_nan = tcg_const_i64(0xffffffff7fc00000ull);
+ TCGv_i64 t_max = tcg_constant_i64(0xffffffff00000000ull);
+ TCGv_i64 t_nan = tcg_constant_i64(0xffffffff7fc00000ull);
tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan);
- tcg_temp_free_i64(t_max);
- tcg_temp_free_i64(t_nan);
}
static void generate_exception(DisasContext *ctx, int excp)
{
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
- TCGv_i32 helper_tmp = tcg_const_i32(excp);
- gen_helper_raise_exception(cpu_env, helper_tmp);
- tcg_temp_free_i32(helper_tmp);
+ gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
ctx->base.is_jmp = DISAS_NORETURN;
}
@@ -125,17 +144,13 @@ static void generate_exception_mtval(DisasContext *ctx, int excp)
{
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr));
- TCGv_i32 helper_tmp = tcg_const_i32(excp);
- gen_helper_raise_exception(cpu_env, helper_tmp);
- tcg_temp_free_i32(helper_tmp);
+ gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
ctx->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception_debug(void)
{
- TCGv_i32 helper_tmp = tcg_const_i32(EXCP_DEBUG);
- gen_helper_raise_exception(cpu_env, helper_tmp);
- tcg_temp_free_i32(helper_tmp);
+ gen_helper_raise_exception(cpu_env, tcg_constant_i32(EXCP_DEBUG));
}
/* Wrapper around tcg_gen_exit_tb that handles single stepping */
@@ -180,151 +195,60 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
}
}
-/* Wrapper for getting reg values - need to check of reg is zero since
- * cpu_gpr[0] is not actually allocated
- */
-static inline void gen_get_gpr(TCGv t, int reg_num)
-{
- if (reg_num == 0) {
- tcg_gen_movi_tl(t, 0);
- } else {
- tcg_gen_mov_tl(t, cpu_gpr[reg_num]);
- }
-}
-
-/* Wrapper for setting reg values - need to check of reg is zero since
- * cpu_gpr[0] is not actually allocated. this is more for safety purposes,
- * since we usually avoid calling the OP_TYPE_gen function if we see a write to
- * $zero
+/*
+ * Wrappers for getting reg values.
+ *
+ * The $zero register does not have cpu_gpr[0] allocated -- we supply the
+ * constant zero as a source, and an uninitialized sink as destination.
+ *
+ * Further, we may provide an extension for word operations.
*/
-static inline void gen_set_gpr(int reg_num_dst, TCGv t)
+static TCGv temp_new(DisasContext *ctx)
{
- if (reg_num_dst != 0) {
- tcg_gen_mov_tl(cpu_gpr[reg_num_dst], t);
- }
+ assert(ctx->ntemp < ARRAY_SIZE(ctx->temp));
+ return ctx->temp[ctx->ntemp++] = tcg_temp_new();
}
-static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
+static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)
{
- TCGv rl = tcg_temp_new();
- TCGv rh = tcg_temp_new();
-
- tcg_gen_mulu2_tl(rl, rh, arg1, arg2);
- /* fix up for one negative */
- tcg_gen_sari_tl(rl, arg1, TARGET_LONG_BITS - 1);
- tcg_gen_and_tl(rl, rl, arg2);
- tcg_gen_sub_tl(ret, rh, rl);
+ TCGv t;
- tcg_temp_free(rl);
- tcg_temp_free(rh);
-}
-
-static void gen_div(TCGv ret, TCGv source1, TCGv source2)
-{
- TCGv cond1, cond2, zeroreg, resultopt1;
- /*
- * Handle by altering args to tcg_gen_div to produce req'd results:
- * For overflow: want source1 in source1 and 1 in source2
- * For div by zero: want -1 in source1 and 1 in source2 -> -1 result
- */
- cond1 = tcg_temp_new();
- cond2 = tcg_temp_new();
- zeroreg = tcg_const_tl(0);
- resultopt1 = tcg_temp_new();
-
- tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
- ((target_ulong)1) << (TARGET_LONG_BITS - 1));
- tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
- /* if div by zero, set source1 to -1, otherwise don't change */
- tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
- resultopt1);
- /* if overflow or div by zero, set source2 to 1, else don't change */
- tcg_gen_or_tl(cond1, cond1, cond2);
- tcg_gen_movi_tl(resultopt1, (target_ulong)1);
- tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
- resultopt1);
- tcg_gen_div_tl(ret, source1, source2);
-
- tcg_temp_free(cond1);
- tcg_temp_free(cond2);
- tcg_temp_free(zeroreg);
- tcg_temp_free(resultopt1);
-}
+ if (reg_num == 0) {
+ return ctx->zero;
+ }
-static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
-{
- TCGv cond1, zeroreg, resultopt1;
- cond1 = tcg_temp_new();
-
- zeroreg = tcg_const_tl(0);
- resultopt1 = tcg_temp_new();
-
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
- tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
- tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
- resultopt1);
- tcg_gen_movi_tl(resultopt1, (target_ulong)1);
- tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
- resultopt1);
- tcg_gen_divu_tl(ret, source1, source2);
-
- tcg_temp_free(cond1);
- tcg_temp_free(zeroreg);
- tcg_temp_free(resultopt1);
+ switch (ctx->w ? ext : EXT_NONE) {
+ case EXT_NONE:
+ return cpu_gpr[reg_num];
+ case EXT_SIGN:
+ t = temp_new(ctx);
+ tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);
+ return t;
+ case EXT_ZERO:
+ t = temp_new(ctx);
+ tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);
+ return t;
+ }
+ g_assert_not_reached();
}
-static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
+static TCGv dest_gpr(DisasContext *ctx, int reg_num)
{
- TCGv cond1, cond2, zeroreg, resultopt1;
-
- cond1 = tcg_temp_new();
- cond2 = tcg_temp_new();
- zeroreg = tcg_const_tl(0);
- resultopt1 = tcg_temp_new();
-
- tcg_gen_movi_tl(resultopt1, 1L);
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1);
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
- (target_ulong)1 << (TARGET_LONG_BITS - 1));
- tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
- /* if overflow or div by zero, set source2 to 1, else don't change */
- tcg_gen_or_tl(cond2, cond1, cond2);
- tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
- resultopt1);
- tcg_gen_rem_tl(resultopt1, source1, source2);
- /* if div by zero, just return the original dividend */
- tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
- source1);
-
- tcg_temp_free(cond1);
- tcg_temp_free(cond2);
- tcg_temp_free(zeroreg);
- tcg_temp_free(resultopt1);
+ if (reg_num == 0 || ctx->w) {
+ return temp_new(ctx);
+ }
+ return cpu_gpr[reg_num];
}
-static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
+static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)
{
- TCGv cond1, zeroreg, resultopt1;
- cond1 = tcg_temp_new();
- zeroreg = tcg_const_tl(0);
- resultopt1 = tcg_temp_new();
-
- tcg_gen_movi_tl(resultopt1, (target_ulong)1);
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
- tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
- resultopt1);
- tcg_gen_remu_tl(resultopt1, source1, source2);
- /* if div by zero, just return the original dividend */
- tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
- source1);
-
- tcg_temp_free(cond1);
- tcg_temp_free(zeroreg);
- tcg_temp_free(resultopt1);
+ if (reg_num != 0) {
+ if (ctx->w) {
+ tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);
+ } else {
+ tcg_gen_mov_tl(cpu_gpr[reg_num], t);
+ }
+ }
}
static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
@@ -384,15 +308,11 @@ static inline void mark_fs_dirty(DisasContext *ctx) { }
static void gen_set_rm(DisasContext *ctx, int rm)
{
- TCGv_i32 t0;
-
if (ctx->frm == rm) {
return;
}
ctx->frm = rm;
- t0 = tcg_const_i32(rm);
- gen_helper_set_rounding_mode(cpu_env, t0);
- tcg_temp_free_i32(t0);
+ gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm));
}
static int ex_plus_1(DisasContext *ctx, int nf)
@@ -437,355 +357,108 @@ static int ex_rvc_shifti(DisasContext *ctx, int imm)
/* Include the auto-generated decoder for 32 bit insn */
#include "decode-insn32.c.inc"
-static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a,
+static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a, DisasExtend ext,
void (*func)(TCGv, TCGv, target_long))
{
- TCGv source1;
- source1 = tcg_temp_new();
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
- gen_get_gpr(source1, a->rs1);
+ func(dest, src1, a->imm);
- (*func)(source1, source1, a->imm);
-
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
+ gen_set_gpr(ctx, a->rd, dest);
return true;
}
-static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a,
+static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, DisasExtend ext,
void (*func)(TCGv, TCGv, TCGv))
{
- TCGv source1, source2;
- source1 = tcg_temp_new();
- source2 = tcg_temp_new();
-
- gen_get_gpr(source1, a->rs1);
- tcg_gen_movi_tl(source2, a->imm);
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
+ TCGv src2 = tcg_constant_tl(a->imm);
- (*func)(source1, source1, source2);
+ func(dest, src1, src2);
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
+ gen_set_gpr(ctx, a->rd, dest);
return true;
}
-static void gen_addw(TCGv ret, TCGv arg1, TCGv arg2)
+static bool gen_arith(DisasContext *ctx, arg_r *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv))
{
- tcg_gen_add_tl(ret, arg1, arg2);
- tcg_gen_ext32s_tl(ret, ret);
-}
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
+ TCGv src2 = get_gpr(ctx, a->rs2, ext);
-static void gen_subw(TCGv ret, TCGv arg1, TCGv arg2)
-{
- tcg_gen_sub_tl(ret, arg1, arg2);
- tcg_gen_ext32s_tl(ret, ret);
-}
-
-static void gen_mulw(TCGv ret, TCGv arg1, TCGv arg2)
-{
- tcg_gen_mul_tl(ret, arg1, arg2);
- tcg_gen_ext32s_tl(ret, ret);
-}
+ func(dest, src1, src2);
-static bool gen_arith_div_w(DisasContext *ctx, arg_r *a,
- void(*func)(TCGv, TCGv, TCGv))
-{
- TCGv source1, source2;
- source1 = tcg_temp_new();
- source2 = tcg_temp_new();
-
- gen_get_gpr(source1, a->rs1);
- gen_get_gpr(source2, a->rs2);
- tcg_gen_ext32s_tl(source1, source1);
- tcg_gen_ext32s_tl(source2, source2);
-
- (*func)(source1, source1, source2);
-
- tcg_gen_ext32s_tl(source1, source1);
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
- return true;
-}
-
-static bool gen_arith_div_uw(DisasContext *ctx, arg_r *a,
- void(*func)(TCGv, TCGv, TCGv))
-{
- TCGv source1, source2;
- source1 = tcg_temp_new();
- source2 = tcg_temp_new();
-
- gen_get_gpr(source1, a->rs1);
- gen_get_gpr(source2, a->rs2);
- tcg_gen_ext32u_tl(source1, source1);
- tcg_gen_ext32u_tl(source2, source2);
-
- (*func)(source1, source1, source2);
-
- tcg_gen_ext32s_tl(source1, source1);
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
+ gen_set_gpr(ctx, a->rd, dest);
return true;
}
-static void gen_pack(TCGv ret, TCGv arg1, TCGv arg2)
-{
- tcg_gen_deposit_tl(ret, arg1, arg2,
- TARGET_LONG_BITS / 2,
- TARGET_LONG_BITS / 2);
-}
-
-static void gen_packu(TCGv ret, TCGv arg1, TCGv arg2)
-{
- TCGv t = tcg_temp_new();
- tcg_gen_shri_tl(t, arg1, TARGET_LONG_BITS / 2);
- tcg_gen_deposit_tl(ret, arg2, t, 0, TARGET_LONG_BITS / 2);
- tcg_temp_free(t);
-}
-
-static void gen_packh(TCGv ret, TCGv arg1, TCGv arg2)
-{
- TCGv t = tcg_temp_new();
- tcg_gen_ext8u_tl(t, arg2);
- tcg_gen_deposit_tl(ret, arg1, t, 8, TARGET_LONG_BITS - 8);
- tcg_temp_free(t);
-}
-
-static void gen_sbop_mask(TCGv ret, TCGv shamt)
-{
- tcg_gen_movi_tl(ret, 1);
- tcg_gen_shl_tl(ret, ret, shamt);
-}
-
-static void gen_bset(TCGv ret, TCGv arg1, TCGv shamt)
-{
- TCGv t = tcg_temp_new();
-
- gen_sbop_mask(t, shamt);
- tcg_gen_or_tl(ret, arg1, t);
-
- tcg_temp_free(t);
-}
-
-static void gen_bclr(TCGv ret, TCGv arg1, TCGv shamt)
-{
- TCGv t = tcg_temp_new();
-
- gen_sbop_mask(t, shamt);
- tcg_gen_andc_tl(ret, arg1, t);
-
- tcg_temp_free(t);
-}
-
-static void gen_binv(TCGv ret, TCGv arg1, TCGv shamt)
-{
- TCGv t = tcg_temp_new();
-
- gen_sbop_mask(t, shamt);
- tcg_gen_xor_tl(ret, arg1, t);
-
- tcg_temp_free(t);
-}
-
-static void gen_bext(TCGv ret, TCGv arg1, TCGv shamt)
-{
- tcg_gen_shr_tl(ret, arg1, shamt);
- tcg_gen_andi_tl(ret, ret, 1);
-}
-
-static void gen_slo(TCGv ret, TCGv arg1, TCGv arg2)
-{
- tcg_gen_not_tl(ret, arg1);
- tcg_gen_shl_tl(ret, ret, arg2);
- tcg_gen_not_tl(ret, ret);
-}
-
-static void gen_sro(TCGv ret, TCGv arg1, TCGv arg2)
-{
- tcg_gen_not_tl(ret, arg1);
- tcg_gen_shr_tl(ret, ret, arg2);
- tcg_gen_not_tl(ret, ret);
-}
-
-static bool gen_grevi(DisasContext *ctx, arg_grevi *a)
+static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, target_long))
{
- TCGv source1 = tcg_temp_new();
- TCGv source2;
+ TCGv dest, src1;
+ int max_len = oper_len(ctx);
- gen_get_gpr(source1, a->rs1);
-
- if (a->shamt == (TARGET_LONG_BITS - 8)) {
- /* rev8, byte swaps */
- tcg_gen_bswap_tl(source1, source1);
- } else {
- source2 = tcg_temp_new();
- tcg_gen_movi_tl(source2, a->shamt);
- gen_helper_grev(source1, source1, source2);
- tcg_temp_free(source2);
+ if (a->shamt >= max_len) {
+ return false;
}
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- return true;
-}
-
-#define GEN_SHADD(SHAMT) \
-static void gen_sh##SHAMT##add(TCGv ret, TCGv arg1, TCGv arg2) \
-{ \
- TCGv t = tcg_temp_new(); \
- \
- tcg_gen_shli_tl(t, arg1, SHAMT); \
- tcg_gen_add_tl(ret, t, arg2); \
- \
- tcg_temp_free(t); \
-}
-
-GEN_SHADD(1)
-GEN_SHADD(2)
-GEN_SHADD(3)
-
-static void gen_ctzw(TCGv ret, TCGv arg1)
-{
- tcg_gen_ori_tl(ret, arg1, (target_ulong)MAKE_64BIT_MASK(32, 32));
- tcg_gen_ctzi_tl(ret, ret, 64);
-}
-
-static void gen_clzw(TCGv ret, TCGv arg1)
-{
- tcg_gen_ext32u_tl(ret, arg1);
- tcg_gen_clzi_tl(ret, ret, 64);
- tcg_gen_subi_tl(ret, ret, 32);
-}
-
-static void gen_cpopw(TCGv ret, TCGv arg1)
-{
- tcg_gen_ext32u_tl(arg1, arg1);
- tcg_gen_ctpop_tl(ret, arg1);
-}
-
-static void gen_packw(TCGv ret, TCGv arg1, TCGv arg2)
-{
- TCGv t = tcg_temp_new();
- tcg_gen_ext16s_tl(t, arg2);
- tcg_gen_deposit_tl(ret, arg1, t, 16, 48);
- tcg_temp_free(t);
-}
-
-static void gen_packuw(TCGv ret, TCGv arg1, TCGv arg2)
-{
- TCGv t = tcg_temp_new();
- tcg_gen_shri_tl(t, arg1, 16);
- tcg_gen_deposit_tl(ret, arg2, t, 0, 16);
- tcg_gen_ext32s_tl(ret, ret);
- tcg_temp_free(t);
-}
-
-static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2)
-{
- TCGv_i32 t1 = tcg_temp_new_i32();
- TCGv_i32 t2 = tcg_temp_new_i32();
-
- /* truncate to 32-bits */
- tcg_gen_trunc_tl_i32(t1, arg1);
- tcg_gen_trunc_tl_i32(t2, arg2);
-
- tcg_gen_rotr_i32(t1, t1, t2);
-
- /* sign-extend 64-bits */
- tcg_gen_ext_i32_tl(ret, t1);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
-}
-
-static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2)
-{
- TCGv_i32 t1 = tcg_temp_new_i32();
- TCGv_i32 t2 = tcg_temp_new_i32();
+ dest = dest_gpr(ctx, a->rd);
+ src1 = get_gpr(ctx, a->rs1, ext);
- /* truncate to 32-bits */
- tcg_gen_trunc_tl_i32(t1, arg1);
- tcg_gen_trunc_tl_i32(t2, arg2);
+ func(dest, src1, a->shamt);
- tcg_gen_rotl_i32(t1, t1, t2);
-
- /* sign-extend 64-bits */
- tcg_gen_ext_i32_tl(ret, t1);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
}
-static void gen_grevw(TCGv ret, TCGv arg1, TCGv arg2)
+static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv))
{
- tcg_gen_ext32u_tl(arg1, arg1);
- gen_helper_grev(ret, arg1, arg2);
-}
+ TCGv dest, src1, src2;
+ int max_len = oper_len(ctx);
-static void gen_gorcw(TCGv ret, TCGv arg1, TCGv arg2)
-{
- tcg_gen_ext32u_tl(arg1, arg1);
- gen_helper_gorcw(ret, arg1, arg2);
-}
+ if (a->shamt >= max_len) {
+ return false;
+ }
-#define GEN_SHADD_UW(SHAMT) \
-static void gen_sh##SHAMT##add_uw(TCGv ret, TCGv arg1, TCGv arg2) \
-{ \
- TCGv t = tcg_temp_new(); \
- \
- tcg_gen_ext32u_tl(t, arg1); \
- \
- tcg_gen_shli_tl(t, t, SHAMT); \
- tcg_gen_add_tl(ret, t, arg2); \
- \
- tcg_temp_free(t); \
-}
+ dest = dest_gpr(ctx, a->rd);
+ src1 = get_gpr(ctx, a->rs1, ext);
+ src2 = tcg_constant_tl(a->shamt);
-GEN_SHADD_UW(1)
-GEN_SHADD_UW(2)
-GEN_SHADD_UW(3)
+ func(dest, src1, src2);
-static void gen_add_uw(TCGv ret, TCGv arg1, TCGv arg2)
-{
- tcg_gen_ext32u_tl(arg1, arg1);
- tcg_gen_add_tl(ret, arg1, arg2);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
}
-static bool gen_arith(DisasContext *ctx, arg_r *a,
- void(*func)(TCGv, TCGv, TCGv))
+static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv))
{
- TCGv source1, source2;
- source1 = tcg_temp_new();
- source2 = tcg_temp_new();
-
- gen_get_gpr(source1, a->rs1);
- gen_get_gpr(source2, a->rs2);
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+ TCGv ext2 = tcg_temp_new();
- (*func)(source1, source1, source2);
+ tcg_gen_andi_tl(ext2, src2, oper_len(ctx) - 1);
+ func(dest, src1, ext2);
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
+ gen_set_gpr(ctx, a->rd, dest);
+ tcg_temp_free(ext2);
return true;
}
-static bool gen_shift(DisasContext *ctx, arg_r *a,
- void(*func)(TCGv, TCGv, TCGv))
+static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv))
{
- TCGv source1 = tcg_temp_new();
- TCGv source2 = tcg_temp_new();
-
- gen_get_gpr(source1, a->rs1);
- gen_get_gpr(source2, a->rs2);
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
- tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
- (*func)(source1, source1, source2);
+ func(dest, src1);
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
+ gen_set_gpr(ctx, a->rd, dest);
return true;
}
@@ -798,88 +471,6 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
return cpu_ldl_code(env, pc);
}
-static bool gen_shifti(DisasContext *ctx, arg_shift *a,
- void(*func)(TCGv, TCGv, TCGv))
-{
- if (a->shamt >= TARGET_LONG_BITS) {
- return false;
- }
-
- TCGv source1 = tcg_temp_new();
- TCGv source2 = tcg_temp_new();
-
- gen_get_gpr(source1, a->rs1);
-
- tcg_gen_movi_tl(source2, a->shamt);
- (*func)(source1, source1, source2);
-
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
- return true;
-}
-
-static bool gen_shiftw(DisasContext *ctx, arg_r *a,
- void(*func)(TCGv, TCGv, TCGv))
-{
- TCGv source1 = tcg_temp_new();
- TCGv source2 = tcg_temp_new();
-
- gen_get_gpr(source1, a->rs1);
- gen_get_gpr(source2, a->rs2);
-
- tcg_gen_andi_tl(source2, source2, 31);
- (*func)(source1, source1, source2);
- tcg_gen_ext32s_tl(source1, source1);
-
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
- return true;
-}
-
-static bool gen_shiftiw(DisasContext *ctx, arg_shift *a,
- void(*func)(TCGv, TCGv, TCGv))
-{
- TCGv source1 = tcg_temp_new();
- TCGv source2 = tcg_temp_new();
-
- gen_get_gpr(source1, a->rs1);
- tcg_gen_movi_tl(source2, a->shamt);
-
- (*func)(source1, source1, source2);
- tcg_gen_ext32s_tl(source1, source1);
-
- gen_set_gpr(a->rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
- return true;
-}
-
-static void gen_ctz(TCGv ret, TCGv arg1)
-{
- tcg_gen_ctzi_tl(ret, arg1, TARGET_LONG_BITS);
-}
-
-static void gen_clz(TCGv ret, TCGv arg1)
-{
- tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS);
-}
-
-static bool gen_unary(DisasContext *ctx, arg_r2 *a,
- void(*func)(TCGv, TCGv))
-{
- TCGv source = tcg_temp_new();
-
- gen_get_gpr(source, a->rs1);
-
- (*func)(source, source);
-
- gen_set_gpr(a->rd, source);
- tcg_temp_free(source);
- return true;
-}
-
/* Include insn module translation function */
#include "insn_trans/trans_rvi.c.inc"
#include "insn_trans/trans_rvm.c.inc"
@@ -948,6 +539,11 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->mlen = 1 << (ctx->sew + 3 - ctx->lmul);
ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
ctx->cs = cs;
+ ctx->w = false;
+ ctx->ntemp = 0;
+ memset(ctx->temp, 0, sizeof(ctx->temp));
+
+ ctx->zero = tcg_constant_tl(0);
}
static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
@@ -969,6 +565,13 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
decode_opc(env, ctx, opcode16);
ctx->base.pc_next = ctx->pc_succ_insn;
+ ctx->w = false;
+
+ for (int i = ctx->ntemp - 1; i >= 0; --i) {
+ tcg_temp_free(ctx->temp[i]);
+ ctx->temp[i] = NULL;
+ }
+ ctx->ntemp = 0;
if (ctx->base.is_jmp == DISAS_NEXT) {
target_ulong page_start;
@@ -1029,9 +632,11 @@ void riscv_translate_init(void)
{
int i;
- /* cpu_gpr[0] is a placeholder for the zero register. Do not use it. */
- /* Use the gen_set_gpr and gen_get_gpr helper functions when accessing */
- /* registers, unless you specifically block reads/writes to reg 0 */
+ /*
+ * cpu_gpr[0] is a placeholder for the zero register. Do not use it.
+ * Use the gen_set_gpr and get_gpr helper functions when accessing regs,
+ * unless you specifically block reads/writes to reg 0.
+ */
cpu_gpr[0] = NULL;
for (i = 1; i < 32; i++) {