@@ -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))) {
@@ -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);
Introduce register access functions with value extend capability to prepare for decodetree based translation implmentation. Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> --- target/mips/tcg/translate.c | 143 +++++++++++++++++++++++++++++++++++- target/mips/tcg/translate.h | 54 ++++++++++++++ 2 files changed, 196 insertions(+), 1 deletion(-)