Introduce register access functions with value extend capability to prepare for decodetree based translation implmentation.
Signed-off-by: Jiaxun Yang <jiaxun.y...@flygoat.com> --- target/mips/tcg/translate.c | 143 +++++++++++++++++++++++++++++++++++- target/mips/tcg/translate.h | 54 ++++++++++++++ 2 files changed, 196 insertions(+), 1 deletion(-) diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index de1511baaf..b5d595ef34 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -1196,6 +1196,17 @@ enum { MMI_OPC_MADDU1 = 0x21 | MMI_OPC_CLASS_MMI, }; +/* + * 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; + /* global register indices */ TCGv cpu_gpr[32], cpu_PC; /* @@ -1221,6 +1232,18 @@ static const char regnames_LO[][4] = { "LO0", "LO1", "LO2", "LO3", }; +static TCGv ctx_temp_new(DisasContext *ctx) +{ + assert(ctx->ntemp < ARRAY_SIZE(ctx->temp)); + return ctx->temp[ctx->ntemp++] = tcg_temp_new(); +} + +static TCGv_i64 ctx_temp_new_i64(DisasContext *ctx) +{ + assert(ctx->ntemp64 < ARRAY_SIZE(ctx->temp64)); + return ctx->temp64[ctx->ntemp64++] = tcg_temp_new_i64(); +} + /* General purpose registers moves. */ void gen_load_gpr(TCGv t, int reg) { @@ -1238,6 +1261,106 @@ void gen_store_gpr(TCGv t, int reg) } } +void gen_extend(TCGv dst, TCGv src, DisasExtend src_ext) +{ + switch (src_ext) { + case EXT_NONE: + tcg_gen_mov_tl(dst, src); + return; + case EXT_SIGN: + tcg_gen_ext32s_tl(dst, src); + return; + case EXT_ZERO: + tcg_gen_ext32u_tl(dst, src); + return; + } + g_assert_not_reached(); +} + +TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend src_ext) +{ + TCGv t; + + if (reg_num == 0) { + return ctx->zero; + } + + switch (src_ext) { + case EXT_NONE: + return cpu_gpr[reg_num]; + default: + t = ctx_temp_new(ctx); + gen_extend(t, cpu_gpr[reg_num], src_ext); + return t; + } +} + +TCGv_i64 get_hilo(DisasContext *ctx, int acc) +{ + TCGv_i64 t = ctx_temp_new_i64(ctx); + /* acc must be 0 when DSP is not implemented */ + g_assert(acc == 0 || ctx->insn_flags & ASE_DSP); + tcg_gen_concat_tl_i64(t, cpu_LO[acc], cpu_HI[acc]); + + return t; +} + +TCGv dest_gpr(DisasContext *ctx, int reg_num) +{ + if (reg_num == 0) { + return ctx_temp_new(ctx); + } + return cpu_gpr[reg_num]; +} + +TCGv dest_lo(DisasContext *ctx, int acc) +{ + /* acc must be 0 when DSP is not implemented */ + g_assert(acc == 0 || ctx->insn_flags & ASE_DSP); + + return cpu_LO[acc]; +} + +TCGv dest_hi(DisasContext *ctx, int acc) +{ + /* acc must be 0 when DSP is not implemented */ + g_assert(acc == 0 || ctx->insn_flags & ASE_DSP); + + return cpu_HI[acc]; +} + +/* For 32 bit hilo pair */ +TCGv_i64 dest_hilo(DisasContext *ctx, int acc) +{ + /* acc must be 0 when DSP is not implemented */ + g_assert(acc == 0 || ctx->insn_flags & ASE_DSP); + return ctx_temp_new_i64(ctx); +} + +void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext) +{ + if (reg_num != 0) { + gen_extend(cpu_gpr[reg_num], t, dst_ext); + } +} + +void gen_set_lo(int acc, TCGv t, DisasExtend dst_ext) +{ + gen_extend(cpu_LO[acc], t, dst_ext); +} + +void gen_set_hi(int acc, TCGv t, DisasExtend dst_ext) +{ + gen_extend(cpu_HI[acc], t, dst_ext); +} + +/* For 32 bit hilo pair */ +void gen_set_hilo(int acc, TCGv_i64 t) +{ + gen_move_low32(cpu_LO[acc], t); + gen_move_high32(cpu_HI[acc], t); +} + #if defined(TARGET_MIPS64) void gen_load_gpr_hi(TCGv_i64 t, int reg) { @@ -2615,7 +2738,6 @@ static void gen_shift_imm(DisasContext *ctx, uint32_t opc, tcg_temp_free(t0); } -/* Arithmetic */ static void gen_arith(DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { @@ -16031,6 +16153,12 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->base.max_insns = 2; } + ctx->ntemp = 0; + ctx->ntemp64 = 0; + memset(ctx->temp, 0, sizeof(ctx->temp)); + memset(ctx->temp64, 0, sizeof(ctx->temp)); + ctx->zero = tcg_constant_tl(0); + LOG_DISAS("\ntb %p idx %d hflags %04x\n", ctx->base.tb, ctx->mem_idx, ctx->hflags); } @@ -16053,6 +16181,7 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) DisasContext *ctx = container_of(dcbase, DisasContext, base); int insn_bytes; int is_slot; + int i; is_slot = ctx->hflags & MIPS_HFLAG_BMASK; if (ctx->insn_flags & ISA_NANOMIPS32) { @@ -16074,6 +16203,18 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) return; } + for (i = ctx->ntemp - 1; i >= 0; --i) { + tcg_temp_free(ctx->temp[i]); + ctx->temp[i] = NULL; + ctx->ntemp--; + } + + for (i = ctx->ntemp64 - 1; i >= 0; --i) { + tcg_temp_free_i64(ctx->temp64[i]); + ctx->temp64[i] = NULL; + ctx->ntemp64--; + } + if (ctx->hflags & MIPS_HFLAG_BMASK) { if (!(ctx->hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32 | MIPS_HFLAG_FBNSLOT))) { diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h index 69f85841d2..980aa8682d 100644 --- a/target/mips/tcg/translate.h +++ b/target/mips/tcg/translate.h @@ -49,6 +49,11 @@ typedef struct DisasContext { bool saar; bool mi; int gi; + TCGv zero; + TCGv temp[4]; + uint8_t ntemp; + TCGv_i64 temp64[4]; + uint8_t ntemp64; } DisasContext; #define DISAS_STOP DISAS_TARGET_0 @@ -119,6 +124,17 @@ enum { OPC_BC1TANY4 = (0x01 << 16) | OPC_BC1ANY4, }; +/* + * 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; + #define gen_helper_0e1i(name, arg1, arg2) do { \ gen_helper_##name(cpu_env, arg1, tcg_constant_i32(arg2)); \ } while (0) @@ -150,6 +166,18 @@ void check_cp1_64bitmode(DisasContext *ctx); void check_cp1_registers(DisasContext *ctx, int regs); void check_cop1x(DisasContext *ctx); +void gen_extend(TCGv dst, TCGv src, DisasExtend src_ext); +TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend src_ext); +TCGv_i64 get_hilo(DisasContext *ctx, int acc); +TCGv dest_gpr(DisasContext *ctx, int reg_num); +TCGv dest_lo(DisasContext *ctx, int acc); +TCGv dest_hi(DisasContext *ctx, int acc); +TCGv_i64 dest_hilo(DisasContext *ctx, int acc); +void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext); +void gen_set_lo(int acc, TCGv t, DisasExtend dst_ext); +void gen_set_hi(int acc, TCGv t, DisasExtend dst_ext); +void gen_set_hilo(int acc, TCGv_i64 t); + void gen_base_offset_addr(DisasContext *ctx, TCGv addr, int base, int offset); void gen_move_low32(TCGv ret, TCGv_i64 arg); void gen_move_high32(TCGv ret, TCGv_i64 arg); @@ -231,6 +259,32 @@ bool decode_ext_vr54xx(DisasContext *ctx, uint32_t insn); static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ { return FUNC(ctx, a, __VA_ARGS__); } +/* Instructions removed in Release 6 */ +#define TRANS_6R(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ + { return !(ctx->insn_flags & ISA_MIPS_R6) & FUNC(ctx, a, __VA_ARGS__); } + +#if defined(TARGET_MIPS64) +#define TRANS64(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ + { check_mips_64(ctx); return FUNC(ctx, a, __VA_ARGS__); } +#define TRANS64_6R(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ + { if (ctx->insn_flags & ISA_MIPS_R6) return false; check_mips_64(ctx); \ + return FUNC(ctx, a, __VA_ARGS__); } +#else +#define TRANS64(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ + { return false; } +#define TRANS64_6R(NAME, FUNC, ...) \ + static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ + { return false; } +#endif + +#define TRANS_FLAGS(NAME, FLAGS, ...) \ + static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ + { return (ctx->insn_flags & FLAGS) && FUNC(s, __VA_ARGS__); } + static inline bool cpu_is_bigendian(DisasContext *ctx) { return extract32(ctx->CP0_Config0, CP0C0_BE, 1); -- 2.34.1