qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] MIPS decodetree conversion
@ 2022-10-24 15:23 Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 1/6] target/mips: Introduce register access helper functions Jiaxun Yang
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Jiaxun Yang @ 2022-10-24 15:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: f4bug, richard.henderson, Jiaxun Yang

Currently only MIPS I to MIPS Release 5 arithmatic functions are converted.
Old decoding functions are perserved in codebase for now due to dependencies
from microMIPS/nanoMIPS translation code. Will remove them after dealing with
release 6.

Both instruction encoding and test cases are generated form MIPS's internal
architecture validation tools so they are gureented to be correct.

Note:
There are some checkpatch warning/error on test cases but I'm not going to
touch them as they are generated code.

Thanks.

RFC->v1:
 - Tidy up test cases
 - Convert TX79 as well

- Jiaxun
Jiaxun Yang (6):
  target/mips: Introduce register access helper functions
  target/mips: Convert legacy arithmatic instructions to decodetree
  tests/tcg/mips: Add mips32 arithmatic instruction test cases
  target/mips: Split Loongson extention translation into standalone file
  target/mips: Move all tx79 instructions to decodetree
  target/mips: Make MXU decoder standalone

 target/mips/tcg/insn_trans/trans_arith.c.inc  |  352 +++
 target/mips/tcg/legacy.decode                 |   62 +
 target/mips/tcg/loongson_translate.c          | 1290 +++++++++++
 target/mips/tcg/meson.build                   |    2 +
 target/mips/tcg/mxu_translate.c               |   98 +-
 target/mips/tcg/translate.c                   | 1917 ++---------------
 target/mips/tcg/translate.h                   |   60 +
 target/mips/tcg/tx79.decode                   |   14 +
 target/mips/tcg/tx79_translate.c              |  205 +-
 tests/tcg/mips/include/test_utils_32.h        |   75 +
 .../tcg/mips/user/isa/mips32/arithmatic/add.c |   99 +
 .../mips/user/isa/mips32/arithmatic/addi.c    |   70 +
 .../mips/user/isa/mips32/arithmatic/addiu.c   |   90 +
 .../mips/user/isa/mips32/arithmatic/addu.c    |  125 ++
 .../tcg/mips/user/isa/mips32/arithmatic/div.c |   81 +
 .../mips/user/isa/mips32/arithmatic/divu.c    |   78 +
 .../mips/user/isa/mips32/arithmatic/madd.c    |   79 +
 .../mips/user/isa/mips32/arithmatic/maddu.c   |   78 +
 .../mips/user/isa/mips32/arithmatic/msub.c    |   78 +
 .../mips/user/isa/mips32/arithmatic/msubu.c   |   78 +
 .../tcg/mips/user/isa/mips32/arithmatic/mul.c |   78 +
 .../mips/user/isa/mips32/arithmatic/mult.c    |   78 +
 .../mips/user/isa/mips32/arithmatic/multu.c   |   78 +
 .../tcg/mips/user/isa/mips32/arithmatic/slt.c |   61 +
 .../mips/user/isa/mips32/arithmatic/slti.c    |   48 +
 .../mips/user/isa/mips32/arithmatic/sltiu.c   |   48 +
 .../mips/user/isa/mips32/arithmatic/sltu.c    |   61 +
 .../tcg/mips/user/isa/mips32/arithmatic/sub.c |  104 +
 .../mips/user/isa/mips32/arithmatic/subu.c    |  108 +
 29 files changed, 3865 insertions(+), 1730 deletions(-)
 create mode 100644 target/mips/tcg/insn_trans/trans_arith.c.inc
 create mode 100644 target/mips/tcg/legacy.decode
 create mode 100644 target/mips/tcg/loongson_translate.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/add.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/addi.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/addiu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/addu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/div.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/divu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/madd.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/maddu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/msub.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/msubu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/mul.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/mult.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/multu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/slt.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/slti.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/sltiu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/sltu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/sub.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/subu.c

-- 
2.34.1



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/6] target/mips: Introduce register access helper functions
  2022-10-24 15:23 [PATCH 0/6] MIPS decodetree conversion Jiaxun Yang
@ 2022-10-24 15:23 ` Jiaxun Yang
  2022-10-24 22:47   ` Richard Henderson
  2022-10-24 15:23 ` [PATCH 2/6] target/mips: Convert legacy arithmatic instructions to decodetree Jiaxun Yang
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 8+ messages in thread
From: Jiaxun Yang @ 2022-10-24 15:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: f4bug, richard.henderson, Jiaxun Yang

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(-)

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



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/6] target/mips: Convert legacy arithmatic instructions to decodetree
  2022-10-24 15:23 [PATCH 0/6] MIPS decodetree conversion Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 1/6] target/mips: Introduce register access helper functions Jiaxun Yang
@ 2022-10-24 15:23 ` Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 3/6] tests/tcg/mips: Add mips32 arithmatic instruction test cases Jiaxun Yang
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Jiaxun Yang @ 2022-10-24 15:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: f4bug, richard.henderson, Jiaxun Yang

Mostly copy paste from translate.c, with some simplification
based on newly introduced register access functions.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/tcg/insn_trans/trans_arith.c.inc | 352 +++++++++++++++++++
 target/mips/tcg/legacy.decode                |  62 ++++
 target/mips/tcg/meson.build                  |   1 +
 target/mips/tcg/translate.c                  |  20 +-
 4 files changed, 425 insertions(+), 10 deletions(-)
 create mode 100644 target/mips/tcg/insn_trans/trans_arith.c.inc
 create mode 100644 target/mips/tcg/legacy.decode

diff --git a/target/mips/tcg/insn_trans/trans_arith.c.inc b/target/mips/tcg/insn_trans/trans_arith.c.inc
new file mode 100644
index 0000000000..3de9722939
--- /dev/null
+++ b/target/mips/tcg/insn_trans/trans_arith.c.inc
@@ -0,0 +1,352 @@
+static bool gen_arith_notrap(DisasContext *ctx, arg_r *a,
+                             DisasExtend ext, void (*func)(TCGv, TCGv, TCGv))
+{
+    TCGv dest = dest_gpr(ctx, a->rd);
+    TCGv src1 = get_gpr(ctx, a->rs, ext);
+    TCGv src2 = get_gpr(ctx, a->rt, ext);
+
+    func(dest, src1, src2);
+    gen_set_gpr(a->rd, dest, ext);
+
+    return true;
+}
+
+static bool gen_add(DisasContext *ctx, arg_r *a, DisasExtend ext)
+{
+    TCGv t0 = tcg_temp_local_new();
+    TCGv t1 = get_gpr(ctx, a->rs, ext);
+    TCGv t2 = get_gpr(ctx, a->rt, ext);
+    TCGLabel *l1 = gen_new_label();
+
+    tcg_gen_add_tl(t0, t1, t2);
+    gen_extend(t0, t0, ext);
+    tcg_gen_xor_tl(t1, t1, t2);
+    tcg_gen_xor_tl(t2, t0, t2);
+    tcg_gen_andc_tl(t1, t2, t1);
+    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+    /* operands of same sign, result different sign */
+    generate_exception(ctx, EXCP_OVERFLOW);
+    gen_set_label(l1);
+    gen_store_gpr(t0, a->rd);
+    tcg_temp_free(t0);
+
+    return true;
+}
+
+static bool gen_sub(DisasContext *ctx, arg_r *a, DisasExtend ext)
+{
+    TCGv src1 = get_gpr(ctx, a->rs, ext);
+    TCGv src2 = get_gpr(ctx, a->rt, ext);
+    TCGv t0 = tcg_temp_local_new();
+    TCGv t1 = tcg_temp_local_new();
+    TCGv t2 = tcg_temp_local_new();
+    TCGLabel *l1 = gen_new_label();
+
+    tcg_gen_sub_tl(t0, src1, src2);
+    gen_extend(t0, t0, ext);
+    tcg_gen_xor_tl(t2, src1, src2);
+    tcg_gen_xor_tl(t1, t0, src1);
+    tcg_gen_and_tl(t1, t1, t2);
+    tcg_temp_free(t2);
+    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+    tcg_temp_free(t1);
+    /*
+     * operands of different sign, first operand and the result
+     * of different sign
+     */
+    generate_exception(ctx, EXCP_OVERFLOW);
+    gen_set_label(l1);
+    gen_store_gpr(t0, a->rd);
+    tcg_temp_free(t0);
+
+    return true;
+}
+
+static bool gen_arith_imm_notrap(DisasContext *ctx, arg_i *a, DisasExtend ext,
+                             void (*func)(TCGv, TCGv, target_long))
+{
+    TCGv dest = dest_gpr(ctx, a->rt);
+    TCGv src1 = get_gpr(ctx, a->rs, ext);
+
+    func(dest, src1, a->imm);
+    gen_set_gpr(a->rt, dest, ext);
+
+    return true;
+}
+
+static bool gen_add_imm(DisasContext *ctx, arg_i *a, DisasExtend ext)
+{
+    TCGv t0 = tcg_temp_local_new();
+    TCGv t1 = get_gpr(ctx, a->rs, ext);
+    TCGv t2 = tcg_temp_new();
+    TCGLabel *l1 = gen_new_label();
+    target_ulong uimm = (target_long)a->imm; /* Sign extend to 32/64 bits */
+
+    gen_load_gpr(t1, a->rs);
+    tcg_gen_addi_tl(t0, t1, uimm);
+    tcg_gen_ext32s_tl(t0, t0);
+
+    tcg_gen_xori_tl(t1, t1, ~uimm);
+    tcg_gen_xori_tl(t2, t0, uimm);
+    tcg_gen_and_tl(t1, t1, t2);
+    tcg_temp_free(t2);
+    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+    /* operands of same sign, result different sign */
+    generate_exception(ctx, EXCP_OVERFLOW);
+    gen_set_label(l1);
+    tcg_gen_ext32s_tl(t0, t0);
+    gen_store_gpr(t0, a->rt);
+    tcg_temp_free(t0);
+
+    return true;
+}
+
+#define DECLEAR_GEN_CL(suffix, arg_type)                                    \
+static bool gen_cl_##suffix(DisasContext *ctx, arg_type * a, bool zero)     \
+{                                                                           \
+    TCGv dest = dest_gpr(ctx, a->rd);                                       \
+    TCGv src = get_gpr(ctx, a->rs, EXT_NONE);                               \
+    if (!zero) {                                                            \
+        tcg_gen_not_tl(dest, src);                                          \
+    }                                                                       \
+    tcg_gen_ext32u_tl(dest, dest);                                          \
+    tcg_gen_clzi_tl(dest, dest, TARGET_LONG_BITS);                          \
+    tcg_gen_subi_tl(dest, dest, TARGET_LONG_BITS - 32);                     \
+    gen_set_gpr(a->rd, dest, EXT_NONE);                                     \
+    return true;                                                            \
+}                                                                           \
+
+DECLEAR_GEN_CL(legacy, arg_r)
+#undef DECLEAR_GEN_CL
+
+#ifdef TARGET_MIPS64
+#define DECLEAR_GEN_DCL(suffix, arg_type)                                   \
+static bool gen_dcl_##suffix(DisasContext *ctx, arg_type * a, bool zero)    \
+{                                                                           \
+    TCGv dest = dest_gpr(ctx, a->rd);                                       \
+    TCGv src = get_gpr(ctx, a->rs, EXT_NONE);                               \
+    if (!zero) {                                                            \
+        tcg_gen_not_tl(dest, src);                                          \
+    }                                                                       \
+    tcg_gen_clzi_i64(dest, dest, 64);                                       \
+    gen_set_gpr(a->rd, dest, EXT_NONE);                                     \
+    return true;                                                            \
+}                                                                           \
+
+DECLEAR_GEN_DCL(legacy, arg_r)
+#undef DECLEAR_GEN_DCL
+#endif
+
+static bool gen_setcond(DisasContext *ctx, arg_r *a, TCGCond cond)
+{
+    TCGv dest = dest_gpr(ctx, a->rd);
+    TCGv src1 = get_gpr(ctx, a->rs, EXT_NONE);
+    TCGv src2 = get_gpr(ctx, a->rt, EXT_NONE);
+
+    tcg_gen_setcond_tl(cond, dest, src1, src2);
+
+    gen_set_gpr(a->rd, dest, EXT_NONE);
+
+    return true;
+}
+
+static bool gen_setcond_imm(DisasContext *ctx, arg_i *a, TCGCond cond)
+{
+    TCGv dest = dest_gpr(ctx, a->rt);
+    TCGv src1 = get_gpr(ctx, a->rs, EXT_NONE);
+
+    tcg_gen_setcondi_tl(cond, dest, src1, a->imm);
+
+    gen_set_gpr(a->rt, dest, EXT_NONE);
+
+    return true;
+}
+
+static bool gen_mult32(DisasContext *ctx, arg_r2_s *a,
+                       void (*func)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32))
+{
+    TCGv src1 = get_gpr(ctx, a->rs, EXT_NONE);
+    TCGv src2 = get_gpr(ctx, a->rt, EXT_NONE);
+    TCGv dst_lo = dest_lo(ctx, 0);
+    TCGv dst_hi = dest_hi(ctx, 0);
+    TCGv_i32 t1 = tcg_temp_new_i32();
+    TCGv_i32 t2 = tcg_temp_new_i32();
+
+    tcg_gen_trunc_tl_i32(t1, src1);
+    tcg_gen_trunc_tl_i32(t2, src2);
+
+    func(t1, t2, t1, t2);
+
+    tcg_gen_ext_i32_tl(dst_lo, t1);
+    tcg_gen_ext_i32_tl(dst_hi, t2);
+
+    gen_set_lo(0, dst_lo, EXT_NONE);
+    gen_set_hi(0, dst_hi, EXT_NONE);
+
+    return true;
+}
+
+#if defined(TARGET_MIPS64)
+static bool gen_mult64(DisasContext *ctx, arg_r2_s *a,
+                       void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv src1 = get_gpr(ctx, a->rs, EXT_NONE);
+    TCGv src2 = get_gpr(ctx, a->rt, EXT_NONE);
+    TCGv dst_lo = dest_lo(ctx, 0);
+    TCGv dst_hi = dest_hi(ctx, 0);
+
+    func(dst_lo, dst_hi, src1, src2);
+
+    gen_set_lo(0, dst_lo, EXT_NONE);
+    gen_set_hi(0, dst_hi, EXT_NONE);
+
+    return true;
+}
+#endif
+
+static bool gen_div(DisasContext *ctx, arg_r2_s *a, DisasExtend src_ext,
+                    DisasExtend dst_ext)
+{
+    TCGv temp1, temp2, zero, one, mone, min;
+    TCGv src1 = get_gpr(ctx, a->rs, src_ext);
+    TCGv src2 = get_gpr(ctx, a->rt, src_ext);
+    TCGv dst_lo = dest_lo(ctx, 0);
+    TCGv dst_hi = dest_hi(ctx, 0);
+
+    temp1 = tcg_temp_new();
+    temp2 = tcg_temp_new();
+    zero = tcg_constant_tl(0);
+    one = tcg_constant_tl(1);
+    mone = tcg_constant_tl(-1);
+    min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
+
+    /*
+     * If overflow, set temp2 to 1, else source2.
+     * This produces the required result of min.
+     */
+    tcg_gen_setcond_tl(TCG_COND_EQ, temp1, src1, min);
+    tcg_gen_setcond_tl(TCG_COND_EQ, temp2, src2, mone);
+    tcg_gen_and_tl(temp1, temp1, temp2);
+    tcg_gen_movcond_tl(TCG_COND_NE, temp2, temp1, zero, one, src2);
+
+    /*
+     * If div by zero, set temp1 to -1 and temp2 to 1 to
+     * produce the required result of -1.
+     */
+    tcg_gen_movcond_tl(TCG_COND_EQ, temp1, src2, zero, mone, src1);
+    tcg_gen_movcond_tl(TCG_COND_EQ, temp2, src2, zero, one, src2);
+
+    tcg_gen_div_tl(dst_lo, temp1, temp2);
+    tcg_gen_rem_tl(dst_hi, temp1, temp2);
+
+    tcg_temp_free(temp1);
+    tcg_temp_free(temp2);
+
+    gen_set_lo(0, dst_lo, dst_ext);
+    gen_set_hi(0, dst_hi, dst_ext);
+
+    return true;
+}
+
+static bool gen_divu(DisasContext *ctx, arg_r2_s *a, DisasExtend src_ext,
+                    DisasExtend dst_ext)
+{
+    TCGv temp1, temp2, zero, one, max;
+    TCGv src1 = get_gpr(ctx, a->rs, src_ext);
+    TCGv src2 = get_gpr(ctx, a->rt, src_ext);
+    TCGv dst_lo = dest_lo(ctx, 0);
+    TCGv dst_hi = dest_hi(ctx, 0);
+
+    temp1 = tcg_temp_new();
+    temp2 = tcg_temp_new();
+    zero = tcg_constant_tl(0);
+    one = tcg_constant_tl(1);
+    max = tcg_constant_tl(~0);
+
+    /*
+     * If div by zero, set temp1 to max and temp2 to 1 to
+     * produce the required result of max.
+     */
+    tcg_gen_movcond_tl(TCG_COND_EQ, temp1, src2, zero, max, src1);
+    tcg_gen_movcond_tl(TCG_COND_EQ, temp2, src2, zero, one, src2);
+
+    tcg_gen_divu_tl(dst_lo, temp1, temp2);
+    tcg_gen_remu_tl(dst_hi, temp1, temp2);
+
+    tcg_temp_free(temp1);
+    tcg_temp_free(temp2);
+
+    gen_set_lo(0, dst_lo, dst_ext);
+    gen_set_hi(0, dst_hi, dst_ext);
+
+    return true;
+}
+
+static bool gen_mul_addsub(DisasContext *ctx, arg_r2_s *a, DisasExtend ext,
+                            void (*func)(TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv src1 = get_gpr(ctx, a->rs, ext);
+    TCGv src2 = get_gpr(ctx, a->rt, ext);
+    TCGv_i64 src3 = get_hilo(ctx, 0);
+    TCGv_i64 dst = dest_hilo(ctx, 0);
+    TCGv_i64 t2 = tcg_temp_new_i64();
+    TCGv_i64 t3 = tcg_temp_new_i64();
+
+    switch (ext) {
+    case EXT_SIGN:
+        tcg_gen_ext_tl_i64(t2, src1);
+        tcg_gen_ext_tl_i64(t3, src2);
+        break;
+    case EXT_ZERO:
+        tcg_gen_extu_tl_i64(t2, src1);
+        tcg_gen_extu_tl_i64(t3, src2);
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+
+    tcg_gen_mul_i64(dst, t2, t3);
+    tcg_temp_free_i64(t2);
+    tcg_temp_free_i64(t3);
+    func(dst, dst, src3);
+
+    gen_set_hilo(0, dst);
+
+    return true;
+}
+
+TRANS(ADD, gen_add, EXT_SIGN)
+TRANS(ADDU, gen_arith_notrap, EXT_SIGN, tcg_gen_add_tl)
+TRANS_6R(ADDI, gen_add_imm, EXT_SIGN)
+TRANS(ADDIU, gen_arith_imm_notrap, EXT_SIGN, tcg_gen_addi_tl)
+TRANS(SUB, gen_sub, EXT_SIGN)
+TRANS(SUBU, gen_arith_notrap, EXT_SIGN, tcg_gen_sub_tl)
+TRANS_6R(CLO, gen_cl_legacy, false)
+TRANS_6R(CLZ, gen_cl_legacy, true)
+TRANS(SLT, gen_setcond, TCG_COND_LT)
+TRANS(SLTU, gen_setcond, TCG_COND_LTU)
+TRANS(SLTI, gen_setcond_imm, TCG_COND_LT)
+TRANS(SLTIU, gen_setcond_imm, TCG_COND_LTU)
+TRANS_6R(MUL, gen_arith_notrap, EXT_SIGN, tcg_gen_mul_tl)
+TRANS_6R(MULT, gen_mult32, tcg_gen_muls2_i32)
+TRANS_6R(MULTU, gen_mult32, tcg_gen_mulu2_i32)
+TRANS_6R(DIV, gen_div, EXT_SIGN, EXT_SIGN)
+TRANS_6R(DIVU, gen_divu, EXT_ZERO, EXT_SIGN)
+TRANS_6R(MADD, gen_mul_addsub, EXT_SIGN, tcg_gen_add_i64)
+TRANS_6R(MADDU, gen_mul_addsub, EXT_ZERO, tcg_gen_add_i64)
+TRANS_6R(MSUB, gen_mul_addsub, EXT_SIGN, tcg_gen_sub_i64)
+TRANS_6R(MSUBU, gen_mul_addsub, EXT_ZERO, tcg_gen_sub_i64)
+
+TRANS64(DADD, gen_add, EXT_NONE)
+TRANS64(DADDU, gen_arith_notrap, EXT_NONE, tcg_gen_add_tl)
+TRANS64_6R(DADDI, gen_add_imm, EXT_NONE)
+TRANS64(DADDIU, gen_arith_imm_notrap, EXT_NONE, tcg_gen_addi_tl)
+TRANS64(DSUB, gen_sub, EXT_NONE)
+TRANS64(DSUBU, gen_arith_notrap, EXT_NONE, tcg_gen_sub_tl)
+TRANS64_6R(DCLO, gen_dcl_legacy, false)
+TRANS64_6R(DCLZ, gen_dcl_legacy, true)
+TRANS64_6R(DMULT, gen_mult64, tcg_gen_muls2_i64)
+TRANS64_6R(DMULTU, gen_mult64, tcg_gen_mulu2_i64)
+TRANS64_6R(DDIV, gen_div, EXT_NONE, EXT_NONE)
+TRANS64_6R(DDIVU, gen_divu, EXT_NONE, EXT_NONE)
diff --git a/target/mips/tcg/legacy.decode b/target/mips/tcg/legacy.decode
new file mode 100644
index 0000000000..d535fbe31b
--- /dev/null
+++ b/target/mips/tcg/legacy.decode
@@ -0,0 +1,62 @@
+# MIPS I to MIPS Release 5 instructions
+#
+# Copyright (C) 2022 Jiaxun Yang
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+
+
+# Fields:
+%rd       11:5
+%rs       21:5
+%rt       16:5
+
+%imms16   0:s16
+
+# Argument sets:
+&empty
+&r      rd rs rt
+&r2_s   rs rt
+&i      rt rs imm
+
+# Formats:
+@r             ................................     &r  %rd %rs %rt
+@r2_s          ................................     &r2_s %rs %rt
+@i             ................................     &i   %rt %rs imm=%imms16
+
+# Base arithmetic instructions
+ADD            000000 ...............00000100000       @r
+ADDI           001000 ..........................       @i # 6R
+ADDIU          001001 ..........................       @i
+ADDU           000000 ...............00000100001       @r
+CLO            011100 ...............00000100001       @r # 6Rm
+CLZ            011100 ...............00000100000       @r # 6Rm
+DIV            000000 ..........0000000000011010       @r2_s # 6R
+DIVU           000000 ..........0000000000011011       @r2_s # 6R
+MADD           011100 ..........0000000000000000       @r2_s # 6R
+MADDU          011100 ..........0000000000000001       @r2_s # 6R
+MSUB           011100 ..........0000000000000100       @r2_s # 6R
+MSUBU          011100 ..........0000000000000101       @r2_s # 6R
+MUL            011100 ...............00000000010       @r    # 6R
+MULT           000000 ..........0000000000011000       @r2_s # 6R
+MULTU          000000 ..........0000000000011001       @r2_s # 6R
+SLT            000000 ...............00000101010       @r
+SLTI           001010 ..........................       @i
+SLTIU          001011 ..........................       @i
+SLTU           000000 ...............00000101011       @r
+SUB            000000 ...............00000100010       @r
+SUBU           000000 ...............00000100011       @r
+
+
+DADD           000000 ...............00000101100       @r
+DADDI          011000 ..........................       @i # 6R
+DADDIU         011001 ..........................       @i
+DADDU          000000 ...............00000101101       @r
+DCLO           011100 ...............00000100101       @r # 6Rm
+DCLZ           011100 ...............00000100100       @r # 6Rm
+DDIV           000000 ..........0000000000011110       @r2_s # 6R
+DDIVU          000000 ..........0000000000011111       @r2_s # 6R
+DSUB           000000 ...............00000101110       @r
+DSUBU          000000 ...............00000101111       @r
+DMULT          000000 ..........0000000000011100       @r2_s # 6R
+DMULTU         000000 ..........0000000000011101       @r2_s  # 6R
diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build
index 7ee969ec8f..7a27fe93e0 100644
--- a/target/mips/tcg/meson.build
+++ b/target/mips/tcg/meson.build
@@ -1,4 +1,5 @@
 gen = [
+  decodetree.process('legacy.decode', extra_args: ['--static-decode=decode_isa_legacy']),
   decodetree.process('rel6.decode', extra_args: ['--decode=decode_isa_rel6']),
   decodetree.process('msa.decode', extra_args: '--decode=decode_ase_msa'),
   decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'),
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index b5d595ef34..bcb267e6bd 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -38,6 +38,9 @@
 #include "fpu_helper.h"
 #include "translate.h"
 
+/* Include the generated ISA decoders */
+#include "decode-legacy.c.inc"
+
 /*
  * Many sysemu-only helpers are not reachable for user-only.
  * Define stub generators here, so that we need not either sprinkle
@@ -1196,16 +1199,6 @@ 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;
@@ -12261,6 +12254,9 @@ static void gen_sync(int stype)
     tcg_gen_mb(tcg_mo);
 }
 
+/* ISA base */
+#include "insn_trans/trans_arith.c.inc"
+
 /* ISA extensions (ASEs) */
 
 /* MIPS16 extension to MIPS32 */
@@ -16090,6 +16086,10 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
         return;
     }
 
+    if (decode_isa_legacy(ctx, ctx->opcode)) {
+        return;
+    }
+
     if (decode_opc_legacy(env, ctx)) {
         return;
     }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/6] tests/tcg/mips: Add mips32 arithmatic instruction test cases
  2022-10-24 15:23 [PATCH 0/6] MIPS decodetree conversion Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 1/6] target/mips: Introduce register access helper functions Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 2/6] target/mips: Convert legacy arithmatic instructions to decodetree Jiaxun Yang
@ 2022-10-24 15:23 ` Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 4/6] target/mips: Split Loongson extention translation into standalone file Jiaxun Yang
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Jiaxun Yang @ 2022-10-24 15:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: f4bug, richard.henderson, Jiaxun Yang

Those cases are delivered from MIPS internal architecture validation
tools.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 tests/tcg/mips/include/test_utils_32.h        |  75 +++++++++++
 .../tcg/mips/user/isa/mips32/arithmatic/add.c |  99 ++++++++++++++
 .../mips/user/isa/mips32/arithmatic/addi.c    |  70 ++++++++++
 .../mips/user/isa/mips32/arithmatic/addiu.c   |  90 +++++++++++++
 .../mips/user/isa/mips32/arithmatic/addu.c    | 125 ++++++++++++++++++
 .../tcg/mips/user/isa/mips32/arithmatic/div.c |  81 ++++++++++++
 .../mips/user/isa/mips32/arithmatic/divu.c    |  78 +++++++++++
 .../mips/user/isa/mips32/arithmatic/madd.c    |  79 +++++++++++
 .../mips/user/isa/mips32/arithmatic/maddu.c   |  78 +++++++++++
 .../mips/user/isa/mips32/arithmatic/msub.c    |  78 +++++++++++
 .../mips/user/isa/mips32/arithmatic/msubu.c   |  78 +++++++++++
 .../tcg/mips/user/isa/mips32/arithmatic/mul.c |  78 +++++++++++
 .../mips/user/isa/mips32/arithmatic/mult.c    |  78 +++++++++++
 .../mips/user/isa/mips32/arithmatic/multu.c   |  78 +++++++++++
 .../tcg/mips/user/isa/mips32/arithmatic/slt.c |  61 +++++++++
 .../mips/user/isa/mips32/arithmatic/slti.c    |  48 +++++++
 .../mips/user/isa/mips32/arithmatic/sltiu.c   |  48 +++++++
 .../mips/user/isa/mips32/arithmatic/sltu.c    |  61 +++++++++
 .../tcg/mips/user/isa/mips32/arithmatic/sub.c | 104 +++++++++++++++
 .../mips/user/isa/mips32/arithmatic/subu.c    | 108 +++++++++++++++
 20 files changed, 1595 insertions(+)
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/add.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/addi.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/addiu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/addu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/div.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/divu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/madd.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/maddu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/msub.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/msubu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/mul.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/mult.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/multu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/slt.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/slti.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/sltiu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/sltu.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/sub.c
 create mode 100644 tests/tcg/mips/user/isa/mips32/arithmatic/subu.c

diff --git a/tests/tcg/mips/include/test_utils_32.h b/tests/tcg/mips/include/test_utils_32.h
index c33990c0c5..00480e3283 100644
--- a/tests/tcg/mips/include/test_utils_32.h
+++ b/tests/tcg/mips/include/test_utils_32.h
@@ -29,6 +29,81 @@
 
 #define PRINT_RESULTS 0
 
+#define DO_MIPS32_r(mnemonic, id, input1, input2, expect)              \
+{                                                                      \
+    uint32_t output;                                                   \
+    uint32_t expect_val = expect;                                      \
+    __asm__ volatile (                                                 \
+      "li $t1, " #input1 "\n\t"                                        \
+      "li $t2, " #input2 "\n\t"                                        \
+      #mnemonic " $t0, $t1, $t2\n\t"                                   \
+      "sw $t0, 0(%0)\n\t"                                              \
+      :                                                                \
+      : "r" (&output)                                                  \
+      : "t0", "t1", "t2", "memory"                                     \
+    );                                                                 \
+    check_single_insn_32(id, &pass_count, &fail_count, 1, &expect_val, &output); \
+}
+
+#define DO_MIPS32_i(mnemonic, id, imm, input1, expect)                 \
+{                                                                      \
+    uint32_t output;                                                   \
+    uint32_t expect_val = expect;                                      \
+    __asm__ volatile (                                                 \
+      "li $t1, " #input1 "\n\t"                                        \
+      #mnemonic " $t0, $t1, " #imm "\n\t"                              \
+      "sw $t0, 0(%0)\n\t"                                              \
+      :                                                                \
+      : "r" (&output)                                                  \
+      : "t0", "t1", "memory"                                           \
+    );                                                                 \
+    check_single_insn_32(id, &pass_count, &fail_count, 1, &expect_val, &output); \
+}
+
+#define DO_MIPS32_r2_s(mnemonic, id, hi, lo, input1, input2, expect_hi, expect_lo) \
+{                                                                      \
+    uint32_t output[2];                                                \
+    uint32_t expect_val[2] = {expect_lo, expect_hi};                   \
+    __asm__ volatile (                                                 \
+      ".set noreorder \n\t"                                            \
+      "li $t0, " #hi "\n\t"                                            \
+      "mthi $t0       \n\t"                                            \
+      "li $t0, " #lo "\n\t"                                            \
+      "mtlo $t0       \n\t"                                            \
+      "li $t0, " #input1 "\n\t"                                        \
+      "li $t1, " #input2 "\n\t"                                        \
+      #mnemonic " $t0, $t1 \n\t"                                       \
+      "mfhi $t0       \n\t"                                            \
+      "sw $t0, 4(%0)\n\t"                                              \
+      "mflo $t0       \n\t"                                            \
+      "sw $t0, 0(%0)\n\t"                                              \
+      ".set reorder \n\t"                                              \
+      :                                                                \
+      : "r" (&output)                                                  \
+      : "t0", "t1", "hi", "lo", "memory"                              \
+    );                                                                 \
+    check_single_insn_32(id, &pass_count, &fail_count, 2, expect_val, output); \
+}
+
+static inline void check_single_insn_32(int id, int *pass, int *fail, int cnt,
+                                        uint32_t *expect, uint32_t *actual)
+{
+    int i;
+
+    if (memcmp(expect, actual, 4 * cnt) == 0) {
+        (*pass)++;
+        printf("Case %d pass:\n", id);
+        for (i = 0; i < cnt; i++) {
+            printf("    [%d]: actual: 0x%08x, expect: 0x%08x\n", i, actual[i], expect[i]);
+        }
+    } else {
+        (*fail)++;
+        printf("Case %d fail:\n", id);
+        for (i = 0; i < cnt; i++) {
+            printf("    [%d]: actual: 0x%08x, expect: 0x%08x\n", i, actual[i], expect[i]);
+        }
+    }
+}
 
 static inline int32_t check_results_32(const char *instruction_name,
                                        const uint32_t test_count,
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/add.c b/tests/tcg/mips/user/isa/mips32/arithmatic/add.c
new file mode 100644
index 0000000000..2e1d380c90
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/add.c
@@ -0,0 +1,99 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r(add, 0, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r(add, 1, 0x00000001, 0x00000001, 0x00000002);
+    DO_MIPS32_r(add, 2, 0x00000002, 0x00000003, 0x00000005);
+    DO_MIPS32_r(add, 3, 0x00000004, 0x00000007, 0x0000000B);
+    DO_MIPS32_r(add, 4, 0x00000008, 0x0000000F, 0x00000017);
+    DO_MIPS32_r(add, 5, 0x00000010, 0x0000001F, 0x0000002F);
+    DO_MIPS32_r(add, 6, 0x00000020, 0x0000003F, 0x0000005F);
+    DO_MIPS32_r(add, 7, 0x00000040, 0x0000007F, 0x000000BF);
+    DO_MIPS32_r(add, 8, 0x00000080, 0x000000FF, 0x0000017F);
+    DO_MIPS32_r(add, 9, 0x00000100, 0x000001FF, 0x000002FF);
+    DO_MIPS32_r(add, 10, 0x00000200, 0x000003FF, 0x000005FF);
+    DO_MIPS32_r(add, 11, 0x00000400, 0x000007FF, 0x00000BFF);
+    DO_MIPS32_r(add, 12, 0x00000800, 0x00000FFF, 0x000017FF);
+    DO_MIPS32_r(add, 13, 0x00001000, 0x00001FFF, 0x00002FFF);
+    DO_MIPS32_r(add, 14, 0x00002000, 0x00003FFF, 0x00005FFF);
+    DO_MIPS32_r(add, 15, 0x00004000, 0x00007FFF, 0x0000BFFF);
+    DO_MIPS32_r(add, 16, 0x00008000, 0x0000FFFF, 0x00017FFF);
+    DO_MIPS32_r(add, 17, 0x00010000, 0x0001FFFF, 0x0002FFFF);
+    DO_MIPS32_r(add, 18, 0x00020000, 0x0003FFFF, 0x0005FFFF);
+    DO_MIPS32_r(add, 19, 0x00040000, 0x0007FFFF, 0x000BFFFF);
+    DO_MIPS32_r(add, 20, 0x00080000, 0x000FFFFF, 0x0017FFFF);
+    DO_MIPS32_r(add, 21, 0x00100000, 0x001FFFFF, 0x002FFFFF);
+    DO_MIPS32_r(add, 22, 0x00200000, 0x003FFFFF, 0x005FFFFF);
+    DO_MIPS32_r(add, 23, 0x00400000, 0x007FFFFF, 0x00BFFFFF);
+    DO_MIPS32_r(add, 24, 0x00800000, 0x00FFFFFF, 0x017FFFFF);
+    DO_MIPS32_r(add, 25, 0x01000000, 0x01FFFFFF, 0x02FFFFFF);
+    DO_MIPS32_r(add, 26, 0x02000000, 0x03FFFFFF, 0x05FFFFFF);
+    DO_MIPS32_r(add, 27, 0x04000000, 0x07FFFFFF, 0x0BFFFFFF);
+    DO_MIPS32_r(add, 28, 0x08000000, 0x0FFFFFFF, 0x17FFFFFF);
+    DO_MIPS32_r(add, 29, 0x10000000, 0x1FFFFFFF, 0x2FFFFFFF);
+    DO_MIPS32_r(add, 30, 0x20000000, 0x3FFFFFFF, 0x5FFFFFFF);
+    DO_MIPS32_r(add, 31, 0x00000000, 0x00000001, 0x00000001);
+    DO_MIPS32_r(add, 32, 0x80000001, 0xFFFFFFFF, 0x80000000);
+    DO_MIPS32_r(add, 33, 0xC0000003, 0x7FFFFFFD, 0x40000000);
+    DO_MIPS32_r(add, 34, 0xE0000007, 0x3FFFFFF9, 0x20000000);
+    DO_MIPS32_r(add, 35, 0xF000000F, 0x1FFFFFF1, 0x10000000);
+    DO_MIPS32_r(add, 36, 0xF800001F, 0x0FFFFFE1, 0x08000000);
+    DO_MIPS32_r(add, 37, 0xFC00003F, 0x07FFFFC1, 0x04000000);
+    DO_MIPS32_r(add, 38, 0xFE00007F, 0x03FFFF81, 0x02000000);
+    DO_MIPS32_r(add, 39, 0xFF0000FF, 0x01FFFF01, 0x01000000);
+    DO_MIPS32_r(add, 40, 0xFF8001FF, 0x00FFFE01, 0x00800000);
+    DO_MIPS32_r(add, 41, 0xFFC003FF, 0x007FFC01, 0x00400000);
+    DO_MIPS32_r(add, 42, 0xFFE007FF, 0x003FF801, 0x00200000);
+    DO_MIPS32_r(add, 43, 0xFFF00FFF, 0x001FF001, 0x00100000);
+    DO_MIPS32_r(add, 44, 0xFFF81FFF, 0x000FE001, 0x00080000);
+    DO_MIPS32_r(add, 45, 0xFFFC3FFF, 0x0007C001, 0x00040000);
+    DO_MIPS32_r(add, 46, 0xFFFE7FFF, 0x00038001, 0x00020000);
+    DO_MIPS32_r(add, 47, 0xFFFFFFFF, 0x00010001, 0x00010000);
+    DO_MIPS32_r(add, 48, 0xFFFFFFFF, 0x00018001, 0x00018000);
+    DO_MIPS32_r(add, 49, 0xFFFE7FFF, 0x00024001, 0x0000C000);
+    DO_MIPS32_r(add, 50, 0xFFFC3FFF, 0x00042001, 0x00006000);
+    DO_MIPS32_r(add, 51, 0xFFF81FFF, 0x00081001, 0x00003000);
+    DO_MIPS32_r(add, 52, 0xFFF00FFF, 0x00100801, 0x00001800);
+    DO_MIPS32_r(add, 53, 0xFFE007FF, 0x00200401, 0x00000C00);
+    DO_MIPS32_r(add, 54, 0xFFC003FF, 0x00400201, 0x00000600);
+    DO_MIPS32_r(add, 55, 0xFF8001FF, 0x00800101, 0x00000300);
+    DO_MIPS32_r(add, 56, 0xFF0000FF, 0x01000081, 0x00000180);
+    DO_MIPS32_r(add, 57, 0xFE00007F, 0x02000041, 0x000000C0);
+    DO_MIPS32_r(add, 58, 0xFC00003F, 0x04000021, 0x00000060);
+    DO_MIPS32_r(add, 59, 0xF800001F, 0x08000011, 0x00000030);
+    DO_MIPS32_r(add, 60, 0xF000000F, 0x10000009, 0x00000018);
+    DO_MIPS32_r(add, 61, 0xE0000007, 0x20000005, 0x0000000C);
+    DO_MIPS32_r(add, 62, 0xC0000003, 0x40000003, 0x00000006);
+    DO_MIPS32_r(add, 63, 0x00000000, 0x55555555, 0x55555555);
+    DO_MIPS32_r(add, 64, 0x15555555, 0x55555555, 0x6AAAAAAA);
+    DO_MIPS32_r(add, 65, 0xAAAAAAAA, 0x55555555, 0xFFFFFFFF);
+    DO_MIPS32_r(add, 66, 0xFFFFFFFF, 0x55555555, 0x55555554);
+    DO_MIPS32_r(add, 67, 0xAAAAAAAA, 0x00000000, 0xAAAAAAAA);
+    DO_MIPS32_r(add, 68, 0xAAAAAAAA, 0x55555555, 0xFFFFFFFF);
+    DO_MIPS32_r(add, 69, 0xAAAAAAAA, 0x2AAAAAAA, 0xD5555554);
+    DO_MIPS32_r(add, 70, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAA9);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/addi.c b/tests/tcg/mips/user/isa/mips32/arithmatic/addi.c
new file mode 100644
index 0000000000..c032e4d9e5
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/addi.c
@@ -0,0 +1,70 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_i(addi, 0, 0x0000, 0x00000000, 0x00000000);
+    DO_MIPS32_i(addi, 1, 0x0001, 0x00000001, 0x00000002);
+    DO_MIPS32_i(addi, 2, 0x0003, 0x00000002, 0x00000005);
+    DO_MIPS32_i(addi, 3, 0x0007, 0x00000004, 0x0000000B);
+    DO_MIPS32_i(addi, 4, 0x000F, 0x00000008, 0x00000017);
+    DO_MIPS32_i(addi, 5, 0x001F, 0x00000010, 0x0000002F);
+    DO_MIPS32_i(addi, 6, 0x003F, 0x00000020, 0x0000005F);
+    DO_MIPS32_i(addi, 7, 0x007F, 0x00000040, 0x000000BF);
+    DO_MIPS32_i(addi, 8, 0x00FF, 0x00000080, 0x0000017F);
+    DO_MIPS32_i(addi, 9, 0x01FF, 0x00000100, 0x000002FF);
+    DO_MIPS32_i(addi, 10, 0x03FF, 0x00000200, 0x000005FF);
+    DO_MIPS32_i(addi, 11, 0x07FF, 0x00000400, 0x00000BFF);
+    DO_MIPS32_i(addi, 12, 0x0FFF, 0x00000800, 0x000017FF);
+    DO_MIPS32_i(addi, 13, 0x1FFF, 0x00001000, 0x00002FFF);
+    DO_MIPS32_i(addi, 14, 0x3FFF, 0x00002000, 0x00005FFF);
+    DO_MIPS32_i(addi, 15, 0x7FFF, 0x00004000, 0x0000BFFF);
+    DO_MIPS32_i(addi, 16, 0xFFFF, 0x00008000, 0x00007FFF);
+    DO_MIPS32_i(addi, 17, 0x0001, 0x00000000, 0x00000001);
+    DO_MIPS32_i(addi, 18, 0xFFFF, 0x80000001, 0x80000000);
+    DO_MIPS32_i(addi, 19, 0xFFFD, 0xC0000003, 0xC0000000);
+    DO_MIPS32_i(addi, 20, 0xFFF9, 0xE0000007, 0xE0000000);
+    DO_MIPS32_i(addi, 21, 0xFFF1, 0xF000000F, 0xF0000000);
+    DO_MIPS32_i(addi, 22, 0xFFE1, 0xF800001F, 0xF8000000);
+    DO_MIPS32_i(addi, 23, 0xFFC1, 0xFC00003F, 0xFC000000);
+    DO_MIPS32_i(addi, 24, 0xFF81, 0xFE00007F, 0xFE000000);
+    DO_MIPS32_i(addi, 25, 0xFF01, 0xFF0000FF, 0xFF000000);
+    DO_MIPS32_i(addi, 26, 0xFE01, 0xFF8001FF, 0xFF800000);
+    DO_MIPS32_i(addi, 27, 0xFC01, 0xFFC003FF, 0xFFC00000);
+    DO_MIPS32_i(addi, 28, 0xF801, 0xFFE007FF, 0xFFE00000);
+    DO_MIPS32_i(addi, 29, 0xF001, 0xFFF00FFF, 0xFFF00000);
+    DO_MIPS32_i(addi, 30, 0xE001, 0xFFF81FFF, 0xFFF80000);
+    DO_MIPS32_i(addi, 31, 0xC001, 0xFFFC3FFF, 0xFFFC0000);
+    DO_MIPS32_i(addi, 32, 0x8001, 0xFFFE7FFF, 0xFFFE0000);
+    DO_MIPS32_i(addi, 33, 0x0001, 0xFFFFFFFF, 0x00000000);
+    DO_MIPS32_i(addi, 34, 0x5555, 0x00000000, 0x00005555);
+    DO_MIPS32_i(addi, 35, 0x5555, 0x55555555, 0x5555AAAA);
+    DO_MIPS32_i(addi, 36, 0x5555, 0xAAAAAAAA, 0xAAAAFFFF);
+    DO_MIPS32_i(addi, 37, 0x5555, 0xFFFFFFFF, 0x00005554);
+    DO_MIPS32_i(addi, 38, 0x0000, 0xAAAAAAAA, 0xAAAAAAAA);
+    DO_MIPS32_i(addi, 39, 0x5555, 0xAAAAAAAA, 0xAAAAFFFF);
+    DO_MIPS32_i(addi, 40, 0xAAAA, 0xAAAAAAAA, 0xAAAA5554);
+    DO_MIPS32_i(addi, 41, 0xFFFF, 0xAAAAAAAA, 0xAAAAAAA9);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/addiu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/addiu.c
new file mode 100644
index 0000000000..cdc2ebc932
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/addiu.c
@@ -0,0 +1,90 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_i(addiu, 0, 0x0000, 0x00000000, 0x00000000);
+    DO_MIPS32_i(addiu, 1, 0x0001, 0x00000001, 0x00000002);
+    DO_MIPS32_i(addiu, 2, 0x0003, 0x00000002, 0x00000005);
+    DO_MIPS32_i(addiu, 3, 0x0007, 0x00000004, 0x0000000B);
+    DO_MIPS32_i(addiu, 4, 0x000F, 0x00000008, 0x00000017);
+    DO_MIPS32_i(addiu, 5, 0x001F, 0x00000010, 0x0000002F);
+    DO_MIPS32_i(addiu, 6, 0x003F, 0x00000020, 0x0000005F);
+    DO_MIPS32_i(addiu, 7, 0x007F, 0x00000040, 0x000000BF);
+    DO_MIPS32_i(addiu, 8, 0x00FF, 0x00000080, 0x0000017F);
+    DO_MIPS32_i(addiu, 9, 0x01FF, 0x00000100, 0x000002FF);
+    DO_MIPS32_i(addiu, 10, 0x03FF, 0x00000200, 0x000005FF);
+    DO_MIPS32_i(addiu, 11, 0x07FF, 0x00000400, 0x00000BFF);
+    DO_MIPS32_i(addiu, 12, 0x0FFF, 0x00000800, 0x000017FF);
+    DO_MIPS32_i(addiu, 13, 0x1FFF, 0x00001000, 0x00002FFF);
+    DO_MIPS32_i(addiu, 14, 0x3FFF, 0x00002000, 0x00005FFF);
+    DO_MIPS32_i(addiu, 15, 0x7FFF, 0x00004000, 0x0000BFFF);
+    DO_MIPS32_i(addiu, 16, -1, 0x00008000, 0x00007FFF);
+    DO_MIPS32_i(addiu, 17, 0x0001, 0x00000000, 0x00000001);
+    DO_MIPS32_i(addiu, 18, -1, 0x80000001, 0x80000000);
+    DO_MIPS32_i(addiu, 19, -3, 0xC0000003, 0xC0000000);
+    DO_MIPS32_i(addiu, 20, -7, 0xE0000007, 0xE0000000);
+    DO_MIPS32_i(addiu, 21, -15, 0xF000000F, 0xF0000000);
+    DO_MIPS32_i(addiu, 22, -31, 0xF800001F, 0xF8000000);
+    DO_MIPS32_i(addiu, 23, -63, 0xFC00003F, 0xFC000000);
+    DO_MIPS32_i(addiu, 24, -127, 0xFE00007F, 0xFE000000);
+    DO_MIPS32_i(addiu, 25, -255, 0xFF0000FF, 0xFF000000);
+    DO_MIPS32_i(addiu, 26, -511, 0xFF8001FF, 0xFF800000);
+    DO_MIPS32_i(addiu, 27, -1023, 0xFFC003FF, 0xFFC00000);
+    DO_MIPS32_i(addiu, 28, -2047, 0xFFE007FF, 0xFFE00000);
+    DO_MIPS32_i(addiu, 29, -4095, 0xFFF00FFF, 0xFFF00000);
+    DO_MIPS32_i(addiu, 30, -8191, 0xFFF81FFF, 0xFFF80000);
+    DO_MIPS32_i(addiu, 31, 0xC001, 0xFFFC3FFF, 0xFFFC0000);
+    DO_MIPS32_i(addiu, 32, 0x8001, 0xFFFE7FFF, 0xFFFE0000);
+    DO_MIPS32_i(addiu, 33, 0x0001, 0xFFFFFFFF, 0x00000000);
+    DO_MIPS32_i(addiu, 34, 0x5555, 0x00000000, 0x00005555);
+    DO_MIPS32_i(addiu, 35, 0x5555, 0x55555555, 0x5555AAAA);
+    DO_MIPS32_i(addiu, 36, 0x5555, 0xAAAAAAAA, 0xAAAAFFFF);
+    DO_MIPS32_i(addiu, 37, 0x5555, 0xFFFFFFFF, 0x00005554);
+    DO_MIPS32_i(addiu, 38, 0x0000, 0xAAAAAAAA, 0xAAAAAAAA);
+    DO_MIPS32_i(addiu, 39, 0x5555, 0xAAAAAAAA, 0xAAAAFFFF);
+    DO_MIPS32_i(addiu, 40, 0xAAAA, 0xAAAAAAAA, 0xAAAA5554);
+    DO_MIPS32_i(addiu, 41, -1, 0xAAAAAAAA, 0xAAAAAAA9);
+    DO_MIPS32_i(addiu, 42, 0x0001, 0x7FFFFFFF, 0x80000000);
+    DO_MIPS32_i(addiu, 43, 0x7FFF, 0x7FFFFFFF, 0x80007FFE);
+    DO_MIPS32_i(addiu, 44, -1, 0x80000000, 0x7FFFFFFF);
+    DO_MIPS32_i(addiu, 45, 0x8000, 0x80000000, 0x7FFF8000);
+    DO_MIPS32_i(addiu, 46, 0x555F, 0x7FFFAAAA, 0x80000009);
+    DO_MIPS32_i(addiu, 47, 0xAAAA, 0x7FFF5555, 0x7FFEFFFF);
+    DO_MIPS32_i(addiu, 48, 0x0002, 0x7FFFFFFF, 0x80000001);
+    DO_MIPS32_i(addiu, 49, 0x0004, 0x7FFFFFFF, 0x80000003);
+    DO_MIPS32_i(addiu, 50, 0x0008, 0x7FFFFFFF, 0x80000007);
+    DO_MIPS32_i(addiu, 51, 0x0010, 0x7FFFFFFF, 0x8000000F);
+    DO_MIPS32_i(addiu, 52, 0x0020, 0x7FFFFFFF, 0x8000001F);
+    DO_MIPS32_i(addiu, 53, 0x0040, 0x7FFFFFFF, 0x8000003F);
+    DO_MIPS32_i(addiu, 54, 0x0080, 0x7FFFFFFF, 0x8000007F);
+    DO_MIPS32_i(addiu, 55, 0x0100, 0x7FFFFFFF, 0x800000FF);
+    DO_MIPS32_i(addiu, 56, 0x0200, 0x7FFFFFFF, 0x800001FF);
+    DO_MIPS32_i(addiu, 57, 0x0400, 0x7FFFFFFF, 0x800003FF);
+    DO_MIPS32_i(addiu, 58, 0x0800, 0x7FFFFFFF, 0x800007FF);
+    DO_MIPS32_i(addiu, 59, 0x1000, 0x7FFFFFFF, 0x80000FFF);
+    DO_MIPS32_i(addiu, 60, 0x2000, 0x7FFFFFFF, 0x80001FFF);
+    DO_MIPS32_i(addiu, 61, 0x4000, 0x7FFFFFFF, 0x80003FFF);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/addu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/addu.c
new file mode 100644
index 0000000000..062999edd6
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/addu.c
@@ -0,0 +1,125 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r(addu, 0, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r(addu, 1, 0x00000001, 0x00000001, 0x00000002);
+    DO_MIPS32_r(addu, 2, 0x00000002, 0x00000003, 0x00000005);
+    DO_MIPS32_r(addu, 3, 0x00000004, 0x00000007, 0x0000000B);
+    DO_MIPS32_r(addu, 4, 0x00000008, 0x0000000F, 0x00000017);
+    DO_MIPS32_r(addu, 5, 0x00000010, 0x0000001F, 0x0000002F);
+    DO_MIPS32_r(addu, 6, 0x00000020, 0x0000003F, 0x0000005F);
+    DO_MIPS32_r(addu, 7, 0x00000040, 0x0000007F, 0x000000BF);
+    DO_MIPS32_r(addu, 8, 0x00000080, 0x000000FF, 0x0000017F);
+    DO_MIPS32_r(addu, 9, 0x00000100, 0x000001FF, 0x000002FF);
+    DO_MIPS32_r(addu, 10, 0x00000200, 0x000003FF, 0x000005FF);
+    DO_MIPS32_r(addu, 11, 0x00000400, 0x000007FF, 0x00000BFF);
+    DO_MIPS32_r(addu, 12, 0x00000800, 0x00000FFF, 0x000017FF);
+    DO_MIPS32_r(addu, 13, 0x00001000, 0x00001FFF, 0x00002FFF);
+    DO_MIPS32_r(addu, 14, 0x00002000, 0x00003FFF, 0x00005FFF);
+    DO_MIPS32_r(addu, 15, 0x00004000, 0x00007FFF, 0x0000BFFF);
+    DO_MIPS32_r(addu, 16, 0x00008000, 0x0000FFFF, 0x00017FFF);
+    DO_MIPS32_r(addu, 17, 0x00010000, 0x0001FFFF, 0x0002FFFF);
+    DO_MIPS32_r(addu, 18, 0x00020000, 0x0003FFFF, 0x0005FFFF);
+    DO_MIPS32_r(addu, 19, 0x00040000, 0x0007FFFF, 0x000BFFFF);
+    DO_MIPS32_r(addu, 20, 0x00080000, 0x000FFFFF, 0x0017FFFF);
+    DO_MIPS32_r(addu, 21, 0x00100000, 0x001FFFFF, 0x002FFFFF);
+    DO_MIPS32_r(addu, 22, 0x00200000, 0x003FFFFF, 0x005FFFFF);
+    DO_MIPS32_r(addu, 23, 0x00400000, 0x007FFFFF, 0x00BFFFFF);
+    DO_MIPS32_r(addu, 24, 0x00800000, 0x00FFFFFF, 0x017FFFFF);
+    DO_MIPS32_r(addu, 25, 0x01000000, 0x01FFFFFF, 0x02FFFFFF);
+    DO_MIPS32_r(addu, 26, 0x02000000, 0x03FFFFFF, 0x05FFFFFF);
+    DO_MIPS32_r(addu, 27, 0x04000000, 0x07FFFFFF, 0x0BFFFFFF);
+    DO_MIPS32_r(addu, 28, 0x08000000, 0x0FFFFFFF, 0x17FFFFFF);
+    DO_MIPS32_r(addu, 29, 0x10000000, 0x1FFFFFFF, 0x2FFFFFFF);
+    DO_MIPS32_r(addu, 30, 0x20000000, 0x3FFFFFFF, 0x5FFFFFFF);
+    DO_MIPS32_r(addu, 31, 0x40000000, 0x7FFFFFFF, 0xBFFFFFFF);
+    DO_MIPS32_r(addu, 32, 0x80000000, 0xFFFFFFFF, 0x7FFFFFFF);
+    DO_MIPS32_r(addu, 33, 0x00000000, 0x00000001, 0x00000001);
+    DO_MIPS32_r(addu, 34, 0x80000001, 0xFFFFFFFF, 0x80000000);
+    DO_MIPS32_r(addu, 35, 0xC0000003, 0x7FFFFFFD, 0x40000000);
+    DO_MIPS32_r(addu, 36, 0xE0000007, 0x3FFFFFF9, 0x20000000);
+    DO_MIPS32_r(addu, 37, 0xF000000F, 0x1FFFFFF1, 0x10000000);
+    DO_MIPS32_r(addu, 38, 0xF800001F, 0x0FFFFFE1, 0x08000000);
+    DO_MIPS32_r(addu, 39, 0xFC00003F, 0x07FFFFC1, 0x04000000);
+    DO_MIPS32_r(addu, 40, 0xFE00007F, 0x03FFFF81, 0x02000000);
+    DO_MIPS32_r(addu, 41, 0xFF0000FF, 0x01FFFF01, 0x01000000);
+    DO_MIPS32_r(addu, 42, 0xFF8001FF, 0x00FFFE01, 0x00800000);
+    DO_MIPS32_r(addu, 43, 0xFFC003FF, 0x007FFC01, 0x00400000);
+    DO_MIPS32_r(addu, 44, 0xFFE007FF, 0x003FF801, 0x00200000);
+    DO_MIPS32_r(addu, 45, 0xFFF00FFF, 0x001FF001, 0x00100000);
+    DO_MIPS32_r(addu, 46, 0xFFF81FFF, 0x000FE001, 0x00080000);
+    DO_MIPS32_r(addu, 47, 0xFFFC3FFF, 0x0007C001, 0x00040000);
+    DO_MIPS32_r(addu, 48, 0xFFFE7FFF, 0x00038001, 0x00020000);
+    DO_MIPS32_r(addu, 49, 0xFFFFFFFF, 0x00010001, 0x00010000);
+    DO_MIPS32_r(addu, 50, 0xFFFFFFFF, 0x00018001, 0x00018000);
+    DO_MIPS32_r(addu, 51, 0xFFFE7FFF, 0x00024001, 0x0000C000);
+    DO_MIPS32_r(addu, 52, 0xFFFC3FFF, 0x00042001, 0x00006000);
+    DO_MIPS32_r(addu, 53, 0xFFF81FFF, 0x00081001, 0x00003000);
+    DO_MIPS32_r(addu, 54, 0xFFF00FFF, 0x00100801, 0x00001800);
+    DO_MIPS32_r(addu, 55, 0xFFE007FF, 0x00200401, 0x00000C00);
+    DO_MIPS32_r(addu, 56, 0xFFC003FF, 0x00400201, 0x00000600);
+    DO_MIPS32_r(addu, 57, 0xFF8001FF, 0x00800101, 0x00000300);
+    DO_MIPS32_r(addu, 58, 0xFF0000FF, 0x01000081, 0x00000180);
+    DO_MIPS32_r(addu, 59, 0xFE00007F, 0x02000041, 0x000000C0);
+    DO_MIPS32_r(addu, 60, 0xFC00003F, 0x04000021, 0x00000060);
+    DO_MIPS32_r(addu, 61, 0xF800001F, 0x08000011, 0x00000030);
+    DO_MIPS32_r(addu, 62, 0xF000000F, 0x10000009, 0x00000018);
+    DO_MIPS32_r(addu, 63, 0xE0000007, 0x20000005, 0x0000000C);
+    DO_MIPS32_r(addu, 64, 0xC0000003, 0x40000003, 0x00000006);
+    DO_MIPS32_r(addu, 65, 0x80000001, 0x80000001, 0x00000002);
+    DO_MIPS32_r(addu, 66, 0x00000000, 0x55555555, 0x55555555);
+    DO_MIPS32_r(addu, 67, 0x15555555, 0x55555555, 0x6AAAAAAA);
+    DO_MIPS32_r(addu, 68, 0xAAAAAAAA, 0x55555555, 0xFFFFFFFF);
+    DO_MIPS32_r(addu, 69, 0xFFFFFFFF, 0x55555555, 0x55555554);
+    DO_MIPS32_r(addu, 70, 0xAAAAAAAA, 0x00000000, 0xAAAAAAAA);
+    DO_MIPS32_r(addu, 71, 0xAAAAAAAA, 0x55555555, 0xFFFFFFFF);
+    DO_MIPS32_r(addu, 72, 0xAAAAAAAA, 0x2AAAAAAA, 0xD5555554);
+    DO_MIPS32_r(addu, 73, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAA9);
+    DO_MIPS32_r(addu, 74, 0x7FFFFFFF, 0x00000001, 0x80000000);
+    DO_MIPS32_r(addu, 75, 0x7FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFE);
+    DO_MIPS32_r(addu, 76, 0x80000000, 0xFFFFFFFF, 0x7FFFFFFF);
+    DO_MIPS32_r(addu, 77, 0x80000000, 0x80000000, 0x00000000);
+    DO_MIPS32_r(addu, 78, 0x7FFFFFFF, 0x00000001, 0x80000000);
+    DO_MIPS32_r(addu, 79, 0x7FFFFFFF, 0x00007FFF, 0x80007FFE);
+    DO_MIPS32_r(addu, 80, 0x80000000, 0x0000FFFF, 0x8000FFFF);
+    DO_MIPS32_r(addu, 81, 0x80000000, 0x00008000, 0x80008000);
+    DO_MIPS32_r(addu, 82, 0x7FFFAAAA, 0x0000555F, 0x80000009);
+    DO_MIPS32_r(addu, 83, 0x7FFF5555, 0x0000AAAA, 0x7FFFFFFF);
+    DO_MIPS32_r(addu, 84, 0x7FFFFFFF, 0x00000002, 0x80000001);
+    DO_MIPS32_r(addu, 85, 0x7FFFFFFF, 0x00000004, 0x80000003);
+    DO_MIPS32_r(addu, 86, 0x7FFFFFFF, 0x00000008, 0x80000007);
+    DO_MIPS32_r(addu, 87, 0x7FFFFFFF, 0x00000010, 0x8000000F);
+    DO_MIPS32_r(addu, 88, 0x7FFFFFFF, 0x00000020, 0x8000001F);
+    DO_MIPS32_r(addu, 89, 0x7FFFFFFF, 0x00000040, 0x8000003F);
+    DO_MIPS32_r(addu, 90, 0x7FFFFFFF, 0x00000080, 0x8000007F);
+    DO_MIPS32_r(addu, 91, 0x7FFFFFFF, 0x00000100, 0x800000FF);
+    DO_MIPS32_r(addu, 92, 0x7FFFFFFF, 0x00000200, 0x800001FF);
+    DO_MIPS32_r(addu, 93, 0x7FFFFFFF, 0x00000400, 0x800003FF);
+    DO_MIPS32_r(addu, 94, 0x7FFFFFFF, 0x00000800, 0x800007FF);
+    DO_MIPS32_r(addu, 95, 0x7FFFFFFF, 0x00001000, 0x80000FFF);
+    DO_MIPS32_r(addu, 96, 0x7FFFFFFF, 0x00002000, 0x80001FFF);
+    DO_MIPS32_r(addu, 97, 0x7FFFFFFF, 0x00004000, 0x80003FFF);
+    DO_MIPS32_r(addu, 98, 0x7FFFFFFF, 0x00001000, 0x80003FFF);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/div.c b/tests/tcg/mips/user/isa/mips32/arithmatic/div.c
new file mode 100644
index 0000000000..5eafca326e
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/div.c
@@ -0,0 +1,81 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r2_s(div, 0, 0, 0, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(div, 1, 0, 0, 0x80000001, 0x00000001, 0x00000000, 0x80000001);
+    DO_MIPS32_r2_s(div, 2, 0, 0, 0x40000002, 0x00000003, 0x00000000, 0x15555556);
+    DO_MIPS32_r2_s(div, 3, 0, 0, 0x20000004, 0x00000007, 0x00000001, 0x04924925);
+    DO_MIPS32_r2_s(div, 4, 0, 0, 0x10000008, 0x0000000F, 0x00000009, 0x01111111);
+    DO_MIPS32_r2_s(div, 5, 0, 0, 0x88000010, 0x0000001F, 0xFFFFFFF3, 0xFC210843);
+    DO_MIPS32_r2_s(div, 6, 0, 0, 0x44000020, 0x0000003F, 0x00000025, 0x01145145);
+    DO_MIPS32_r2_s(div, 7, 0, 0, 0x22000040, 0x0000007F, 0x00000052, 0x00448912);
+    DO_MIPS32_r2_s(div, 8, 0, 0, 0x11000080, 0x000000FF, 0x00000091, 0x00111111);
+    DO_MIPS32_r2_s(div, 9, 0, 0, 0x80800100, 0x000001FF, 0xFFFFFF11, 0xFFC02011);
+    DO_MIPS32_r2_s(div, 10, 0, 0, 0x40400200, 0x000003FF, 0x00000205, 0x00101405);
+    DO_MIPS32_r2_s(div, 11, 0, 0, 0x20200400, 0x000007FF, 0x00000081, 0x00040481);
+    DO_MIPS32_r2_s(div, 12, 0, 0, 0x10100800, 0x00000FFF, 0x00000910, 0x00010110);
+    DO_MIPS32_r2_s(div, 13, 0, 0, 0x80081000, 0x00001FFF, 0xFFFFF021, 0xFFFC0021);
+    DO_MIPS32_r2_s(div, 14, 0, 0, 0x40042000, 0x00003FFF, 0x00002014, 0x00010014);
+    DO_MIPS32_r2_s(div, 15, 0, 0, 0x20024000, 0x00007FFF, 0x00000005, 0x00004005);
+    DO_MIPS32_r2_s(div, 16, 0, 0, 0x10018000, 0x0000FFFF, 0x00009001, 0x00001001);
+    DO_MIPS32_r2_s(div, 17, 0, 0, 0x80018000, 0x0001FFFF, 0xFFFF4001, 0xFFFFC001);
+    DO_MIPS32_r2_s(div, 18, 0, 0, 0x40024000, 0x0003FFFF, 0x00025000, 0x00001000);
+    DO_MIPS32_r2_s(div, 19, 0, 0, 0x20042000, 0x0007FFFF, 0x00042400, 0x00000400);
+    DO_MIPS32_r2_s(div, 20, 0, 0, 0x10081000, 0x000FFFFF, 0x00081100, 0x00000100);
+    DO_MIPS32_r2_s(div, 21, 0, 0, 0x80100800, 0x001FFFFF, 0xFFF00401, 0xFFFFFC01);
+    DO_MIPS32_r2_s(div, 22, 0, 0, 0x40200400, 0x003FFFFF, 0x00200500, 0x00000100);
+    DO_MIPS32_r2_s(div, 23, 0, 0, 0x20400200, 0x007FFFFF, 0x00400240, 0x00000040);
+    DO_MIPS32_r2_s(div, 24, 0, 0, 0x10800100, 0x00FFFFFF, 0x00800110, 0x00000010);
+    DO_MIPS32_r2_s(div, 25, 0, 0, 0x81000080, 0x01FFFFFF, 0xFF000041, 0xFFFFFFC1);
+    DO_MIPS32_r2_s(div, 26, 0, 0, 0x42000040, 0x03FFFFFF, 0x02000050, 0x00000010);
+    DO_MIPS32_r2_s(div, 27, 0, 0, 0x24000020, 0x07FFFFFF, 0x04000024, 0x00000004);
+    DO_MIPS32_r2_s(div, 28, 0, 0, 0x18000010, 0x0FFFFFFF, 0x08000011, 0x00000001);
+    DO_MIPS32_r2_s(div, 29, 0, 0, 0x90000008, 0x1FFFFFFF, 0xF0000005, 0xFFFFFFFD);
+    DO_MIPS32_r2_s(div, 30, 0, 0, 0x60000004, 0x3FFFFFFF, 0x20000005, 0x00000001);
+    DO_MIPS32_r2_s(div, 31, 0, 0, 0x60000002, 0x7FFFFFFF, 0x60000002, 0x00000000);
+    DO_MIPS32_r2_s(div, 32, 0, 0, 0x90000001, 0xFFFFFFFF, 0x00000000, 0x6FFFFFFF);
+    DO_MIPS32_r2_s(div, 33, 0, 0, 0x00000000, 0x55555555, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(div, 34, 0, 0, 0x55555555, 0x55555555, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(div, 35, 0, 0, 0xAAAAAAAA, 0x55555555, 0xFFFFFFFF, 0xFFFFFFFF);
+    DO_MIPS32_r2_s(div, 36, 0, 0, 0xFFFFFFFF, 0x55555555, 0xFFFFFFFF, 0x00000000);
+    DO_MIPS32_r2_s(div, 37, 0, 0, 0xAAAAAAAA, 0x00000001, 0x00000000, 0xAAAAAAAA);
+    DO_MIPS32_r2_s(div, 38, 0, 0, 0xAAAAAAAA, 0x55555555, 0xFFFFFFFF, 0xFFFFFFFF);
+    DO_MIPS32_r2_s(div, 39, 0, 0, 0xAAAAAAAA, 0xAAAAAAAA, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(div, 40, 0, 0, 0xAAAAAAAA, 0xFFFFFFFF, 0x00000000, 0x55555556);
+    DO_MIPS32_r2_s(div, 41, 0, 0, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(div, 42, 0, 0, 0x7FFFFFFF, 0x80000000, 0x7FFFFFFF, 0x00000000);
+    DO_MIPS32_r2_s(div, 43, 0, 0, 0x7FFFFFFF, 0xFFFFFFFF, 0x00000000, 0x80000001);
+    DO_MIPS32_r2_s(div, 44, 0, 0, 0x80000000, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+    DO_MIPS32_r2_s(div, 45, 0, 0, 0x80000000, 0x80000000, 0x00000000, 0x00000001);
+#if 0
+    /* Disabled until we find a way to disable assembler trap */
+    DO_MIPS32_r2_s(div, 46, 0, 0, 0x80000000, 0xFFFFFFFF, 0x00000000, 0x80000000);
+#endif
+    DO_MIPS32_r2_s(div, 47, 0, 0, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0x00000000);
+    DO_MIPS32_r2_s(div, 48, 0, 0, 0xFFFFFFFF, 0x80000000, 0xFFFFFFFF, 0x00000000);
+    DO_MIPS32_r2_s(div, 49, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000001);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/divu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/divu.c
new file mode 100644
index 0000000000..172e8af693
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/divu.c
@@ -0,0 +1,78 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r2_s(divu, 0, 0, 0, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(divu, 1, 0, 0, 0x80000001, 0x00000001, 0x00000000, 0x80000001);
+    DO_MIPS32_r2_s(divu, 2, 0, 0, 0x40000002, 0x00000003, 0x00000000, 0x15555556);
+    DO_MIPS32_r2_s(divu, 3, 0, 0, 0x20000004, 0x00000007, 0x00000001, 0x04924925);
+    DO_MIPS32_r2_s(divu, 4, 0, 0, 0x10000008, 0x0000000F, 0x00000009, 0x01111111);
+    DO_MIPS32_r2_s(divu, 5, 0, 0, 0x88000010, 0x0000001F, 0x00000016, 0x046318C6);
+    DO_MIPS32_r2_s(divu, 6, 0, 0, 0x44000020, 0x0000003F, 0x00000025, 0x01145145);
+    DO_MIPS32_r2_s(divu, 7, 0, 0, 0x22000040, 0x0000007F, 0x00000052, 0x00448912);
+    DO_MIPS32_r2_s(divu, 8, 0, 0, 0x11000080, 0x000000FF, 0x00000091, 0x00111111);
+    DO_MIPS32_r2_s(divu, 9, 0, 0, 0x80800100, 0x000001FF, 0x00000130, 0x00406030);
+    DO_MIPS32_r2_s(divu, 10, 0, 0, 0x40400200, 0x000003FF, 0x00000205, 0x00101405);
+    DO_MIPS32_r2_s(divu, 11, 0, 0, 0x20200400, 0x000007FF, 0x00000081, 0x00040481);
+    DO_MIPS32_r2_s(divu, 12, 0, 0, 0x10100800, 0x00000FFF, 0x00000910, 0x00010110);
+    DO_MIPS32_r2_s(divu, 13, 0, 0, 0x80081000, 0x00001FFF, 0x00001060, 0x00040060);
+    DO_MIPS32_r2_s(divu, 14, 0, 0, 0x40042000, 0x00003FFF, 0x00002014, 0x00010014);
+    DO_MIPS32_r2_s(divu, 15, 0, 0, 0x20024000, 0x00007FFF, 0x00000005, 0x00004005);
+    DO_MIPS32_r2_s(divu, 16, 0, 0, 0x10018000, 0x0000FFFF, 0x00009001, 0x00001001);
+    DO_MIPS32_r2_s(divu, 17, 0, 0, 0x80018000, 0x0001FFFF, 0x0001C000, 0x00004000);
+    DO_MIPS32_r2_s(divu, 18, 0, 0, 0x40024000, 0x0003FFFF, 0x00025000, 0x00001000);
+    DO_MIPS32_r2_s(divu, 19, 0, 0, 0x20042000, 0x0007FFFF, 0x00042400, 0x00000400);
+    DO_MIPS32_r2_s(divu, 20, 0, 0, 0x10081000, 0x000FFFFF, 0x00081100, 0x00000100);
+    DO_MIPS32_r2_s(divu, 21, 0, 0, 0x80100800, 0x001FFFFF, 0x00100C00, 0x00000400);
+    DO_MIPS32_r2_s(divu, 22, 0, 0, 0x40200400, 0x003FFFFF, 0x00200500, 0x00000100);
+    DO_MIPS32_r2_s(divu, 23, 0, 0, 0x20400200, 0x007FFFFF, 0x00400240, 0x00000040);
+    DO_MIPS32_r2_s(divu, 24, 0, 0, 0x10800100, 0x00FFFFFF, 0x00800110, 0x00000010);
+    DO_MIPS32_r2_s(divu, 25, 0, 0, 0x81000080, 0x01FFFFFF, 0x010000C0, 0x00000040);
+    DO_MIPS32_r2_s(divu, 26, 0, 0, 0x42000040, 0x03FFFFFF, 0x02000050, 0x00000010);
+    DO_MIPS32_r2_s(divu, 27, 0, 0, 0x24000020, 0x07FFFFFF, 0x04000024, 0x00000004);
+    DO_MIPS32_r2_s(divu, 28, 0, 0, 0x18000010, 0x0FFFFFFF, 0x08000011, 0x00000001);
+    DO_MIPS32_r2_s(divu, 29, 0, 0, 0x90000008, 0x1FFFFFFF, 0x1000000C, 0x00000004);
+    DO_MIPS32_r2_s(divu, 30, 0, 0, 0x60000004, 0x3FFFFFFF, 0x20000005, 0x00000001);
+    DO_MIPS32_r2_s(divu, 31, 0, 0, 0x60000002, 0x7FFFFFFF, 0x60000002, 0x00000000);
+    DO_MIPS32_r2_s(divu, 32, 0, 0, 0x90000001, 0xFFFFFFFF, 0x90000001, 0x00000000);
+    DO_MIPS32_r2_s(divu, 33, 0, 0, 0x00000000, 0x55555555, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(divu, 34, 0, 0, 0x55555555, 0x55555555, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(divu, 35, 0, 0, 0xAAAAAAAA, 0x55555555, 0x00000000, 0x00000002);
+    DO_MIPS32_r2_s(divu, 36, 0, 0, 0xFFFFFFFF, 0x55555555, 0x00000000, 0x00000003);
+    DO_MIPS32_r2_s(divu, 37, 0, 0, 0xAAAAAAAA, 0x00000001, 0x00000000, 0xAAAAAAAA);
+    DO_MIPS32_r2_s(divu, 38, 0, 0, 0xAAAAAAAA, 0x55555555, 0x00000000, 0x00000002);
+    DO_MIPS32_r2_s(divu, 39, 0, 0, 0xAAAAAAAA, 0xAAAAAAAA, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(divu, 40, 0, 0, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA, 0x00000000);
+    DO_MIPS32_r2_s(divu, 41, 0, 0, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(divu, 42, 0, 0, 0x7FFFFFFF, 0x80000000, 0x7FFFFFFF, 0x00000000);
+    DO_MIPS32_r2_s(divu, 43, 0, 0, 0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0x00000000);
+    DO_MIPS32_r2_s(divu, 44, 0, 0, 0x80000000, 0x7FFFFFFF, 0x00000001, 0x00000001);
+    DO_MIPS32_r2_s(divu, 45, 0, 0, 0x80000000, 0x80000000, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(divu, 46, 0, 0, 0x80000000, 0xFFFFFFFF, 0x80000000, 0x00000000);
+    DO_MIPS32_r2_s(divu, 47, 0, 0, 0xFFFFFFFF, 0x7FFFFFFF, 0x00000001, 0x00000002);
+    DO_MIPS32_r2_s(divu, 48, 0, 0, 0xFFFFFFFF, 0x80000000, 0x7FFFFFFF, 0x00000001);
+    DO_MIPS32_r2_s(divu, 49, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000001);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/madd.c b/tests/tcg/mips/user/isa/mips32/arithmatic/madd.c
new file mode 100644
index 0000000000..7f047f76d9
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/madd.c
@@ -0,0 +1,79 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r2_s(divu, 0, 0, 0, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(madd, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(madd, 1, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(madd, 2, 0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000000, 0x00000007);
+    DO_MIPS32_r2_s(madd, 3, 0x00000000, 0x00000007, 0x00000004, 0x00000007, 0x00000000, 0x00000023);
+    DO_MIPS32_r2_s(madd, 4, 0x00000000, 0x00000023, 0x00000008, 0x0000000F, 0x00000000, 0x0000009b);
+    DO_MIPS32_r2_s(madd, 5, 0x00000000, 0x0000009b, 0x00000010, 0x0000001F, 0x00000000, 0x0000028b);
+    DO_MIPS32_r2_s(madd, 6, 0x00000000, 0x0000028b, 0x00000020, 0x0000003F, 0x00000000, 0x00000a6b);
+    DO_MIPS32_r2_s(madd, 7, 0x00000000, 0x00000a6b, 0x00000040, 0x0000007F, 0x00000000, 0x00002a2b);
+    DO_MIPS32_r2_s(madd, 8, 0x00000000, 0x00002a2b, 0x00000080, 0x000000FF, 0x00000000, 0x0000a9ab);
+    DO_MIPS32_r2_s(madd, 9, 0x00000000, 0x0000a9ab, 0x00000100, 0x000001FF, 0x00000000, 0x0002a8ab);
+    DO_MIPS32_r2_s(madd, 10, 0x00000000, 0x0002a8ab, 0x00000200, 0x000003FF, 0x00000000, 0x000aa6ab);
+    DO_MIPS32_r2_s(madd, 11, 0x00000000, 0x000aa6ab, 0x00000400, 0x000007FF, 0x00000000, 0x002aa2ab);
+    DO_MIPS32_r2_s(madd, 12, 0x00000000, 0x002aa2ab, 0x00000800, 0x00000FFF, 0x00000000, 0x00aa9aab);
+    DO_MIPS32_r2_s(madd, 13, 0x00000000, 0x00aa9aab, 0x00001000, 0x00001FFF, 0x00000000, 0x02aa8aab);
+    DO_MIPS32_r2_s(madd, 14, 0x00000000, 0x02aa8aab, 0x00002000, 0x00003FFF, 0x00000000, 0x0aaa6aab);
+    DO_MIPS32_r2_s(madd, 15, 0x00000000, 0x0aaa6aab, 0x00004000, 0x00007FFF, 0x00000000, 0x2aaa2aab);
+    DO_MIPS32_r2_s(madd, 16, 0x00000000, 0x2aaa2aab, 0x00008000, 0x0000FFFF, 0x00000000, 0xaaa9aaab);
+    DO_MIPS32_r2_s(madd, 17, 0x00000000, 0xaaa9aaab, 0x00010000, 0x0001FFFF, 0x00000002, 0xaaa8aaab);
+    DO_MIPS32_r2_s(madd, 18, 0x00000002, 0xaaa8aaab, 0x00020000, 0x0003FFFF, 0x0000000a, 0xAAA6AAAB);
+    DO_MIPS32_r2_s(madd, 19, 0x0000000a, 0xAAA6AAAB, 0x00040000, 0x0007FFFF, 0x0000002A, 0xAAA2AAAB);
+    DO_MIPS32_r2_s(madd, 20, 0x0000002A, 0xAAA2AAAB, 0x00080000, 0x000FFFFF, 0x000000AA, 0xAA9AAAAB);
+    DO_MIPS32_r2_s(madd, 21, 0x000000AA, 0xAA9AAAAB, 0x00100000, 0x001FFFFF, 0x000002AA, 0xAA8AAAAB);
+    DO_MIPS32_r2_s(madd, 22, 0x000002AA, 0xAA8AAAAB, 0x00200000, 0x003FFFFF, 0x00000AAA, 0xAA6AAAAB);
+    DO_MIPS32_r2_s(madd, 23, 0x00000AAA, 0xAA6AAAAB, 0x00400000, 0x007FFFFF, 0x00002AAA, 0xAA2AAAAB);
+    DO_MIPS32_r2_s(madd, 24, 0x00002AAA, 0xAA2AAAAB, 0x00800000, 0x00FFFFFF, 0x0000AAAA, 0xA9AAAAAB);
+    DO_MIPS32_r2_s(madd, 25, 0x0000AAAA, 0xA9AAAAAB, 0x01000000, 0x01FFFFFF, 0x0002AAAA, 0xA8AAAAAB);
+    DO_MIPS32_r2_s(madd, 26, 0x0002AAAA, 0xA8AAAAAB, 0x02000000, 0x03FFFFFF, 0x000AAAAA, 0xA6AAAAAB);
+    DO_MIPS32_r2_s(madd, 27, 0x000AAAAA, 0xA6AAAAAB, 0x04000000, 0x07FFFFFF, 0x002AAAAA, 0xA2AAAAAB);
+    DO_MIPS32_r2_s(madd, 28, 0x002AAAAA, 0xA2AAAAAB, 0x08000000, 0x0FFFFFFF, 0x00AAAAAA, 0x9AAAAAAB);
+    DO_MIPS32_r2_s(madd, 29, 0x00AAAAAA, 0x9AAAAAAB, 0x10000000, 0x1FFFFFFF, 0x02AAAAAA, 0x8AAAAAAB);
+    DO_MIPS32_r2_s(madd, 30, 0x02AAAAAA, 0x8AAAAAAB, 0x20000000, 0x3FFFFFFF, 0x0AAAAAAA, 0x6AAAAAAB);
+    DO_MIPS32_r2_s(madd, 31, 0x0AAAAAAA, 0x6AAAAAAB, 0x40000000, 0x7FFFFFFF, 0x2AAAAAAA, 0x2AAAAAAB);
+    DO_MIPS32_r2_s(madd, 32, 0x2AAAAAAA, 0x2AAAAAAB, 0x80000000, 0xFFFFFFFF, 0x2AAAAAAA, 0xAAAAAAAB);
+    DO_MIPS32_r2_s(madd, 33, 0x00000000, 0x00000000, 0x00000000, 0x55555555, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(madd, 34, 0x00000000, 0x00000000, 0x55555555, 0x55555555, 0x1C71C71C, 0x38E38E39);
+    DO_MIPS32_r2_s(madd, 35, 0x1C71C71C, 0x38E38E39, 0xAAAAAAAA, 0x55555555, 0xFFFFFFFF, 0xAAAAAAAB);
+    DO_MIPS32_r2_s(madd, 36, 0xFFFFFFFF, 0xAAAAAAAB, 0xFFFFFFFF, 0x55555555, 0xFFFFFFFF, 0x55555556);
+    DO_MIPS32_r2_s(madd, 37, 0xFFFFFFFF, 0x55555556, 0xAAAAAAAA, 0x00000000, 0xFFFFFFFF, 0x55555556);
+    DO_MIPS32_r2_s(madd, 38, 0xFFFFFFFF, 0x55555556, 0xAAAAAAAA, 0x55555555, 0xe38e38e2, 0xc71c71c8);
+    DO_MIPS32_r2_s(madd, 39, 0xe38e38e2, 0xc71c71c8, 0xAAAAAAAA, 0xAAAAAAAA, 0xffffffff, 0xaaaaaaac);
+    DO_MIPS32_r2_s(madd, 40, 0xffffffff, 0xaaaaaaac, 0xAAAAAAAA, 0xFFFFFFFF, 0x00000000, 0x00000002);
+    DO_MIPS32_r2_s(madd, 41, 0x00000000, 0x00000000, 0x7FFFFFFF, 0x7FFFFFFF, 0x3FFFFFFF, 0x00000001);
+    DO_MIPS32_r2_s(madd, 42, 0x3FFFFFFF, 0x00000001, 0x7FFFFFFF, 0x80000000, 0xffffffff, 0x80000001);
+    DO_MIPS32_r2_s(madd, 43, 0xffffffff, 0x80000001, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000002);
+    DO_MIPS32_r2_s(madd, 44, 0xFFFFFFFF, 0x00000002, 0x80000000, 0x7FFFFFFF, 0xbfffffff, 0x80000002);
+    DO_MIPS32_r2_s(madd, 45, 0xbfffffff, 0x80000002, 0x80000000, 0x80000000, 0xffffffff, 0x80000002);
+    DO_MIPS32_r2_s(madd, 46, 0xffffffff, 0x80000002, 0x80000000, 0xFFFFFFFF, 0x00000000, 0x00000002);
+    DO_MIPS32_r2_s(madd, 47, 0x00000000, 0x00000002, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0x80000003);
+    DO_MIPS32_r2_s(madd, 48, 0xFFFFFFFF, 0x80000003, 0xFFFFFFFF, 0x80000000, 0x00000000, 0x00000003);
+    DO_MIPS32_r2_s(madd, 49, 0x00000000, 0x00000003, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000004);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/maddu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/maddu.c
new file mode 100644
index 0000000000..8073841b33
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/maddu.c
@@ -0,0 +1,78 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r2_s(maddu, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(maddu, 1, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(maddu, 2, 0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000000, 0x00000007);
+    DO_MIPS32_r2_s(maddu, 3, 0x00000000, 0x00000007, 0x00000004, 0x00000007, 0x00000000, 0x00000023);
+    DO_MIPS32_r2_s(maddu, 4, 0x00000000, 0x00000023, 0x00000008, 0x0000000F, 0x00000000, 0x0000009b);
+    DO_MIPS32_r2_s(maddu, 5, 0x00000000, 0x0000009b, 0x00000010, 0x0000001F, 0x00000000, 0x0000028b);
+    DO_MIPS32_r2_s(maddu, 6, 0x00000000, 0x0000028b, 0x00000020, 0x0000003F, 0x00000000, 0x00000a6b);
+    DO_MIPS32_r2_s(maddu, 7, 0x00000000, 0x00000a6b, 0x00000040, 0x0000007F, 0x00000000, 0x00002a2b);
+    DO_MIPS32_r2_s(maddu, 8, 0x00000000, 0x00002a2b, 0x00000080, 0x000000FF, 0x00000000, 0x0000a9ab);
+    DO_MIPS32_r2_s(maddu, 9, 0x00000000, 0x0000a9ab, 0x00000100, 0x000001FF, 0x00000000, 0x0002a8ab);
+    DO_MIPS32_r2_s(maddu, 10, 0x00000000, 0x0002a8ab, 0x00000200, 0x000003FF, 0x00000000, 0x000aa6ab);
+    DO_MIPS32_r2_s(maddu, 11, 0x00000000, 0x000aa6ab, 0x00000400, 0x000007FF, 0x00000000, 0x002aa2ab);
+    DO_MIPS32_r2_s(maddu, 12, 0x00000000, 0x002aa2ab, 0x00000800, 0x00000FFF, 0x00000000, 0x00aa9aab);
+    DO_MIPS32_r2_s(maddu, 13, 0x00000000, 0x00aa9aab, 0x00001000, 0x00001FFF, 0x00000000, 0x02aa8aab);
+    DO_MIPS32_r2_s(maddu, 14, 0x00000000, 0x02aa8aab, 0x00002000, 0x00003FFF, 0x00000000, 0x0aaa6aab);
+    DO_MIPS32_r2_s(maddu, 15, 0x00000000, 0x0aaa6aab, 0x00004000, 0x00007FFF, 0x00000000, 0x2aaa2aab);
+    DO_MIPS32_r2_s(maddu, 16, 0x00000000, 0x2aaa2aab, 0x00008000, 0x0000FFFF, 0x00000000, 0xaaa9aaab);
+    DO_MIPS32_r2_s(maddu, 17, 0x00000000, 0xaaa9aaab, 0x00010000, 0x0001FFFF, 0x00000002, 0xaaa8aaab);
+    DO_MIPS32_r2_s(maddu, 18, 0x00000002, 0xaaa8aaab, 0x00020000, 0x0003FFFF, 0x0000000a, 0xAAA6AAAB);
+    DO_MIPS32_r2_s(maddu, 19, 0x0000000a, 0xAAA6AAAB, 0x00040000, 0x0007FFFF, 0x0000002A, 0xAAA2AAAB);
+    DO_MIPS32_r2_s(maddu, 20, 0x0000002A, 0xAAA2AAAB, 0x00080000, 0x000FFFFF, 0x000000AA, 0xAA9AAAAB);
+    DO_MIPS32_r2_s(maddu, 21, 0x000000AA, 0xAA9AAAAB, 0x00100000, 0x001FFFFF, 0x000002AA, 0xAA8AAAAB);
+    DO_MIPS32_r2_s(maddu, 22, 0x000002AA, 0xAA8AAAAB, 0x00200000, 0x003FFFFF, 0x00000AAA, 0xAA6AAAAB);
+    DO_MIPS32_r2_s(maddu, 23, 0x00000AAA, 0xAA6AAAAB, 0x00400000, 0x007FFFFF, 0x00002AAA, 0xAA2AAAAB);
+    DO_MIPS32_r2_s(maddu, 24, 0x00002AAA, 0xAA2AAAAB, 0x00800000, 0x00FFFFFF, 0x0000AAAA, 0xA9AAAAAB);
+    DO_MIPS32_r2_s(maddu, 25, 0x0000AAAA, 0xA9AAAAAB, 0x01000000, 0x01FFFFFF, 0x0002AAAA, 0xA8AAAAAB);
+    DO_MIPS32_r2_s(maddu, 26, 0x0002AAAA, 0xA8AAAAAB, 0x02000000, 0x03FFFFFF, 0x000AAAAA, 0xA6AAAAAB);
+    DO_MIPS32_r2_s(maddu, 27, 0x000AAAAA, 0xA6AAAAAB, 0x04000000, 0x07FFFFFF, 0x002AAAAA, 0xA2AAAAAB);
+    DO_MIPS32_r2_s(maddu, 28, 0x002AAAAA, 0xA2AAAAAB, 0x08000000, 0x0FFFFFFF, 0x00AAAAAA, 0x9AAAAAAB);
+    DO_MIPS32_r2_s(maddu, 29, 0x00AAAAAA, 0x9AAAAAAB, 0x10000000, 0x1FFFFFFF, 0x02AAAAAA, 0x8AAAAAAB);
+    DO_MIPS32_r2_s(maddu, 30, 0x02AAAAAA, 0x8AAAAAAB, 0x20000000, 0x3FFFFFFF, 0x0AAAAAAA, 0x6AAAAAAB);
+    DO_MIPS32_r2_s(maddu, 31, 0x0AAAAAAA, 0x6AAAAAAB, 0x40000000, 0x7FFFFFFF, 0x2AAAAAAA, 0x2AAAAAAB);
+    DO_MIPS32_r2_s(maddu, 32, 0x2AAAAAAA, 0x2AAAAAAB, 0x80000000, 0xFFFFFFFF, 0xAAAAAAA9, 0xAAAAAAAB);
+    DO_MIPS32_r2_s(maddu, 33, 0x00000000, 0x00000000, 0x00000000, 0x55555555, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(maddu, 34, 0x00000000, 0x00000000, 0x55555555, 0x55555555, 0x1C71C71C, 0x38E38E39);
+    DO_MIPS32_r2_s(maddu, 35, 0x1C71C71C, 0x38E38E39, 0xAAAAAAAA, 0x55555555, 0x55555554, 0xaaaaaaab);
+    DO_MIPS32_r2_s(maddu, 36, 0x55555554, 0xaaaaaaab, 0xFFFFFFFF, 0x55555555, 0xaaaaaaa9, 0x55555556);
+    DO_MIPS32_r2_s(maddu, 37, 0xaaaaaaa9, 0x55555556, 0xAAAAAAAA, 0x00000000, 0xaaaaaaa9, 0x55555556);
+    DO_MIPS32_r2_s(maddu, 38, 0xaaaaaaa9, 0x55555556, 0xAAAAAAAA, 0x55555555, 0xe38e38e1, 0xc71c71c8);
+    DO_MIPS32_r2_s(maddu, 39, 0xe38e38e1, 0xc71c71c8, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555552, 0xaaaaaaac);
+    DO_MIPS32_r2_s(maddu, 40, 0x55555552, 0xaaaaaaac, 0xAAAAAAAA, 0xFFFFFFFF, 0xfffffffc, 0x00000002);
+    DO_MIPS32_r2_s(maddu, 41, 0x00000000, 0x00000000, 0x7FFFFFFF, 0x7FFFFFFF, 0x3fffffff, 0x00000001);
+    DO_MIPS32_r2_s(maddu, 42, 0x3fffffff, 0x00000001, 0x7FFFFFFF, 0x80000000, 0x7ffffffe, 0x80000001);
+    DO_MIPS32_r2_s(maddu, 43, 0x7ffffffe, 0x80000001, 0x7FFFFFFF, 0xFFFFFFFF, 0xfffffffd, 0x00000002);
+    DO_MIPS32_r2_s(maddu, 44, 0xfffffffd, 0x00000002, 0x80000000, 0x7FFFFFFF, 0x3ffffffc, 0x80000002);
+    DO_MIPS32_r2_s(maddu, 45, 0x3ffffffc, 0x80000002, 0x80000000, 0x80000000, 0x7ffffffc, 0x80000002);
+    DO_MIPS32_r2_s(maddu, 46, 0x7ffffffc, 0x80000002, 0x80000000, 0xFFFFFFFF, 0xfffffffc, 0x00000002);
+    DO_MIPS32_r2_s(maddu, 47, 0xfffffffc, 0x00000002, 0xFFFFFFFF, 0x7FFFFFFF, 0x7ffffffa, 0x80000003);
+    DO_MIPS32_r2_s(maddu, 48, 0x7ffffffa, 0x80000003, 0xFFFFFFFF, 0x80000000, 0xfffffffa, 0x00000003);
+    DO_MIPS32_r2_s(maddu, 49, 0xfffffffa, 0x00000003, 0xFFFFFFFF, 0xFFFFFFFF, 0xfffffff8, 0x00000004);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/msub.c b/tests/tcg/mips/user/isa/mips32/arithmatic/msub.c
new file mode 100644
index 0000000000..36387cbdf8
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/msub.c
@@ -0,0 +1,78 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r2_s(msub, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(msub, 1, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0xffffffff, 0xffffffff);
+    DO_MIPS32_r2_s(msub, 2, 0xffffffff, 0xffffffff, 0x00000002, 0x00000003, 0xffffffff, 0xfffffff9);
+    DO_MIPS32_r2_s(msub, 3, 0xffffffff, 0xfffffff9, 0x00000004, 0x00000007, 0xffffffff, 0xffffffdd);
+    DO_MIPS32_r2_s(msub, 4, 0xffffffff, 0xffffffdd, 0x00000008, 0x0000000F, 0xffffffff, 0xffffff65);
+    DO_MIPS32_r2_s(msub, 5, 0xffffffff, 0xffffff65, 0x00000010, 0x0000001F, 0xffffffff, 0xfffffd75);
+    DO_MIPS32_r2_s(msub, 6, 0xffffffff, 0xfffffd75, 0x00000020, 0x0000003F, 0xffffffff, 0xfffff595);
+    DO_MIPS32_r2_s(msub, 7, 0xffffffff, 0xfffff595, 0x00000040, 0x0000007F, 0xffffffff, 0xffffd5d5);
+    DO_MIPS32_r2_s(msub, 8, 0xffffffff, 0xffffd5d5, 0x00000080, 0x000000FF, 0xffffffff, 0xffff5655);
+    DO_MIPS32_r2_s(msub, 9, 0xffffffff, 0xffff5655, 0x00000100, 0x000001FF, 0xffffffff, 0xfffd5755);
+    DO_MIPS32_r2_s(msub, 10, 0xffffffff, 0xfffd5755, 0x00000200, 0x000003FF, 0xffffffff, 0xfff55955);
+    DO_MIPS32_r2_s(msub, 11, 0xffffffff, 0xfff55955, 0x00000400, 0x000007FF, 0xffffffff, 0xffd55d55);
+    DO_MIPS32_r2_s(msub, 12, 0xffffffff, 0xffd55d55, 0x00000800, 0x00000FFF, 0xffffffff, 0xff556555);
+    DO_MIPS32_r2_s(msub, 13, 0xffffffff, 0xff556555, 0x00001000, 0x00001FFF, 0xffffffff, 0xfd557555);
+    DO_MIPS32_r2_s(msub, 14, 0xffffffff, 0xfd557555, 0x00002000, 0x00003FFF, 0xffffffff, 0xf5559555);
+    DO_MIPS32_r2_s(msub, 15, 0xffffffff, 0xf5559555, 0x00004000, 0x00007FFF, 0xffffffff, 0xd555d555);
+    DO_MIPS32_r2_s(msub, 16, 0xffffffff, 0xd555d555, 0x00008000, 0x0000FFFF, 0xffffffff, 0x55565555);
+    DO_MIPS32_r2_s(msub, 17, 0xffffffff, 0x55565555, 0x00010000, 0x0001FFFF, 0xfffffffd, 0x55575555);
+    DO_MIPS32_r2_s(msub, 18, 0xfffffffd, 0x55575555, 0x00020000, 0x0003FFFF, 0xfffffff5, 0x55595555);
+    DO_MIPS32_r2_s(msub, 19, 0xfffffff5, 0x55595555, 0x00040000, 0x0007FFFF, 0xffffffd5, 0x555d5555);
+    DO_MIPS32_r2_s(msub, 20, 0xffffffd5, 0x555d5555, 0x00080000, 0x000FFFFF, 0xffffff55, 0x55655555);
+    DO_MIPS32_r2_s(msub, 21, 0xffffff55, 0x55655555, 0x00100000, 0x001FFFFF, 0xfffffd55, 0x55755555);
+    DO_MIPS32_r2_s(msub, 22, 0xfffffd55, 0x55755555, 0x00200000, 0x003FFFFF, 0xfffff555, 0x55955555);
+    DO_MIPS32_r2_s(msub, 23, 0xfffff555, 0x55955555, 0x00400000, 0x007FFFFF, 0xffffd555, 0x55d55555);
+    DO_MIPS32_r2_s(msub, 24, 0xffffd555, 0x55d55555, 0x00800000, 0x00FFFFFF, 0xffff5555, 0x56555555);
+    DO_MIPS32_r2_s(msub, 25, 0xffff5555, 0x56555555, 0x01000000, 0x01FFFFFF, 0xfffd5555, 0x57555555);
+    DO_MIPS32_r2_s(msub, 26, 0xfffd5555, 0x57555555, 0x02000000, 0x03FFFFFF, 0xfff55555, 0x59555555);
+    DO_MIPS32_r2_s(msub, 27, 0xfff55555, 0x59555555, 0x04000000, 0x07FFFFFF, 0xffd55555, 0x5d555555);
+    DO_MIPS32_r2_s(msub, 28, 0xffd55555, 0x5d555555, 0x08000000, 0x0FFFFFFF, 0xff555555, 0x65555555);
+    DO_MIPS32_r2_s(msub, 29, 0xff555555, 0x65555555, 0x10000000, 0x1FFFFFFF, 0xfd555555, 0x75555555);
+    DO_MIPS32_r2_s(msub, 30, 0xfd555555, 0x75555555, 0x20000000, 0x3FFFFFFF, 0xf5555555, 0x95555555);
+    DO_MIPS32_r2_s(msub, 31, 0xf5555555, 0x95555555, 0x40000000, 0x7FFFFFFF, 0xd5555555, 0xd5555555);
+    DO_MIPS32_r2_s(msub, 32, 0xd5555555, 0xd5555555, 0x80000000, 0xFFFFFFFF, 0xd5555555, 0x55555555);
+    DO_MIPS32_r2_s(msub, 33, 0x00000000, 0x00000000, 0x00000000, 0x55555555, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(msub, 34, 0x00000000, 0x00000000, 0x55555555, 0x55555555, 0xe38e38e3, 0xc71c71c7);
+    DO_MIPS32_r2_s(msub, 35, 0xe38e38e3, 0xc71c71c7, 0xAAAAAAAA, 0x55555555, 0x00000000, 0x55555555);
+    DO_MIPS32_r2_s(msub, 36, 0x00000000, 0x55555555, 0xFFFFFFFF, 0x55555555, 0x00000000, 0xaaaaaaaa);
+    DO_MIPS32_r2_s(msub, 37, 0x00000000, 0xaaaaaaaa, 0xAAAAAAAA, 0x00000000, 0x00000000, 0xaaaaaaaa);
+    DO_MIPS32_r2_s(msub, 38, 0x00000000, 0xaaaaaaaa, 0xAAAAAAAA, 0x55555555, 0x1c71c71d, 0x38e38e38);
+    DO_MIPS32_r2_s(msub, 39, 0x1c71c71d, 0x38e38e38, 0xAAAAAAAA, 0xAAAAAAAA, 0x00000000, 0x55555554);
+    DO_MIPS32_r2_s(msub, 40, 0x00000000, 0x55555554, 0xAAAAAAAA, 0xFFFFFFFF, 0xffffffff, 0xfffffffe);
+    DO_MIPS32_r2_s(msub, 41, 0x00000000, 0x00000000, 0x7FFFFFFF, 0x7FFFFFFF, 0xc0000000, 0xffffffff);
+    DO_MIPS32_r2_s(msub, 42, 0xc0000000, 0xffffffff, 0x7FFFFFFF, 0x80000000, 0x00000000, 0x7fffffff);
+    DO_MIPS32_r2_s(msub, 43, 0x00000000, 0x7fffffff, 0x7FFFFFFF, 0xFFFFFFFF, 0x00000000, 0xfffffffe);
+    DO_MIPS32_r2_s(msub, 44, 0x00000000, 0xfffffffe, 0x80000000, 0x7FFFFFFF, 0x40000000, 0x7ffffffe);
+    DO_MIPS32_r2_s(msub, 45, 0x40000000, 0x7ffffffe, 0x80000000, 0x80000000, 0x00000000, 0x7ffffffe);
+    DO_MIPS32_r2_s(msub, 46, 0x00000000, 0x7ffffffe, 0x80000000, 0xFFFFFFFF, 0xffffffff, 0xfffffffe);
+    DO_MIPS32_r2_s(msub, 47, 0xffffffff, 0xfffffffe, 0xFFFFFFFF, 0x7FFFFFFF, 0x00000000, 0x7ffffffd);
+    DO_MIPS32_r2_s(msub, 48, 0x00000000, 0x7ffffffd, 0xFFFFFFFF, 0x80000000, 0xffffffff, 0xfffffffd);
+    DO_MIPS32_r2_s(msub, 49, 0xffffffff, 0xfffffffd, 0xFFFFFFFF, 0xFFFFFFFF, 0xffffffff, 0xfffffffc);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/msubu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/msubu.c
new file mode 100644
index 0000000000..d20065d0b2
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/msubu.c
@@ -0,0 +1,78 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r2_s(msubu, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(msubu, 1, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0xffffffff, 0xffffffff);
+    DO_MIPS32_r2_s(msubu, 2, 0xffffffff, 0xffffffff, 0x00000002, 0x00000003, 0xffffffff, 0xfffffff9);
+    DO_MIPS32_r2_s(msubu, 3, 0xffffffff, 0xfffffff9, 0x00000004, 0x00000007, 0xffffffff, 0xffffffdd);
+    DO_MIPS32_r2_s(msubu, 4, 0xffffffff, 0xffffffdd, 0x00000008, 0x0000000F, 0xffffffff, 0xffffff65);
+    DO_MIPS32_r2_s(msubu, 5, 0xffffffff, 0xffffff65, 0x00000010, 0x0000001F, 0xffffffff, 0xfffffd75);
+    DO_MIPS32_r2_s(msubu, 6, 0xffffffff, 0xfffffd75, 0x00000020, 0x0000003F, 0xffffffff, 0xfffff595);
+    DO_MIPS32_r2_s(msubu, 7, 0xffffffff, 0xfffff595, 0x00000040, 0x0000007F, 0xffffffff, 0xffffd5d5);
+    DO_MIPS32_r2_s(msubu, 8, 0xffffffff, 0xffffd5d5, 0x00000080, 0x000000FF, 0xffffffff, 0xffff5655);
+    DO_MIPS32_r2_s(msubu, 9, 0xffffffff, 0xffff5655, 0x00000100, 0x000001FF, 0xffffffff, 0xfffd5755);
+    DO_MIPS32_r2_s(msubu, 10, 0xffffffff, 0xfffd5755, 0x00000200, 0x000003FF, 0xffffffff, 0xfff55955);
+    DO_MIPS32_r2_s(msubu, 11, 0xffffffff, 0xfff55955, 0x00000400, 0x000007FF, 0xffffffff, 0xffd55d55);
+    DO_MIPS32_r2_s(msubu, 12, 0xffffffff, 0xffd55d55, 0x00000800, 0x00000FFF, 0xffffffff, 0xff556555);
+    DO_MIPS32_r2_s(msubu, 13, 0xffffffff, 0xff556555, 0x00001000, 0x00001FFF, 0xffffffff, 0xfd557555);
+    DO_MIPS32_r2_s(msubu, 14, 0xffffffff, 0xfd557555, 0x00002000, 0x00003FFF, 0xffffffff, 0xf5559555);
+    DO_MIPS32_r2_s(msubu, 15, 0xffffffff, 0xf5559555, 0x00004000, 0x00007FFF, 0xffffffff, 0xd555d555);
+    DO_MIPS32_r2_s(msubu, 16, 0xffffffff, 0xd555d555, 0x00008000, 0x0000FFFF, 0xffffffff, 0x55565555);
+    DO_MIPS32_r2_s(msubu, 17, 0xffffffff, 0x55565555, 0x00010000, 0x0001FFFF, 0xfffffffd, 0x55575555);
+    DO_MIPS32_r2_s(msubu, 18, 0xfffffffd, 0x55575555, 0x00020000, 0x0003FFFF, 0xfffffff5, 0x55595555);
+    DO_MIPS32_r2_s(msubu, 19, 0xfffffff5, 0x55595555, 0x00040000, 0x0007FFFF, 0xffffffd5, 0x555d5555);
+    DO_MIPS32_r2_s(msubu, 20, 0xffffffd5, 0x555d5555, 0x00080000, 0x000FFFFF, 0xffffff55, 0x55655555);
+    DO_MIPS32_r2_s(msubu, 21, 0xffffff55, 0x55655555, 0x00100000, 0x001FFFFF, 0xfffffd55, 0x55755555);
+    DO_MIPS32_r2_s(msubu, 22, 0xfffffd55, 0x55755555, 0x00200000, 0x003FFFFF, 0xfffff555, 0x55955555);
+    DO_MIPS32_r2_s(msubu, 23, 0xfffff555, 0x55955555, 0x00400000, 0x007FFFFF, 0xffffd555, 0x55d55555);
+    DO_MIPS32_r2_s(msubu, 24, 0xffffd555, 0x55d55555, 0x00800000, 0x00FFFFFF, 0xffff5555, 0x56555555);
+    DO_MIPS32_r2_s(msubu, 25, 0xffff5555, 0x56555555, 0x01000000, 0x01FFFFFF, 0xfffd5555, 0x57555555);
+    DO_MIPS32_r2_s(msubu, 26, 0xfffd5555, 0x57555555, 0x02000000, 0x03FFFFFF, 0xfff55555, 0x59555555);
+    DO_MIPS32_r2_s(msubu, 27, 0xfff55555, 0x59555555, 0x04000000, 0x07FFFFFF, 0xffd55555, 0x5d555555);
+    DO_MIPS32_r2_s(msubu, 28, 0xffd55555, 0x5d555555, 0x08000000, 0x0FFFFFFF, 0xff555555, 0x65555555);
+    DO_MIPS32_r2_s(msubu, 29, 0xff555555, 0x65555555, 0x10000000, 0x1FFFFFFF, 0xfd555555, 0x75555555);
+    DO_MIPS32_r2_s(msubu, 30, 0xfd555555, 0x75555555, 0x20000000, 0x3FFFFFFF, 0xf5555555, 0x95555555);
+    DO_MIPS32_r2_s(msubu, 31, 0xf5555555, 0x95555555, 0x40000000, 0x7FFFFFFF, 0xd5555555, 0xd5555555);
+    DO_MIPS32_r2_s(msubu, 32, 0xd5555555, 0xd5555555, 0x80000000, 0xFFFFFFFF, 0x55555556, 0x55555555);
+    DO_MIPS32_r2_s(msubu, 33, 0x00000000, 0x00000000, 0x00000000, 0x55555555, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(msubu, 34, 0x00000000, 0x00000000, 0x55555555, 0x55555555, 0xe38e38e3, 0xc71c71c7);
+    DO_MIPS32_r2_s(msubu, 35, 0xe38e38e3, 0xc71c71c7, 0xAAAAAAAA, 0x55555555, 0xaaaaaaab, 0x55555555);
+    DO_MIPS32_r2_s(msubu, 36, 0xaaaaaaab, 0x55555555, 0xFFFFFFFF, 0x55555555, 0x55555556, 0xaaaaaaaa);
+    DO_MIPS32_r2_s(msubu, 37, 0x55555556, 0xaaaaaaaa, 0xAAAAAAAA, 0x00000000, 0x55555556, 0xaaaaaaaa);
+    DO_MIPS32_r2_s(msubu, 38, 0x55555556, 0xaaaaaaaa, 0xAAAAAAAA, 0x55555555, 0x1c71c71e, 0x38e38e38);
+    DO_MIPS32_r2_s(msubu, 39, 0x1c71c71e, 0x38e38e38, 0xAAAAAAAA, 0xAAAAAAAA, 0xaaaaaaad, 0x55555554);
+    DO_MIPS32_r2_s(msubu, 40, 0xaaaaaaad, 0x55555554, 0xAAAAAAAA, 0xFFFFFFFF, 0x00000003, 0xfffffffe);
+    DO_MIPS32_r2_s(msubu, 41, 0x00000000, 0x00000000, 0x7FFFFFFF, 0x7FFFFFFF, 0xc0000000, 0xffffffff);
+    DO_MIPS32_r2_s(msubu, 42, 0xc0000000, 0xffffffff, 0x7FFFFFFF, 0x80000000, 0x80000001, 0x7fffffff);
+    DO_MIPS32_r2_s(msubu, 43, 0x80000001, 0x7fffffff, 0x7FFFFFFF, 0xFFFFFFFF, 0x00000002, 0xfffffffe);
+    DO_MIPS32_r2_s(msubu, 44, 0x00000002, 0xfffffffe, 0x80000000, 0x7FFFFFFF, 0xc0000003, 0x7ffffffe);
+    DO_MIPS32_r2_s(msubu, 45, 0xc0000003, 0x7ffffffe, 0x80000000, 0x80000000, 0x80000003, 0x7ffffffe);
+    DO_MIPS32_r2_s(msubu, 46, 0x80000003, 0x7ffffffe, 0x80000000, 0xFFFFFFFF, 0x00000003, 0xfffffffe);
+    DO_MIPS32_r2_s(msubu, 47, 0x00000003, 0xfffffffe, 0xFFFFFFFF, 0x7FFFFFFF, 0x80000005, 0x7ffffffd);
+    DO_MIPS32_r2_s(msubu, 48, 0x80000005, 0x7ffffffd, 0xFFFFFFFF, 0x80000000, 0x00000005, 0xfffffffd);
+    DO_MIPS32_r2_s(msubu, 49, 0x00000005, 0xfffffffd, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0xfffffffc);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/mul.c b/tests/tcg/mips/user/isa/mips32/arithmatic/mul.c
new file mode 100644
index 0000000000..ab74a14545
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/mul.c
@@ -0,0 +1,78 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r(mul, 0, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r(mul, 1, 0x00000001, 0x00000001, 0x00000001);
+    DO_MIPS32_r(mul, 2, 0x00000002, 0x00000003, 0x00000006);
+    DO_MIPS32_r(mul, 3, 0x00000004, 0x00000007, 0x0000001C);
+    DO_MIPS32_r(mul, 4, 0x00000008, 0x0000000F, 0x00000078);
+    DO_MIPS32_r(mul, 5, 0x00000010, 0x0000001F, 0x000001F0);
+    DO_MIPS32_r(mul, 6, 0x00000020, 0x0000003F, 0x000007E0);
+    DO_MIPS32_r(mul, 7, 0x00000040, 0x0000007F, 0x00001FC0);
+    DO_MIPS32_r(mul, 8, 0x00000080, 0x000000FF, 0x00007F80);
+    DO_MIPS32_r(mul, 9, 0x00000100, 0x000001FF, 0x0001FF00);
+    DO_MIPS32_r(mul, 10, 0x00000200, 0x000003FF, 0x0007FE00);
+    DO_MIPS32_r(mul, 11, 0x00000400, 0x000007FF, 0x001FFC00);
+    DO_MIPS32_r(mul, 12, 0x00000800, 0x00000FFF, 0x007FF800);
+    DO_MIPS32_r(mul, 13, 0x00001000, 0x00001FFF, 0x01FFF000);
+    DO_MIPS32_r(mul, 14, 0x00002000, 0x00003FFF, 0x07FFE000);
+    DO_MIPS32_r(mul, 15, 0x00004000, 0x00007FFF, 0x1FFFC000);
+    DO_MIPS32_r(mul, 16, 0x00008000, 0x0000FFFF, 0x7FFF8000);
+    DO_MIPS32_r(mul, 17, 0x00010000, 0x0001FFFF, 0xFFFF0000);
+    DO_MIPS32_r(mul, 18, 0x00020000, 0x0003FFFF, 0xFFFE0000);
+    DO_MIPS32_r(mul, 19, 0x00040000, 0x0007FFFF, 0xFFFC0000);
+    DO_MIPS32_r(mul, 20, 0x00080000, 0x000FFFFF, 0xFFF80000);
+    DO_MIPS32_r(mul, 21, 0x00100000, 0x001FFFFF, 0xFFF00000);
+    DO_MIPS32_r(mul, 22, 0x00200000, 0x003FFFFF, 0xFFE00000);
+    DO_MIPS32_r(mul, 23, 0x00400000, 0x007FFFFF, 0xFFC00000);
+    DO_MIPS32_r(mul, 24, 0x00800000, 0x00FFFFFF, 0xFF800000);
+    DO_MIPS32_r(mul, 25, 0x01000000, 0x01FFFFFF, 0xFF000000);
+    DO_MIPS32_r(mul, 26, 0x02000000, 0x03FFFFFF, 0xFE000000);
+    DO_MIPS32_r(mul, 27, 0x04000000, 0x07FFFFFF, 0xFC000000);
+    DO_MIPS32_r(mul, 28, 0x08000000, 0x0FFFFFFF, 0xF8000000);
+    DO_MIPS32_r(mul, 29, 0x10000000, 0x1FFFFFFF, 0xF0000000);
+    DO_MIPS32_r(mul, 30, 0x20000000, 0x3FFFFFFF, 0xE0000000);
+    DO_MIPS32_r(mul, 31, 0x40000000, 0x7FFFFFFF, 0xC0000000);
+    DO_MIPS32_r(mul, 32, 0x80000000, 0xFFFFFFFF, 0x80000000);
+    DO_MIPS32_r(mul, 33, 0x00000000, 0x55555555, 0x00000000);
+    DO_MIPS32_r(mul, 34, 0x55555555, 0x55555555, 0x38E38E39);
+    DO_MIPS32_r(mul, 35, 0xAAAAAAAA, 0x55555555, 0x71C71C72);
+    DO_MIPS32_r(mul, 36, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAB);
+    DO_MIPS32_r(mul, 37, 0xAAAAAAAA, 0x00000000, 0x00000000);
+    DO_MIPS32_r(mul, 38, 0xAAAAAAAA, 0x55555555, 0x71C71C72);
+    DO_MIPS32_r(mul, 39, 0xAAAAAAAA, 0xAAAAAAAA, 0xE38E38E4);
+    DO_MIPS32_r(mul, 40, 0xAAAAAAAA, 0xFFFFFFFF, 0x55555556);
+    DO_MIPS32_r(mul, 41, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000001);
+    DO_MIPS32_r(mul, 42, 0x7FFFFFFF, 0x80000000, 0x80000000);
+    DO_MIPS32_r(mul, 43, 0x7FFFFFFF, 0xFFFFFFFF, 0x80000001);
+    DO_MIPS32_r(mul, 44, 0x80000000, 0x7FFFFFFF, 0x80000000);
+    DO_MIPS32_r(mul, 45, 0x80000000, 0x80000000, 0x00000000);
+    DO_MIPS32_r(mul, 46, 0x80000000, 0xFFFFFFFF, 0x80000000);
+    DO_MIPS32_r(mul, 47, 0xFFFFFFFF, 0x7FFFFFFF, 0x80000001);
+    DO_MIPS32_r(mul, 48, 0xFFFFFFFF, 0x80000000, 0x80000000);
+    DO_MIPS32_r(mul, 49, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/mult.c b/tests/tcg/mips/user/isa/mips32/arithmatic/mult.c
new file mode 100644
index 0000000000..8ac7b2c1b8
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/mult.c
@@ -0,0 +1,78 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r2_s(mult, 0, 0, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(mult, 1, 0, 0, 0x00000001, 0x00000001, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(mult, 2, 0, 0, 0x00000002, 0x00000003, 0x00000000, 0x00000006);
+    DO_MIPS32_r2_s(mult, 3, 0, 0, 0x00000004, 0x00000007, 0x00000000, 0x0000001C);
+    DO_MIPS32_r2_s(mult, 4, 0, 0, 0x00000008, 0x0000000F, 0x00000000, 0x00000078);
+    DO_MIPS32_r2_s(mult, 5, 0, 0, 0x00000010, 0x0000001F, 0x00000000, 0x000001F0);
+    DO_MIPS32_r2_s(mult, 6, 0, 0, 0x00000020, 0x0000003F, 0x00000000, 0x000007E0);
+    DO_MIPS32_r2_s(mult, 7, 0, 0, 0x00000040, 0x0000007F, 0x00000000, 0x00001FC0);
+    DO_MIPS32_r2_s(mult, 8, 0, 0, 0x00000080, 0x000000FF, 0x00000000, 0x00007F80);
+    DO_MIPS32_r2_s(mult, 9, 0, 0, 0x00000100, 0x000001FF, 0x00000000, 0x0001FF00);
+    DO_MIPS32_r2_s(mult, 10, 0, 0, 0x00000200, 0x000003FF, 0x00000000, 0x0007FE00);
+    DO_MIPS32_r2_s(mult, 11, 0, 0, 0x00000400, 0x000007FF, 0x00000000, 0x001FFC00);
+    DO_MIPS32_r2_s(mult, 12, 0, 0, 0x00000800, 0x00000FFF, 0x00000000, 0x007FF800);
+    DO_MIPS32_r2_s(mult, 13, 0, 0, 0x00001000, 0x00001FFF, 0x00000000, 0x01FFF000);
+    DO_MIPS32_r2_s(mult, 14, 0, 0, 0x00002000, 0x00003FFF, 0x00000000, 0x07FFE000);
+    DO_MIPS32_r2_s(mult, 15, 0, 0, 0x00004000, 0x00007FFF, 0x00000000, 0x1FFFC000);
+    DO_MIPS32_r2_s(mult, 16, 0, 0, 0x00008000, 0x0000FFFF, 0x00000000, 0x7FFF8000);
+    DO_MIPS32_r2_s(mult, 17, 0, 0, 0x00010000, 0x0001FFFF, 0x00000001, 0xFFFF0000);
+    DO_MIPS32_r2_s(mult, 18, 0, 0, 0x00020000, 0x0003FFFF, 0x00000007, 0xFFFE0000);
+    DO_MIPS32_r2_s(mult, 19, 0, 0, 0x00040000, 0x0007FFFF, 0x0000001F, 0xFFFC0000);
+    DO_MIPS32_r2_s(mult, 20, 0, 0, 0x00080000, 0x000FFFFF, 0x0000007F, 0xFFF80000);
+    DO_MIPS32_r2_s(mult, 21, 0, 0, 0x00100000, 0x001FFFFF, 0x000001FF, 0xFFF00000);
+    DO_MIPS32_r2_s(mult, 22, 0, 0, 0x00200000, 0x003FFFFF, 0x000007FF, 0xFFE00000);
+    DO_MIPS32_r2_s(mult, 23, 0, 0, 0x00400000, 0x007FFFFF, 0x00001FFF, 0xFFC00000);
+    DO_MIPS32_r2_s(mult, 24, 0, 0, 0x00800000, 0x00FFFFFF, 0x00007FFF, 0xFF800000);
+    DO_MIPS32_r2_s(mult, 25, 0, 0, 0x01000000, 0x01FFFFFF, 0x0001FFFF, 0xFF000000);
+    DO_MIPS32_r2_s(mult, 26, 0, 0, 0x02000000, 0x03FFFFFF, 0x0007FFFF, 0xFE000000);
+    DO_MIPS32_r2_s(mult, 27, 0, 0, 0x04000000, 0x07FFFFFF, 0x001FFFFF, 0xFC000000);
+    DO_MIPS32_r2_s(mult, 28, 0, 0, 0x08000000, 0x0FFFFFFF, 0x007FFFFF, 0xF8000000);
+    DO_MIPS32_r2_s(mult, 29, 0, 0, 0x10000000, 0x1FFFFFFF, 0x01FFFFFF, 0xF0000000);
+    DO_MIPS32_r2_s(mult, 30, 0, 0, 0x20000000, 0x3FFFFFFF, 0x07FFFFFF, 0xE0000000);
+    DO_MIPS32_r2_s(mult, 31, 0, 0, 0x40000000, 0x7FFFFFFF, 0x1FFFFFFF, 0xC0000000);
+    DO_MIPS32_r2_s(mult, 32, 0, 0, 0x80000000, 0xFFFFFFFF, 0x00000000, 0x80000000);
+    DO_MIPS32_r2_s(mult, 33, 0, 0, 0x00000000, 0x55555555, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(mult, 34, 0, 0, 0x55555555, 0x55555555, 0x1C71C71C, 0x38E38E39);
+    DO_MIPS32_r2_s(mult, 35, 0, 0, 0xAAAAAAAA, 0x55555555, 0xE38E38E3, 0x71C71C72);
+    DO_MIPS32_r2_s(mult, 36, 0, 0, 0xFFFFFFFF, 0x55555555, 0xFFFFFFFF, 0xAAAAAAAB);
+    DO_MIPS32_r2_s(mult, 37, 0, 0, 0xAAAAAAAA, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(mult, 38, 0, 0, 0xAAAAAAAA, 0x55555555, 0xE38E38E3, 0x71C71C72);
+    DO_MIPS32_r2_s(mult, 39, 0, 0, 0xAAAAAAAA, 0xAAAAAAAA, 0x1C71C71C, 0xE38E38E4);
+    DO_MIPS32_r2_s(mult, 40, 0, 0, 0xAAAAAAAA, 0xFFFFFFFF, 0x00000000, 0x55555556);
+    DO_MIPS32_r2_s(mult, 41, 0, 0, 0x7FFFFFFF, 0x7FFFFFFF, 0x3FFFFFFF, 0x00000001);
+    DO_MIPS32_r2_s(mult, 42, 0, 0, 0x7FFFFFFF, 0x80000000, 0xC0000000, 0x80000000);
+    DO_MIPS32_r2_s(mult, 43, 0, 0, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x80000001);
+    DO_MIPS32_r2_s(mult, 44, 0, 0, 0x80000000, 0x7FFFFFFF, 0xC0000000, 0x80000000);
+    DO_MIPS32_r2_s(mult, 45, 0, 0, 0x80000000, 0x80000000, 0x40000000, 0x00000000);
+    DO_MIPS32_r2_s(mult, 46, 0, 0, 0x80000000, 0xFFFFFFFF, 0x00000000, 0x80000000);
+    DO_MIPS32_r2_s(mult, 47, 0, 0, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0x80000001);
+    DO_MIPS32_r2_s(mult, 48, 0, 0, 0xFFFFFFFF, 0x80000000, 0x00000000, 0x80000000);
+    DO_MIPS32_r2_s(mult, 49, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000001);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/multu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/multu.c
new file mode 100644
index 0000000000..eeafbd2d50
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/multu.c
@@ -0,0 +1,78 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r2_s(multu, 0, 0, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(multu, 1, 0, 0, 0x00000001, 0x00000001, 0x00000000, 0x00000001);
+    DO_MIPS32_r2_s(multu, 2, 0, 0, 0x00000002, 0x00000003, 0x00000000, 0x00000006);
+    DO_MIPS32_r2_s(multu, 3, 0, 0, 0x00000004, 0x00000007, 0x00000000, 0x0000001C);
+    DO_MIPS32_r2_s(multu, 4, 0, 0, 0x00000008, 0x0000000F, 0x00000000, 0x00000078);
+    DO_MIPS32_r2_s(multu, 5, 0, 0, 0x00000010, 0x0000001F, 0x00000000, 0x000001F0);
+    DO_MIPS32_r2_s(multu, 6, 0, 0, 0x00000020, 0x0000003F, 0x00000000, 0x000007E0);
+    DO_MIPS32_r2_s(multu, 7, 0, 0, 0x00000040, 0x0000007F, 0x00000000, 0x00001FC0);
+    DO_MIPS32_r2_s(multu, 8, 0, 0, 0x00000080, 0x000000FF, 0x00000000, 0x00007F80);
+    DO_MIPS32_r2_s(multu, 9, 0, 0, 0x00000100, 0x000001FF, 0x00000000, 0x0001FF00);
+    DO_MIPS32_r2_s(multu, 10, 0, 0, 0x00000200, 0x000003FF, 0x00000000, 0x0007FE00);
+    DO_MIPS32_r2_s(multu, 11, 0, 0, 0x00000400, 0x000007FF, 0x00000000, 0x001FFC00);
+    DO_MIPS32_r2_s(multu, 12, 0, 0, 0x00000800, 0x00000FFF, 0x00000000, 0x007FF800);
+    DO_MIPS32_r2_s(multu, 13, 0, 0, 0x00001000, 0x00001FFF, 0x00000000, 0x01FFF000);
+    DO_MIPS32_r2_s(multu, 14, 0, 0, 0x00002000, 0x00003FFF, 0x00000000, 0x07FFE000);
+    DO_MIPS32_r2_s(multu, 15, 0, 0, 0x00004000, 0x00007FFF, 0x00000000, 0x1FFFC000);
+    DO_MIPS32_r2_s(multu, 16, 0, 0, 0x00008000, 0x0000FFFF, 0x00000000, 0x7FFF8000);
+    DO_MIPS32_r2_s(multu, 17, 0, 0, 0x00010000, 0x0001FFFF, 0x00000001, 0xFFFF0000);
+    DO_MIPS32_r2_s(multu, 18, 0, 0, 0x00020000, 0x0003FFFF, 0x00000007, 0xFFFE0000);
+    DO_MIPS32_r2_s(multu, 19, 0, 0, 0x00040000, 0x0007FFFF, 0x0000001F, 0xFFFC0000);
+    DO_MIPS32_r2_s(multu, 20, 0, 0, 0x00080000, 0x000FFFFF, 0x0000007F, 0xFFF80000);
+    DO_MIPS32_r2_s(multu, 21, 0, 0, 0x00100000, 0x001FFFFF, 0x000001FF, 0xFFF00000);
+    DO_MIPS32_r2_s(multu, 22, 0, 0, 0x00200000, 0x003FFFFF, 0x000007FF, 0xFFE00000);
+    DO_MIPS32_r2_s(multu, 23, 0, 0, 0x00400000, 0x007FFFFF, 0x00001FFF, 0xFFC00000);
+    DO_MIPS32_r2_s(multu, 24, 0, 0, 0x00800000, 0x00FFFFFF, 0x00007FFF, 0xFF800000);
+    DO_MIPS32_r2_s(multu, 25, 0, 0, 0x01000000, 0x01FFFFFF, 0x0001FFFF, 0xFF000000);
+    DO_MIPS32_r2_s(multu, 26, 0, 0, 0x02000000, 0x03FFFFFF, 0x0007FFFF, 0xFE000000);
+    DO_MIPS32_r2_s(multu, 27, 0, 0, 0x04000000, 0x07FFFFFF, 0x001FFFFF, 0xFC000000);
+    DO_MIPS32_r2_s(multu, 28, 0, 0, 0x08000000, 0x0FFFFFFF, 0x007FFFFF, 0xF8000000);
+    DO_MIPS32_r2_s(multu, 29, 0, 0, 0x10000000, 0x1FFFFFFF, 0x01FFFFFF, 0xF0000000);
+    DO_MIPS32_r2_s(multu, 30, 0, 0, 0x20000000, 0x3FFFFFFF, 0x07FFFFFF, 0xE0000000);
+    DO_MIPS32_r2_s(multu, 31, 0, 0, 0x40000000, 0x7FFFFFFF, 0x1FFFFFFF, 0xC0000000);
+    DO_MIPS32_r2_s(multu, 32, 0, 0, 0x80000000, 0xFFFFFFFF, 0x7FFFFFFF, 0x80000000);
+    DO_MIPS32_r2_s(multu, 33, 0, 0, 0x00000000, 0x55555555, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(multu, 34, 0, 0, 0x55555555, 0x55555555, 0x1C71C71C, 0x38E38E39);
+    DO_MIPS32_r2_s(multu, 35, 0, 0, 0xAAAAAAAA, 0x55555555, 0x38E38E38, 0x71C71C72);
+    DO_MIPS32_r2_s(multu, 36, 0, 0, 0xFFFFFFFF, 0x55555555, 0x55555554, 0xAAAAAAAB);
+    DO_MIPS32_r2_s(multu, 37, 0, 0, 0xAAAAAAAA, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r2_s(multu, 38, 0, 0, 0xAAAAAAAA, 0x55555555, 0x38E38E38, 0x71C71C72);
+    DO_MIPS32_r2_s(multu, 39, 0, 0, 0xAAAAAAAA, 0xAAAAAAAA, 0x71C71C70, 0xE38E38E4);
+    DO_MIPS32_r2_s(multu, 40, 0, 0, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAA9, 0x55555556);
+    DO_MIPS32_r2_s(multu, 41, 0, 0, 0x7FFFFFFF, 0x7FFFFFFF, 0x3FFFFFFF, 0x00000001);
+    DO_MIPS32_r2_s(multu, 42, 0, 0, 0x7FFFFFFF, 0x80000000, 0x3FFFFFFF, 0x80000000);
+    DO_MIPS32_r2_s(multu, 43, 0, 0, 0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFE, 0x80000001);
+    DO_MIPS32_r2_s(multu, 44, 0, 0, 0x80000000, 0x7FFFFFFF, 0x3FFFFFFF, 0x80000000);
+    DO_MIPS32_r2_s(multu, 45, 0, 0, 0x80000000, 0x80000000, 0x40000000, 0x00000000);
+    DO_MIPS32_r2_s(multu, 46, 0, 0, 0x80000000, 0xFFFFFFFF, 0x7FFFFFFF, 0x80000000);
+    DO_MIPS32_r2_s(multu, 47, 0, 0, 0xFFFFFFFF, 0x7FFFFFFF, 0x7FFFFFFE, 0x80000001);
+    DO_MIPS32_r2_s(multu, 48, 0, 0, 0xFFFFFFFF, 0x80000000, 0x7FFFFFFF, 0x80000000);
+    DO_MIPS32_r2_s(multu, 49, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0x00000001);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/slt.c b/tests/tcg/mips/user/isa/mips32/arithmatic/slt.c
new file mode 100644
index 0000000000..74f22c365e
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/slt.c
@@ -0,0 +1,61 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r(slt, 0, 0x00000000, 0x00000000, 0);
+    DO_MIPS32_r(slt, 1, 0x00000001, 0x00000001, 0);
+    DO_MIPS32_r(slt, 2, 0x00000002, 0x00000003, 1);
+    DO_MIPS32_r(slt, 3, 0x00000005, 0x00000007, 1);
+    DO_MIPS32_r(slt, 4, 0x0000000B, 0x0000000F, 1);
+    DO_MIPS32_r(slt, 5, 0x00000017, 0x0000001F, 1);
+    DO_MIPS32_r(slt, 6, 0x0000002F, 0x0000003F, 1);
+    DO_MIPS32_r(slt, 7, 0x0000005F, 0x0000007F, 1);
+    DO_MIPS32_r(slt, 8, 0x000000BF, 0x000000FF, 1);
+    DO_MIPS32_r(slt, 9, 0x0000017F, 0x000001FF, 1);
+    DO_MIPS32_r(slt, 10, 0x000002FF, 0x000003FF, 1);
+    DO_MIPS32_r(slt, 11, 0x000005FF, 0x000007FF, 1);
+    DO_MIPS32_r(slt, 12, 0x00000BFF, 0x00000FFF, 1);
+    DO_MIPS32_r(slt, 13, 0x000017FF, 0x00001FFF, 1);
+    DO_MIPS32_r(slt, 14, 0x00002FFF, 0x00003FFF, 1);
+    DO_MIPS32_r(slt, 15, 0x00005FFF, 0x00007FFF, 1);
+    DO_MIPS32_r(slt, 16, 0x0000BFFF, 0x0000FFFF, 1);
+    DO_MIPS32_r(slt, 17, 0x00017FFF, 0x0001FFFF, 1);
+    DO_MIPS32_r(slt, 18, 0x0002FFFF, 0x0003FFFF, 1);
+    DO_MIPS32_r(slt, 19, 0x0005FFFF, 0x0007FFFF, 1);
+    DO_MIPS32_r(slt, 20, 0x000BFFFF, 0x000FFFFF, 1);
+    DO_MIPS32_r(slt, 21, 0x0017FFFF, 0x001FFFFF, 1);
+    DO_MIPS32_r(slt, 22, 0x002FFFFF, 0x003FFFFF, 1);
+    DO_MIPS32_r(slt, 23, 0x005FFFFF, 0x007FFFFF, 1);
+    DO_MIPS32_r(slt, 24, 0x00BFFFFF, 0x00FFFFFF, 1);
+    DO_MIPS32_r(slt, 25, 0x017FFFFF, 0x01FFFFFF, 1);
+    DO_MIPS32_r(slt, 26, 0x02FFFFFF, 0x03FFFFFF, 1);
+    DO_MIPS32_r(slt, 27, 0x05FFFFFF, 0x07FFFFFF, 1);
+    DO_MIPS32_r(slt, 28, 0x0BFFFFFF, 0x0FFFFFFF, 1);
+    DO_MIPS32_r(slt, 29, 0x17FFFFFF, 0x1FFFFFFF, 1);
+    DO_MIPS32_r(slt, 30, 0x2FFFFFFF, 0x3FFFFFFF, 1);
+    DO_MIPS32_r(slt, 31, 0x5FFFFFFF, 0x7FFFFFFF, 1);
+    DO_MIPS32_r(slt, 32, 0xBFFFFFFF, 0xFFFFFFFF, 1);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/slti.c b/tests/tcg/mips/user/isa/mips32/arithmatic/slti.c
new file mode 100644
index 0000000000..823af3e4d4
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/slti.c
@@ -0,0 +1,48 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_i(slti, 0, 0x0000, 0x00000000, 0);
+    DO_MIPS32_i(slti, 1, 0x0001, 0x00000001, 0);
+    DO_MIPS32_i(slti, 2, 0x0003, 0x00000002, 1);
+    DO_MIPS32_i(slti, 3, 0x0007, 0x00000005, 1);
+    DO_MIPS32_i(slti, 4, 0x000F, 0x0000000B, 1);
+    DO_MIPS32_i(slti, 5, 0x001F, 0x00000017, 1);
+    DO_MIPS32_i(slti, 6, 0x003F, 0x0000002F, 1);
+    DO_MIPS32_i(slti, 7, 0x007F, 0x0000005F, 1);
+    DO_MIPS32_i(slti, 8, 0x00FF, 0x000000BF, 1);
+    DO_MIPS32_i(slti, 9, 0x01FF, 0x0000017F, 1);
+    DO_MIPS32_i(slti, 10, 0x03FF, 0x000002FF, 1);
+    DO_MIPS32_i(slti, 11, 0x07FF, 0x000005FF, 1);
+    DO_MIPS32_i(slti, 12, 0x0FFF, 0x00000BFF, 1);
+    DO_MIPS32_i(slti, 13, 0x1FFF, 0x000017FF, 1);
+    DO_MIPS32_i(slti, 14, 0x3FFF, 0x00002FFF, 1);
+    DO_MIPS32_i(slti, 15, 0x7FFF, 0x00005FFF, 1);
+    DO_MIPS32_i(slti, 16, 0xFFFF, 0x0000BFFF, 0);
+    DO_MIPS32_i(slti, 17, 0xFFFF, 0x7FFFFFFF, 0);
+    DO_MIPS32_i(slti, 18, 0x8000, 0x7FFFFFFF, 0);
+    DO_MIPS32_i(slti, 19, 0x5555, 0x00000000, 1);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/sltiu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/sltiu.c
new file mode 100644
index 0000000000..5644d4d1c1
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/sltiu.c
@@ -0,0 +1,48 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_i(sltiu, 0, 0x0000, 0x00000000, 0);
+    DO_MIPS32_i(sltiu, 1, 0x0001, 0x00000001, 0);
+    DO_MIPS32_i(sltiu, 2, 0x0003, 0x00000002, 1);
+    DO_MIPS32_i(sltiu, 3, 0x0007, 0x00000005, 1);
+    DO_MIPS32_i(sltiu, 4, 0x000F, 0x0000000B, 1);
+    DO_MIPS32_i(sltiu, 5, 0x001F, 0x00000017, 1);
+    DO_MIPS32_i(sltiu, 6, 0x003F, 0x0000002F, 1);
+    DO_MIPS32_i(sltiu, 7, 0x007F, 0x0000005F, 1);
+    DO_MIPS32_i(sltiu, 8, 0x00FF, 0x000000BF, 1);
+    DO_MIPS32_i(sltiu, 9, 0x01FF, 0x0000017F, 1);
+    DO_MIPS32_i(sltiu, 10, 0x03FF, 0x000002FF, 1);
+    DO_MIPS32_i(sltiu, 11, 0x07FF, 0x000005FF, 1);
+    DO_MIPS32_i(sltiu, 12, 0x0FFF, 0x00000BFF, 1);
+    DO_MIPS32_i(sltiu, 13, 0x1FFF, 0x000017FF, 1);
+    DO_MIPS32_i(sltiu, 14, 0x3FFF, 0x00002FFF, 1);
+    DO_MIPS32_i(sltiu, 15, 0x7FFF, 0x00005FFF, 1);
+    DO_MIPS32_i(sltiu, 16, 0xFFFF, 0x0000BFFF, 1);
+    DO_MIPS32_i(sltiu, 17, 0x5555, 0x00000000, 1);
+    DO_MIPS32_i(sltiu, 18, 0xFFFF, 0x7FFFFFFF, 1);
+    DO_MIPS32_i(sltiu, 19, 0x8000, 0x7FFFFFFF, 1);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/sltu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/sltu.c
new file mode 100644
index 0000000000..bba246626e
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/sltu.c
@@ -0,0 +1,61 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r(sltu, 0, 0x00000000, 0x00000000, 0);
+    DO_MIPS32_r(sltu, 1, 0x00000001, 0x00000001, 0);
+    DO_MIPS32_r(sltu, 2, 0x00000002, 0x00000003, 1);
+    DO_MIPS32_r(sltu, 3, 0x00000005, 0x00000007, 1);
+    DO_MIPS32_r(sltu, 4, 0x0000000B, 0x0000000F, 1);
+    DO_MIPS32_r(sltu, 5, 0x00000017, 0x0000001F, 1);
+    DO_MIPS32_r(sltu, 6, 0x0000002F, 0x0000003F, 1);
+    DO_MIPS32_r(sltu, 7, 0x0000005F, 0x0000007F, 1);
+    DO_MIPS32_r(sltu, 8, 0x000000BF, 0x000000FF, 1);
+    DO_MIPS32_r(sltu, 9, 0x0000017F, 0x000001FF, 1);
+    DO_MIPS32_r(sltu, 10, 0x000002FF, 0x000003FF, 1);
+    DO_MIPS32_r(sltu, 11, 0x000005FF, 0x000007FF, 1);
+    DO_MIPS32_r(sltu, 12, 0x00000BFF, 0x00000FFF, 1);
+    DO_MIPS32_r(sltu, 13, 0x000017FF, 0x00001FFF, 1);
+    DO_MIPS32_r(sltu, 14, 0x00002FFF, 0x00003FFF, 1);
+    DO_MIPS32_r(sltu, 15, 0x00005FFF, 0x00007FFF, 1);
+    DO_MIPS32_r(sltu, 16, 0x0000BFFF, 0x0000FFFF, 1);
+    DO_MIPS32_r(sltu, 17, 0x00017FFF, 0x0001FFFF, 1);
+    DO_MIPS32_r(sltu, 18, 0x0002FFFF, 0x0003FFFF, 1);
+    DO_MIPS32_r(sltu, 19, 0x0005FFFF, 0x0007FFFF, 1);
+    DO_MIPS32_r(sltu, 20, 0x000BFFFF, 0x000FFFFF, 1);
+    DO_MIPS32_r(sltu, 21, 0x0017FFFF, 0x001FFFFF, 1);
+    DO_MIPS32_r(sltu, 22, 0x002FFFFF, 0x003FFFFF, 1);
+    DO_MIPS32_r(sltu, 23, 0x005FFFFF, 0x007FFFFF, 1);
+    DO_MIPS32_r(sltu, 24, 0x00BFFFFF, 0x00FFFFFF, 1);
+    DO_MIPS32_r(sltu, 25, 0x017FFFFF, 0x01FFFFFF, 1);
+    DO_MIPS32_r(sltu, 26, 0x02FFFFFF, 0x03FFFFFF, 1);
+    DO_MIPS32_r(sltu, 27, 0x05FFFFFF, 0x07FFFFFF, 1);
+    DO_MIPS32_r(sltu, 28, 0x0BFFFFFF, 0x0FFFFFFF, 1);
+    DO_MIPS32_r(sltu, 29, 0x17FFFFFF, 0x1FFFFFFF, 1);
+    DO_MIPS32_r(sltu, 30, 0x2FFFFFFF, 0x3FFFFFFF, 1);
+    DO_MIPS32_r(sltu, 31, 0x5FFFFFFF, 0x7FFFFFFF, 1);
+    DO_MIPS32_r(sltu, 32, 0xBFFFFFFF, 0xFFFFFFFF, 1);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/sub.c b/tests/tcg/mips/user/isa/mips32/arithmatic/sub.c
new file mode 100644
index 0000000000..86f747c2e7
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/sub.c
@@ -0,0 +1,104 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r(sub, 0, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r(sub, 1, 0x00000001, 0x00000001, 0x00000000);
+    DO_MIPS32_r(sub, 2, 0x00000002, 0x00000003, 0xFFFFFFFF);
+    DO_MIPS32_r(sub, 3, 0x00000004, 0x00000006, 0xFFFFFFFE);
+    DO_MIPS32_r(sub, 4, 0x00000008, 0x0000000C, 0xFFFFFFFC);
+    DO_MIPS32_r(sub, 5, 0x00000010, 0x00000018, 0xFFFFFFF8);
+    DO_MIPS32_r(sub, 6, 0x00000020, 0x00000030, 0xFFFFFFF0);
+    DO_MIPS32_r(sub, 7, 0x00000040, 0x00000060, 0xFFFFFFE0);
+    DO_MIPS32_r(sub, 8, 0x00000080, 0x000000C0, 0xFFFFFFC0);
+    DO_MIPS32_r(sub, 9, 0x00000100, 0x00000180, 0xFFFFFF80);
+    DO_MIPS32_r(sub, 10, 0x00000200, 0x00000300, 0xFFFFFF00);
+    DO_MIPS32_r(sub, 11, 0x00000400, 0x00000600, 0xFFFFFE00);
+    DO_MIPS32_r(sub, 12, 0x00000800, 0x00000C00, 0xFFFFFC00);
+    DO_MIPS32_r(sub, 13, 0x00001000, 0x00001800, 0xFFFFF800);
+    DO_MIPS32_r(sub, 14, 0x00002000, 0x00003000, 0xFFFFF000);
+    DO_MIPS32_r(sub, 15, 0x00004000, 0x00006000, 0xFFFFE000);
+    DO_MIPS32_r(sub, 16, 0x00008000, 0x0000C000, 0xFFFFC000);
+    DO_MIPS32_r(sub, 17, 0x00010000, 0x00018000, 0xFFFF8000);
+    DO_MIPS32_r(sub, 18, 0x00020000, 0x00030000, 0xFFFF0000);
+    DO_MIPS32_r(sub, 19, 0x00040000, 0x00060000, 0xFFFE0000);
+    DO_MIPS32_r(sub, 20, 0x00080000, 0x000C0000, 0xFFFC0000);
+    DO_MIPS32_r(sub, 21, 0x00100000, 0x00180000, 0xFFF80000);
+    DO_MIPS32_r(sub, 22, 0x00200000, 0x00300000, 0xFFF00000);
+    DO_MIPS32_r(sub, 23, 0x00400000, 0x00600000, 0xFFE00000);
+    DO_MIPS32_r(sub, 24, 0x00800000, 0x00C00000, 0xFFC00000);
+    DO_MIPS32_r(sub, 25, 0x01000000, 0x01800000, 0xFF800000);
+    DO_MIPS32_r(sub, 26, 0x02000000, 0x03000000, 0xFF000000);
+    DO_MIPS32_r(sub, 27, 0x04000000, 0x06000000, 0xFE000000);
+    DO_MIPS32_r(sub, 28, 0x08000000, 0x0C000000, 0xFC000000);
+    DO_MIPS32_r(sub, 29, 0x10000000, 0x18000000, 0xF8000000);
+    DO_MIPS32_r(sub, 30, 0x20000000, 0x30000000, 0xF0000000);
+    DO_MIPS32_r(sub, 31, 0x40000000, 0x60000000, 0xE0000000);
+    DO_MIPS32_r(sub, 32, 0x80000000, 0xC0000000, 0xC0000000);
+    DO_MIPS32_r(sub, 33, 0x00000000, 0x80000000, 0x80000000);
+    DO_MIPS32_r(sub, 34, 0x80000001, 0x80000001, 0x00000000);
+    DO_MIPS32_r(sub, 35, 0xC0000003, 0x40000002, 0x80000001);
+    DO_MIPS32_r(sub, 36, 0xE0000007, 0x20000004, 0xC0000003);
+    DO_MIPS32_r(sub, 37, 0xF000000F, 0x10000008, 0xE0000007);
+    DO_MIPS32_r(sub, 38, 0xF800001F, 0x08000010, 0xF000000F);
+    DO_MIPS32_r(sub, 39, 0xFC00003F, 0x04000020, 0xF800001F);
+    DO_MIPS32_r(sub, 40, 0xFE00007F, 0x02000040, 0xFC00003F);
+    DO_MIPS32_r(sub, 41, 0xFF0000FF, 0x01000080, 0xFE00007F);
+    DO_MIPS32_r(sub, 42, 0xFF8001FF, 0x00800100, 0xFF0000FF);
+    DO_MIPS32_r(sub, 43, 0xFFC003FF, 0x00400200, 0xFF8001FF);
+    DO_MIPS32_r(sub, 44, 0xFFE007FF, 0x00200400, 0xFFC003FF);
+    DO_MIPS32_r(sub, 45, 0xFFF00FFF, 0x00100800, 0xFFE007FF);
+    DO_MIPS32_r(sub, 46, 0xFFF81FFF, 0x00081000, 0xFFF00FFF);
+    DO_MIPS32_r(sub, 47, 0xFFFC3FFF, 0x00042000, 0xFFF81FFF);
+    DO_MIPS32_r(sub, 48, 0xFFFE7FFF, 0x00024000, 0xFFFC3FFF);
+    DO_MIPS32_r(sub, 49, 0xFFFFFFFF, 0x00018000, 0xFFFE7FFF);
+    DO_MIPS32_r(sub, 50, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF);
+    DO_MIPS32_r(sub, 51, 0xFFFFFFFF, 0x00018000, 0xFFFE7FFF);
+    DO_MIPS32_r(sub, 52, 0xFFFE7FFF, 0x0003C000, 0xFFFABFFF);
+    DO_MIPS32_r(sub, 53, 0xFFFC3FFF, 0x0007E000, 0xFFF45FFF);
+    DO_MIPS32_r(sub, 54, 0xFFF81FFF, 0x000FF000, 0xFFE82FFF);
+    DO_MIPS32_r(sub, 55, 0xFFF00FFF, 0x001FF800, 0xFFD017FF);
+    DO_MIPS32_r(sub, 56, 0xFFE007FF, 0x003FFC00, 0xFFA00BFF);
+    DO_MIPS32_r(sub, 57, 0xFFC003FF, 0x007FFE00, 0xFF4005FF);
+    DO_MIPS32_r(sub, 58, 0xFF8001FF, 0x00FFFF00, 0xFE8002FF);
+    DO_MIPS32_r(sub, 59, 0xFF0000FF, 0x01FFFF80, 0xFD00017F);
+    DO_MIPS32_r(sub, 60, 0xFE00007F, 0x03FFFFC0, 0xFA0000BF);
+    DO_MIPS32_r(sub, 61, 0xFC00003F, 0x07FFFFE0, 0xF400005F);
+    DO_MIPS32_r(sub, 62, 0xF800001F, 0x0FFFFFF0, 0xE800002F);
+    DO_MIPS32_r(sub, 63, 0xF000000F, 0x1FFFFFF8, 0xD0000017);
+    DO_MIPS32_r(sub, 64, 0xE0000007, 0x3FFFFFFC, 0xA000000B);
+    DO_MIPS32_r(sub, 65, 0xC0000003, 0x7FFFFFFE, 0x40000005);
+    DO_MIPS32_r(sub, 66, 0x80000001, 0xFFFFFFFF, 0x80000002);
+    DO_MIPS32_r(sub, 67, 0x00000000, 0xFFFFFFFF, 0x00000001);
+    DO_MIPS32_r(sub, 68, 0x00000000, 0x55555555, 0xAAAAAAAB);
+    DO_MIPS32_r(sub, 69, 0x55555555, 0x55555555, 0x00000000);
+    DO_MIPS32_r(sub, 70, 0xAAAAAAAA, 0x15555555, 0x95555555);
+    DO_MIPS32_r(sub, 71, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAA);
+    DO_MIPS32_r(sub, 72, 0xAAAAAAAA, 0x00000000, 0xAAAAAAAA);
+    DO_MIPS32_r(sub, 73, 0xAAAAAAAA, 0x15555555, 0x95555555);
+    DO_MIPS32_r(sub, 74, 0xAAAAAAAA, 0xAAAAAAAA, 0x00000000);
+    DO_MIPS32_r(sub, 75, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAB);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips32/arithmatic/subu.c b/tests/tcg/mips/user/isa/mips32/arithmatic/subu.c
new file mode 100644
index 0000000000..fe1df6a71e
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips32/arithmatic/subu.c
@@ -0,0 +1,108 @@
+/*
+ * MIPS instruction test case
+ *
+ *  Copyright (c) 2022 Jiaxun Yang
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/test_utils_32.h"
+
+int main(void)
+{
+    int ret = 0;
+    int pass_count = 0;
+    int fail_count = 0;
+
+    DO_MIPS32_r(subu, 0, 0x00000000, 0x00000000, 0x00000000);
+    DO_MIPS32_r(subu, 1, 0x00000001, 0x00000001, 0x00000000);
+    DO_MIPS32_r(subu, 2, 0x00000002, 0x00000003, 0xFFFFFFFF);
+    DO_MIPS32_r(subu, 3, 0x00000004, 0x00000006, 0xFFFFFFFE);
+    DO_MIPS32_r(subu, 4, 0x00000008, 0x0000000C, 0xFFFFFFFC);
+    DO_MIPS32_r(subu, 5, 0x00000010, 0x00000018, 0xFFFFFFF8);
+    DO_MIPS32_r(subu, 6, 0x00000020, 0x00000030, 0xFFFFFFF0);
+    DO_MIPS32_r(subu, 7, 0x00000040, 0x00000060, 0xFFFFFFE0);
+    DO_MIPS32_r(subu, 8, 0x00000080, 0x000000C0, 0xFFFFFFC0);
+    DO_MIPS32_r(subu, 9, 0x00000100, 0x00000180, 0xFFFFFF80);
+    DO_MIPS32_r(subu, 10, 0x00000200, 0x00000300, 0xFFFFFF00);
+    DO_MIPS32_r(subu, 11, 0x00000400, 0x00000600, 0xFFFFFE00);
+    DO_MIPS32_r(subu, 12, 0x00000800, 0x00000C00, 0xFFFFFC00);
+    DO_MIPS32_r(subu, 13, 0x00001000, 0x00001800, 0xFFFFF800);
+    DO_MIPS32_r(subu, 14, 0x00002000, 0x00003000, 0xFFFFF000);
+    DO_MIPS32_r(subu, 15, 0x00004000, 0x00006000, 0xFFFFE000);
+    DO_MIPS32_r(subu, 16, 0x00008000, 0x0000C000, 0xFFFFC000);
+    DO_MIPS32_r(subu, 17, 0x00010000, 0x00018000, 0xFFFF8000);
+    DO_MIPS32_r(subu, 18, 0x00020000, 0x00030000, 0xFFFF0000);
+    DO_MIPS32_r(subu, 19, 0x00040000, 0x00060000, 0xFFFE0000);
+    DO_MIPS32_r(subu, 20, 0x00080000, 0x000C0000, 0xFFFC0000);
+    DO_MIPS32_r(subu, 21, 0x00100000, 0x00180000, 0xFFF80000);
+    DO_MIPS32_r(subu, 22, 0x00200000, 0x00300000, 0xFFF00000);
+    DO_MIPS32_r(subu, 23, 0x00400000, 0x00600000, 0xFFE00000);
+    DO_MIPS32_r(subu, 24, 0x00800000, 0x00C00000, 0xFFC00000);
+    DO_MIPS32_r(subu, 25, 0x01000000, 0x01800000, 0xFF800000);
+    DO_MIPS32_r(subu, 26, 0x02000000, 0x03000000, 0xFF000000);
+    DO_MIPS32_r(subu, 27, 0x04000000, 0x06000000, 0xFE000000);
+    DO_MIPS32_r(subu, 28, 0x08000000, 0x0C000000, 0xFC000000);
+    DO_MIPS32_r(subu, 29, 0x10000000, 0x18000000, 0xF8000000);
+    DO_MIPS32_r(subu, 30, 0x20000000, 0x30000000, 0xF0000000);
+    DO_MIPS32_r(subu, 31, 0x40000000, 0x60000000, 0xE0000000);
+    DO_MIPS32_r(subu, 32, 0x80000000, 0xC0000000, 0xC0000000);
+    DO_MIPS32_r(subu, 33, 0x00000000, 0x80000000, 0x80000000);
+    DO_MIPS32_r(subu, 34, 0x80000001, 0x80000001, 0x00000000);
+    DO_MIPS32_r(subu, 35, 0xC0000003, 0x40000002, 0x80000001);
+    DO_MIPS32_r(subu, 36, 0xE0000007, 0x20000004, 0xC0000003);
+    DO_MIPS32_r(subu, 37, 0xF000000F, 0x10000008, 0xE0000007);
+    DO_MIPS32_r(subu, 38, 0xF800001F, 0x08000010, 0xF000000F);
+    DO_MIPS32_r(subu, 39, 0xFC00003F, 0x04000020, 0xF800001F);
+    DO_MIPS32_r(subu, 40, 0xFE00007F, 0x02000040, 0xFC00003F);
+    DO_MIPS32_r(subu, 41, 0xFF0000FF, 0x01000080, 0xFE00007F);
+    DO_MIPS32_r(subu, 42, 0xFF8001FF, 0x00800100, 0xFF0000FF);
+    DO_MIPS32_r(subu, 43, 0xFFC003FF, 0x00400200, 0xFF8001FF);
+    DO_MIPS32_r(subu, 44, 0xFFE007FF, 0x00200400, 0xFFC003FF);
+    DO_MIPS32_r(subu, 45, 0xFFF00FFF, 0x00100800, 0xFFE007FF);
+    DO_MIPS32_r(subu, 46, 0xFFF81FFF, 0x00081000, 0xFFF00FFF);
+    DO_MIPS32_r(subu, 47, 0xFFFC3FFF, 0x00042000, 0xFFF81FFF);
+    DO_MIPS32_r(subu, 48, 0xFFFE7FFF, 0x00024000, 0xFFFC3FFF);
+    DO_MIPS32_r(subu, 49, 0xFFFFFFFF, 0x00018000, 0xFFFE7FFF);
+    DO_MIPS32_r(subu, 50, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF);
+    DO_MIPS32_r(subu, 51, 0xFFFFFFFF, 0x00018000, 0xFFFE7FFF);
+    DO_MIPS32_r(subu, 52, 0xFFFE7FFF, 0x0003C000, 0xFFFABFFF);
+    DO_MIPS32_r(subu, 53, 0xFFFC3FFF, 0x0007E000, 0xFFF45FFF);
+    DO_MIPS32_r(subu, 54, 0xFFF81FFF, 0x000FF000, 0xFFE82FFF);
+    DO_MIPS32_r(subu, 55, 0xFFF00FFF, 0x001FF800, 0xFFD017FF);
+    DO_MIPS32_r(subu, 56, 0xFFE007FF, 0x003FFC00, 0xFFA00BFF);
+    DO_MIPS32_r(subu, 57, 0xFFC003FF, 0x007FFE00, 0xFF4005FF);
+    DO_MIPS32_r(subu, 58, 0xFF8001FF, 0x00FFFF00, 0xFE8002FF);
+    DO_MIPS32_r(subu, 59, 0xFF0000FF, 0x01FFFF80, 0xFD00017F);
+    DO_MIPS32_r(subu, 60, 0xFE00007F, 0x03FFFFC0, 0xFA0000BF);
+    DO_MIPS32_r(subu, 61, 0xFC00003F, 0x07FFFFE0, 0xF400005F);
+    DO_MIPS32_r(subu, 62, 0xF800001F, 0x0FFFFFF0, 0xE800002F);
+    DO_MIPS32_r(subu, 63, 0xF000000F, 0x1FFFFFF8, 0xD0000017);
+    DO_MIPS32_r(subu, 64, 0xE0000007, 0x3FFFFFFC, 0xA000000B);
+    DO_MIPS32_r(subu, 65, 0xC0000003, 0x7FFFFFFE, 0x40000005);
+    DO_MIPS32_r(subu, 66, 0x80000001, 0xFFFFFFFF, 0x80000002);
+    DO_MIPS32_r(subu, 67, 0x00000000, 0xFFFFFFFF, 0x00000001);
+    DO_MIPS32_r(subu, 68, 0x00000000, 0x55555555, 0xAAAAAAAB);
+    DO_MIPS32_r(subu, 69, 0x55555555, 0x55555555, 0x00000000);
+    DO_MIPS32_r(subu, 70, 0xAAAAAAAA, 0x55555555, 0x55555555);
+    DO_MIPS32_r(subu, 71, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAA);
+    DO_MIPS32_r(subu, 72, 0xAAAAAAAA, 0x00000000, 0xAAAAAAAA);
+    DO_MIPS32_r(subu, 73, 0xAAAAAAAA, 0x55555555, 0x55555555);
+    DO_MIPS32_r(subu, 74, 0xAAAAAAAA, 0xAAAAAAAA, 0x00000000);
+    DO_MIPS32_r(subu, 75, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAB);
+    DO_MIPS32_r(subu, 76, 0x7FFFFFFF, 0xFFFFFFFF, 0x80000000);
+    DO_MIPS32_r(subu, 77, 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF);
+    DO_MIPS32_r(subu, 78, 0x80000000, 0x00000001, 0x7FFFFFFF);
+    DO_MIPS32_r(subu, 79, 0x80000000, 0x7FFFFFFF, 0x00000001);
+
+    printf("%s: PASS: %d, FAIL: %d\n", __FILE__, pass_count, fail_count);
+
+    if (fail_count) {
+        ret = -1;
+    }
+
+    return ret;
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/6] target/mips: Split Loongson extention translation into standalone file
  2022-10-24 15:23 [PATCH 0/6] MIPS decodetree conversion Jiaxun Yang
                   ` (2 preceding siblings ...)
  2022-10-24 15:23 ` [PATCH 3/6] tests/tcg/mips: Add mips32 arithmatic instruction test cases Jiaxun Yang
@ 2022-10-24 15:23 ` Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 5/6] target/mips: Move all tx79 instructions to decodetree Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 6/6] target/mips: Make MXU decoder standalone Jiaxun Yang
  5 siblings, 0 replies; 8+ messages in thread
From: Jiaxun Yang @ 2022-10-24 15:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: f4bug, richard.henderson, Jiaxun Yang

So we can do decodetree translation for those exts alone.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/tcg/loongson_translate.c | 1290 +++++++++++++++++++++
 target/mips/tcg/meson.build          |    1 +
 target/mips/tcg/translate.c          | 1577 ++++----------------------
 target/mips/tcg/translate.h          |    6 +
 4 files changed, 1493 insertions(+), 1381 deletions(-)
 create mode 100644 target/mips/tcg/loongson_translate.c

diff --git a/target/mips/tcg/loongson_translate.c b/target/mips/tcg/loongson_translate.c
new file mode 100644
index 0000000000..efeb1d6e28
--- /dev/null
+++ b/target/mips/tcg/loongson_translate.c
@@ -0,0 +1,1290 @@
+/*
+ * Loongson EXT and MMI translation routines.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This code is licensed under the LGPL v2.1 or later.
+ */
+
+#include "qemu/osdep.h"
+#include "tcg/tcg-op.h"
+#include "tcg/tcg-op-gvec.h"
+#include "exec/helper-gen.h"
+#include "translate.h"
+
+enum {
+    OPC_CP2      = (0x12 << 26),
+    OPC_SPECIAL2 = (0x1C << 26),
+    OPC_SPECIAL3 = (0x1F << 26),
+    OPC_LWC2     = (0x32 << 26),
+    OPC_LDC2     = (0x36 << 26),
+    OPC_SWC2     = (0x3A << 26),
+    OPC_SDC2     = (0x3E << 26),
+};
+
+/* Special2 opcodes */
+#define MASK_2F_SPECIAL2(op)    (MASK_OP_MAJOR(op) | (op & 0x3F))
+
+enum {
+    OPC_MULT_G_2F   = 0x10 | OPC_SPECIAL2,
+    OPC_DMULT_G_2F  = 0x11 | OPC_SPECIAL2,
+    OPC_MULTU_G_2F  = 0x12 | OPC_SPECIAL2,
+    OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2,
+    OPC_DIV_G_2F    = 0x14 | OPC_SPECIAL2,
+    OPC_DDIV_G_2F   = 0x15 | OPC_SPECIAL2,
+    OPC_DIVU_G_2F   = 0x16 | OPC_SPECIAL2,
+    OPC_DDIVU_G_2F  = 0x17 | OPC_SPECIAL2,
+    OPC_MOD_G_2F    = 0x1c | OPC_SPECIAL2,
+    OPC_DMOD_G_2F   = 0x1d | OPC_SPECIAL2,
+    OPC_MODU_G_2F   = 0x1e | OPC_SPECIAL2,
+    OPC_DMODU_G_2F  = 0x1f | OPC_SPECIAL2,
+};
+
+/* Special3 opcodes */
+#define MASK_2E_SPECIAL3(op)    (MASK_OP_MAJOR(op) | (op & 0x3F))
+enum {
+    /* Loongson 2E */
+    OPC_MULT_G_2E   = 0x18 | OPC_SPECIAL3,
+    OPC_MULTU_G_2E  = 0x19 | OPC_SPECIAL3,
+    OPC_DIV_G_2E    = 0x1A | OPC_SPECIAL3,
+    OPC_DIVU_G_2E   = 0x1B | OPC_SPECIAL3,
+    OPC_DMULT_G_2E  = 0x1C | OPC_SPECIAL3,
+    OPC_DMULTU_G_2E = 0x1D | OPC_SPECIAL3,
+    OPC_DDIV_G_2E   = 0x1E | OPC_SPECIAL3,
+    OPC_DDIVU_G_2E  = 0x1F | OPC_SPECIAL3,
+    OPC_MOD_G_2E    = 0x22 | OPC_SPECIAL3,
+    OPC_MODU_G_2E   = 0x23 | OPC_SPECIAL3,
+    OPC_DMOD_G_2E   = 0x26 | OPC_SPECIAL3,
+    OPC_DMODU_G_2E  = 0x27 | OPC_SPECIAL3,
+};
+
+/* Loongson EXT load/store quad word opcodes */
+#define MASK_LOONGSON_GSLSQ(op)           (MASK_OP_MAJOR(op) | (op & 0x8020))
+enum {
+    OPC_GSLQ        = 0x0020 | OPC_LWC2,
+    OPC_GSLQC1      = 0x8020 | OPC_LWC2,
+    OPC_GSSHFL      = OPC_LWC2,
+    OPC_GSSQ        = 0x0020 | OPC_SWC2,
+    OPC_GSSQC1      = 0x8020 | OPC_SWC2,
+    OPC_GSSHFS      = OPC_SWC2,
+};
+
+/* Loongson EXT shifted load/store opcodes */
+#define MASK_LOONGSON_GSSHFLS(op)         (MASK_OP_MAJOR(op) | (op & 0xc03f))
+enum {
+    OPC_GSLWLC1     = 0x4 | OPC_GSSHFL,
+    OPC_GSLWRC1     = 0x5 | OPC_GSSHFL,
+    OPC_GSLDLC1     = 0x6 | OPC_GSSHFL,
+    OPC_GSLDRC1     = 0x7 | OPC_GSSHFL,
+    OPC_GSSWLC1     = 0x4 | OPC_GSSHFS,
+    OPC_GSSWRC1     = 0x5 | OPC_GSSHFS,
+    OPC_GSSDLC1     = 0x6 | OPC_GSSHFS,
+    OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
+};
+
+/* Loongson EXT LDC2/SDC2 opcodes */
+#define MASK_LOONGSON_LSDC2(op)           (MASK_OP_MAJOR(op) | (op & 0x7))
+
+enum {
+    OPC_GSLBX      = 0x0 | OPC_LDC2,
+    OPC_GSLHX      = 0x1 | OPC_LDC2,
+    OPC_GSLWX      = 0x2 | OPC_LDC2,
+    OPC_GSLDX      = 0x3 | OPC_LDC2,
+    OPC_GSLWXC1    = 0x6 | OPC_LDC2,
+    OPC_GSLDXC1    = 0x7 | OPC_LDC2,
+    OPC_GSSBX      = 0x0 | OPC_SDC2,
+    OPC_GSSHX      = 0x1 | OPC_SDC2,
+    OPC_GSSWX      = 0x2 | OPC_SDC2,
+    OPC_GSSDX      = 0x3 | OPC_SDC2,
+    OPC_GSSWXC1    = 0x6 | OPC_SDC2,
+    OPC_GSSDXC1    = 0x7 | OPC_SDC2,
+};
+
+#define MASK_LMMI(op)    (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F))
+
+enum {
+    OPC_PADDSH      = (24 << 21) | (0x00) | OPC_CP2,
+    OPC_PADDUSH     = (25 << 21) | (0x00) | OPC_CP2,
+    OPC_PADDH       = (26 << 21) | (0x00) | OPC_CP2,
+    OPC_PADDW       = (27 << 21) | (0x00) | OPC_CP2,
+    OPC_PADDSB      = (28 << 21) | (0x00) | OPC_CP2,
+    OPC_PADDUSB     = (29 << 21) | (0x00) | OPC_CP2,
+    OPC_PADDB       = (30 << 21) | (0x00) | OPC_CP2,
+    OPC_PADDD       = (31 << 21) | (0x00) | OPC_CP2,
+
+    OPC_PSUBSH      = (24 << 21) | (0x01) | OPC_CP2,
+    OPC_PSUBUSH     = (25 << 21) | (0x01) | OPC_CP2,
+    OPC_PSUBH       = (26 << 21) | (0x01) | OPC_CP2,
+    OPC_PSUBW       = (27 << 21) | (0x01) | OPC_CP2,
+    OPC_PSUBSB      = (28 << 21) | (0x01) | OPC_CP2,
+    OPC_PSUBUSB     = (29 << 21) | (0x01) | OPC_CP2,
+    OPC_PSUBB       = (30 << 21) | (0x01) | OPC_CP2,
+    OPC_PSUBD       = (31 << 21) | (0x01) | OPC_CP2,
+
+    OPC_PSHUFH      = (24 << 21) | (0x02) | OPC_CP2,
+    OPC_PACKSSWH    = (25 << 21) | (0x02) | OPC_CP2,
+    OPC_PACKSSHB    = (26 << 21) | (0x02) | OPC_CP2,
+    OPC_PACKUSHB    = (27 << 21) | (0x02) | OPC_CP2,
+    OPC_XOR_CP2     = (28 << 21) | (0x02) | OPC_CP2,
+    OPC_NOR_CP2     = (29 << 21) | (0x02) | OPC_CP2,
+    OPC_AND_CP2     = (30 << 21) | (0x02) | OPC_CP2,
+    OPC_PANDN       = (31 << 21) | (0x02) | OPC_CP2,
+
+    OPC_PUNPCKLHW   = (24 << 21) | (0x03) | OPC_CP2,
+    OPC_PUNPCKHHW   = (25 << 21) | (0x03) | OPC_CP2,
+    OPC_PUNPCKLBH   = (26 << 21) | (0x03) | OPC_CP2,
+    OPC_PUNPCKHBH   = (27 << 21) | (0x03) | OPC_CP2,
+    OPC_PINSRH_0    = (28 << 21) | (0x03) | OPC_CP2,
+    OPC_PINSRH_1    = (29 << 21) | (0x03) | OPC_CP2,
+    OPC_PINSRH_2    = (30 << 21) | (0x03) | OPC_CP2,
+    OPC_PINSRH_3    = (31 << 21) | (0x03) | OPC_CP2,
+
+    OPC_PAVGH       = (24 << 21) | (0x08) | OPC_CP2,
+    OPC_PAVGB       = (25 << 21) | (0x08) | OPC_CP2,
+    OPC_PMAXSH      = (26 << 21) | (0x08) | OPC_CP2,
+    OPC_PMINSH      = (27 << 21) | (0x08) | OPC_CP2,
+    OPC_PMAXUB      = (28 << 21) | (0x08) | OPC_CP2,
+    OPC_PMINUB      = (29 << 21) | (0x08) | OPC_CP2,
+
+    OPC_PCMPEQW     = (24 << 21) | (0x09) | OPC_CP2,
+    OPC_PCMPGTW     = (25 << 21) | (0x09) | OPC_CP2,
+    OPC_PCMPEQH     = (26 << 21) | (0x09) | OPC_CP2,
+    OPC_PCMPGTH     = (27 << 21) | (0x09) | OPC_CP2,
+    OPC_PCMPEQB     = (28 << 21) | (0x09) | OPC_CP2,
+    OPC_PCMPGTB     = (29 << 21) | (0x09) | OPC_CP2,
+
+    OPC_PSLLW       = (24 << 21) | (0x0A) | OPC_CP2,
+    OPC_PSLLH       = (25 << 21) | (0x0A) | OPC_CP2,
+    OPC_PMULLH      = (26 << 21) | (0x0A) | OPC_CP2,
+    OPC_PMULHH      = (27 << 21) | (0x0A) | OPC_CP2,
+    OPC_PMULUW      = (28 << 21) | (0x0A) | OPC_CP2,
+    OPC_PMULHUH     = (29 << 21) | (0x0A) | OPC_CP2,
+
+    OPC_PSRLW       = (24 << 21) | (0x0B) | OPC_CP2,
+    OPC_PSRLH       = (25 << 21) | (0x0B) | OPC_CP2,
+    OPC_PSRAW       = (26 << 21) | (0x0B) | OPC_CP2,
+    OPC_PSRAH       = (27 << 21) | (0x0B) | OPC_CP2,
+    OPC_PUNPCKLWD   = (28 << 21) | (0x0B) | OPC_CP2,
+    OPC_PUNPCKHWD   = (29 << 21) | (0x0B) | OPC_CP2,
+
+    OPC_ADDU_CP2    = (24 << 21) | (0x0C) | OPC_CP2,
+    OPC_OR_CP2      = (25 << 21) | (0x0C) | OPC_CP2,
+    OPC_ADD_CP2     = (26 << 21) | (0x0C) | OPC_CP2,
+    OPC_DADD_CP2    = (27 << 21) | (0x0C) | OPC_CP2,
+    OPC_SEQU_CP2    = (28 << 21) | (0x0C) | OPC_CP2,
+    OPC_SEQ_CP2     = (29 << 21) | (0x0C) | OPC_CP2,
+
+    OPC_SUBU_CP2    = (24 << 21) | (0x0D) | OPC_CP2,
+    OPC_PASUBUB     = (25 << 21) | (0x0D) | OPC_CP2,
+    OPC_SUB_CP2     = (26 << 21) | (0x0D) | OPC_CP2,
+    OPC_DSUB_CP2    = (27 << 21) | (0x0D) | OPC_CP2,
+    OPC_SLTU_CP2    = (28 << 21) | (0x0D) | OPC_CP2,
+    OPC_SLT_CP2     = (29 << 21) | (0x0D) | OPC_CP2,
+
+    OPC_SLL_CP2     = (24 << 21) | (0x0E) | OPC_CP2,
+    OPC_DSLL_CP2    = (25 << 21) | (0x0E) | OPC_CP2,
+    OPC_PEXTRH      = (26 << 21) | (0x0E) | OPC_CP2,
+    OPC_PMADDHW     = (27 << 21) | (0x0E) | OPC_CP2,
+    OPC_SLEU_CP2    = (28 << 21) | (0x0E) | OPC_CP2,
+    OPC_SLE_CP2     = (29 << 21) | (0x0E) | OPC_CP2,
+
+    OPC_SRL_CP2     = (24 << 21) | (0x0F) | OPC_CP2,
+    OPC_DSRL_CP2    = (25 << 21) | (0x0F) | OPC_CP2,
+    OPC_SRA_CP2     = (26 << 21) | (0x0F) | OPC_CP2,
+    OPC_DSRA_CP2    = (27 << 21) | (0x0F) | OPC_CP2,
+    OPC_BIADD       = (28 << 21) | (0x0F) | OPC_CP2,
+    OPC_PMOVMSKB    = (29 << 21) | (0x0F) | OPC_CP2,
+};
+
+/* Godson integer instructions */
+static void gen_loongson_integer(DisasContext *ctx, uint32_t opc,
+                                 int rd, int rs, int rt)
+{
+    TCGv t0, t1;
+
+    if (rd == 0) {
+        /* Treat as NOP. */
+        return;
+    }
+
+    switch (opc) {
+    case OPC_MULT_G_2E:
+    case OPC_MULT_G_2F:
+    case OPC_MULTU_G_2E:
+    case OPC_MULTU_G_2F:
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT_G_2E:
+    case OPC_DMULT_G_2F:
+    case OPC_DMULTU_G_2E:
+    case OPC_DMULTU_G_2F:
+#endif
+        t0 = tcg_temp_new();
+        t1 = tcg_temp_new();
+        break;
+    default:
+        t0 = tcg_temp_local_new();
+        t1 = tcg_temp_local_new();
+        break;
+    }
+
+    gen_load_gpr(t0, rs);
+    gen_load_gpr(t1, rt);
+
+    switch (opc) {
+    case OPC_MULT_G_2E:
+    case OPC_MULT_G_2F:
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        break;
+    case OPC_MULTU_G_2E:
+    case OPC_MULTU_G_2F:
+        tcg_gen_ext32u_tl(t0, t0);
+        tcg_gen_ext32u_tl(t1, t1);
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+        break;
+    case OPC_DIV_G_2E:
+    case OPC_DIV_G_2F:
+        {
+            TCGLabel *l1 = gen_new_label();
+            TCGLabel *l2 = gen_new_label();
+            TCGLabel *l3 = gen_new_label();
+            tcg_gen_ext32s_tl(t0, t0);
+            tcg_gen_ext32s_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l3);
+            gen_set_label(l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
+            tcg_gen_mov_tl(cpu_gpr[rd], t0);
+            tcg_gen_br(l3);
+            gen_set_label(l2);
+            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            gen_set_label(l3);
+        }
+        break;
+    case OPC_DIVU_G_2E:
+    case OPC_DIVU_G_2F:
+        {
+            TCGLabel *l1 = gen_new_label();
+            TCGLabel *l2 = gen_new_label();
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            gen_set_label(l2);
+        }
+        break;
+    case OPC_MOD_G_2E:
+    case OPC_MOD_G_2F:
+        {
+            TCGLabel *l1 = gen_new_label();
+            TCGLabel *l2 = gen_new_label();
+            TCGLabel *l3 = gen_new_label();
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
+            gen_set_label(l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l3);
+            gen_set_label(l2);
+            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            gen_set_label(l3);
+        }
+        break;
+    case OPC_MODU_G_2E:
+    case OPC_MODU_G_2F:
+        {
+            TCGLabel *l1 = gen_new_label();
+            TCGLabel *l2 = gen_new_label();
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            gen_set_label(l2);
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT_G_2E:
+    case OPC_DMULT_G_2F:
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        break;
+    case OPC_DMULTU_G_2E:
+    case OPC_DMULTU_G_2F:
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        break;
+    case OPC_DDIV_G_2E:
+    case OPC_DDIV_G_2F:
+        {
+            TCGLabel *l1 = gen_new_label();
+            TCGLabel *l2 = gen_new_label();
+            TCGLabel *l3 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l3);
+            gen_set_label(l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
+            tcg_gen_mov_tl(cpu_gpr[rd], t0);
+            tcg_gen_br(l3);
+            gen_set_label(l2);
+            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
+            gen_set_label(l3);
+        }
+        break;
+    case OPC_DDIVU_G_2E:
+    case OPC_DDIVU_G_2F:
+        {
+            TCGLabel *l1 = gen_new_label();
+            TCGLabel *l2 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
+            gen_set_label(l2);
+        }
+        break;
+    case OPC_DMOD_G_2E:
+    case OPC_DMOD_G_2F:
+        {
+            TCGLabel *l1 = gen_new_label();
+            TCGLabel *l2 = gen_new_label();
+            TCGLabel *l3 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
+            gen_set_label(l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l3);
+            gen_set_label(l2);
+            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
+            gen_set_label(l3);
+        }
+        break;
+    case OPC_DMODU_G_2E:
+    case OPC_DMODU_G_2F:
+        {
+            TCGLabel *l1 = gen_new_label();
+            TCGLabel *l2 = gen_new_label();
+            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+            tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            tcg_gen_br(l2);
+            gen_set_label(l1);
+            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
+            gen_set_label(l2);
+        }
+        break;
+#endif
+    }
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+/* Loongson multimedia instructions */
+static void gen_loongson_multimedia(DisasContext *ctx, int rd, int rs, int rt)
+{
+    uint32_t opc, shift_max;
+    TCGv_i64 t0, t1;
+    TCGCond cond;
+
+    opc = MASK_LMMI(ctx->opcode);
+    switch (opc) {
+    case OPC_ADD_CP2:
+    case OPC_SUB_CP2:
+    case OPC_DADD_CP2:
+    case OPC_DSUB_CP2:
+        t0 = tcg_temp_local_new_i64();
+        t1 = tcg_temp_local_new_i64();
+        break;
+    default:
+        t0 = tcg_temp_new_i64();
+        t1 = tcg_temp_new_i64();
+        break;
+    }
+
+    check_cp1_enabled(ctx);
+    gen_load_fpr64(ctx, t0, rs);
+    gen_load_fpr64(ctx, t1, rt);
+
+    switch (opc) {
+    case OPC_PADDSH:
+        gen_helper_paddsh(t0, t0, t1);
+        break;
+    case OPC_PADDUSH:
+        gen_helper_paddush(t0, t0, t1);
+        break;
+    case OPC_PADDH:
+        gen_helper_paddh(t0, t0, t1);
+        break;
+    case OPC_PADDW:
+        gen_helper_paddw(t0, t0, t1);
+        break;
+    case OPC_PADDSB:
+        gen_helper_paddsb(t0, t0, t1);
+        break;
+    case OPC_PADDUSB:
+        gen_helper_paddusb(t0, t0, t1);
+        break;
+    case OPC_PADDB:
+        gen_helper_paddb(t0, t0, t1);
+        break;
+
+    case OPC_PSUBSH:
+        gen_helper_psubsh(t0, t0, t1);
+        break;
+    case OPC_PSUBUSH:
+        gen_helper_psubush(t0, t0, t1);
+        break;
+    case OPC_PSUBH:
+        gen_helper_psubh(t0, t0, t1);
+        break;
+    case OPC_PSUBW:
+        gen_helper_psubw(t0, t0, t1);
+        break;
+    case OPC_PSUBSB:
+        gen_helper_psubsb(t0, t0, t1);
+        break;
+    case OPC_PSUBUSB:
+        gen_helper_psubusb(t0, t0, t1);
+        break;
+    case OPC_PSUBB:
+        gen_helper_psubb(t0, t0, t1);
+        break;
+
+    case OPC_PSHUFH:
+        gen_helper_pshufh(t0, t0, t1);
+        break;
+    case OPC_PACKSSWH:
+        gen_helper_packsswh(t0, t0, t1);
+        break;
+    case OPC_PACKSSHB:
+        gen_helper_packsshb(t0, t0, t1);
+        break;
+    case OPC_PACKUSHB:
+        gen_helper_packushb(t0, t0, t1);
+        break;
+
+    case OPC_PUNPCKLHW:
+        gen_helper_punpcklhw(t0, t0, t1);
+        break;
+    case OPC_PUNPCKHHW:
+        gen_helper_punpckhhw(t0, t0, t1);
+        break;
+    case OPC_PUNPCKLBH:
+        gen_helper_punpcklbh(t0, t0, t1);
+        break;
+    case OPC_PUNPCKHBH:
+        gen_helper_punpckhbh(t0, t0, t1);
+        break;
+    case OPC_PUNPCKLWD:
+        gen_helper_punpcklwd(t0, t0, t1);
+        break;
+    case OPC_PUNPCKHWD:
+        gen_helper_punpckhwd(t0, t0, t1);
+        break;
+
+    case OPC_PAVGH:
+        gen_helper_pavgh(t0, t0, t1);
+        break;
+    case OPC_PAVGB:
+        gen_helper_pavgb(t0, t0, t1);
+        break;
+    case OPC_PMAXSH:
+        gen_helper_pmaxsh(t0, t0, t1);
+        break;
+    case OPC_PMINSH:
+        gen_helper_pminsh(t0, t0, t1);
+        break;
+    case OPC_PMAXUB:
+        gen_helper_pmaxub(t0, t0, t1);
+        break;
+    case OPC_PMINUB:
+        gen_helper_pminub(t0, t0, t1);
+        break;
+
+    case OPC_PCMPEQW:
+        gen_helper_pcmpeqw(t0, t0, t1);
+        break;
+    case OPC_PCMPGTW:
+        gen_helper_pcmpgtw(t0, t0, t1);
+        break;
+    case OPC_PCMPEQH:
+        gen_helper_pcmpeqh(t0, t0, t1);
+        break;
+    case OPC_PCMPGTH:
+        gen_helper_pcmpgth(t0, t0, t1);
+        break;
+    case OPC_PCMPEQB:
+        gen_helper_pcmpeqb(t0, t0, t1);
+        break;
+    case OPC_PCMPGTB:
+        gen_helper_pcmpgtb(t0, t0, t1);
+        break;
+
+    case OPC_PSLLW:
+        gen_helper_psllw(t0, t0, t1);
+        break;
+    case OPC_PSLLH:
+        gen_helper_psllh(t0, t0, t1);
+        break;
+    case OPC_PSRLW:
+        gen_helper_psrlw(t0, t0, t1);
+        break;
+    case OPC_PSRLH:
+        gen_helper_psrlh(t0, t0, t1);
+        break;
+    case OPC_PSRAW:
+        gen_helper_psraw(t0, t0, t1);
+        break;
+    case OPC_PSRAH:
+        gen_helper_psrah(t0, t0, t1);
+        break;
+
+    case OPC_PMULLH:
+        gen_helper_pmullh(t0, t0, t1);
+        break;
+    case OPC_PMULHH:
+        gen_helper_pmulhh(t0, t0, t1);
+        break;
+    case OPC_PMULHUH:
+        gen_helper_pmulhuh(t0, t0, t1);
+        break;
+    case OPC_PMADDHW:
+        gen_helper_pmaddhw(t0, t0, t1);
+        break;
+
+    case OPC_PASUBUB:
+        gen_helper_pasubub(t0, t0, t1);
+        break;
+    case OPC_BIADD:
+        gen_helper_biadd(t0, t0);
+        break;
+    case OPC_PMOVMSKB:
+        gen_helper_pmovmskb(t0, t0);
+        break;
+
+    case OPC_PADDD:
+        tcg_gen_add_i64(t0, t0, t1);
+        break;
+    case OPC_PSUBD:
+        tcg_gen_sub_i64(t0, t0, t1);
+        break;
+    case OPC_XOR_CP2:
+        tcg_gen_xor_i64(t0, t0, t1);
+        break;
+    case OPC_NOR_CP2:
+        tcg_gen_nor_i64(t0, t0, t1);
+        break;
+    case OPC_AND_CP2:
+        tcg_gen_and_i64(t0, t0, t1);
+        break;
+    case OPC_OR_CP2:
+        tcg_gen_or_i64(t0, t0, t1);
+        break;
+
+    case OPC_PANDN:
+        tcg_gen_andc_i64(t0, t1, t0);
+        break;
+
+    case OPC_PINSRH_0:
+        tcg_gen_deposit_i64(t0, t0, t1, 0, 16);
+        break;
+    case OPC_PINSRH_1:
+        tcg_gen_deposit_i64(t0, t0, t1, 16, 16);
+        break;
+    case OPC_PINSRH_2:
+        tcg_gen_deposit_i64(t0, t0, t1, 32, 16);
+        break;
+    case OPC_PINSRH_3:
+        tcg_gen_deposit_i64(t0, t0, t1, 48, 16);
+        break;
+
+    case OPC_PEXTRH:
+        tcg_gen_andi_i64(t1, t1, 3);
+        tcg_gen_shli_i64(t1, t1, 4);
+        tcg_gen_shr_i64(t0, t0, t1);
+        tcg_gen_ext16u_i64(t0, t0);
+        break;
+
+    case OPC_ADDU_CP2:
+        tcg_gen_add_i64(t0, t0, t1);
+        tcg_gen_ext32s_i64(t0, t0);
+        break;
+    case OPC_SUBU_CP2:
+        tcg_gen_sub_i64(t0, t0, t1);
+        tcg_gen_ext32s_i64(t0, t0);
+        break;
+
+    case OPC_SLL_CP2:
+        shift_max = 32;
+        goto do_shift;
+    case OPC_SRL_CP2:
+        shift_max = 32;
+        goto do_shift;
+    case OPC_SRA_CP2:
+        shift_max = 32;
+        goto do_shift;
+    case OPC_DSLL_CP2:
+        shift_max = 64;
+        goto do_shift;
+    case OPC_DSRL_CP2:
+        shift_max = 64;
+        goto do_shift;
+    case OPC_DSRA_CP2:
+        shift_max = 64;
+        goto do_shift;
+    do_shift:
+        /* Make sure shift count isn't TCG undefined behaviour.  */
+        tcg_gen_andi_i64(t1, t1, shift_max - 1);
+
+        switch (opc) {
+        case OPC_SLL_CP2:
+        case OPC_DSLL_CP2:
+            tcg_gen_shl_i64(t0, t0, t1);
+            break;
+        case OPC_SRA_CP2:
+        case OPC_DSRA_CP2:
+            /*
+             * Since SRA is UndefinedResult without sign-extended inputs,
+             * we can treat SRA and DSRA the same.
+             */
+            tcg_gen_sar_i64(t0, t0, t1);
+            break;
+        case OPC_SRL_CP2:
+            /* We want to shift in zeros for SRL; zero-extend first.  */
+            tcg_gen_ext32u_i64(t0, t0);
+            /* FALLTHRU */
+        case OPC_DSRL_CP2:
+            tcg_gen_shr_i64(t0, t0, t1);
+            break;
+        }
+
+        if (shift_max == 32) {
+            tcg_gen_ext32s_i64(t0, t0);
+        }
+
+        /* Shifts larger than MAX produce zero.  */
+        tcg_gen_setcondi_i64(TCG_COND_LTU, t1, t1, shift_max);
+        tcg_gen_neg_i64(t1, t1);
+        tcg_gen_and_i64(t0, t0, t1);
+        break;
+
+    case OPC_ADD_CP2:
+    case OPC_DADD_CP2:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGLabel *lab = gen_new_label();
+
+            tcg_gen_mov_i64(t2, t0);
+            tcg_gen_add_i64(t0, t1, t2);
+            if (opc == OPC_ADD_CP2) {
+                tcg_gen_ext32s_i64(t0, t0);
+            }
+            tcg_gen_xor_i64(t1, t1, t2);
+            tcg_gen_xor_i64(t2, t2, t0);
+            tcg_gen_andc_i64(t1, t2, t1);
+            tcg_temp_free_i64(t2);
+            tcg_gen_brcondi_i64(TCG_COND_GE, t1, 0, lab);
+            generate_exception(ctx, EXCP_OVERFLOW);
+            gen_set_label(lab);
+            break;
+        }
+
+    case OPC_SUB_CP2:
+    case OPC_DSUB_CP2:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGLabel *lab = gen_new_label();
+
+            tcg_gen_mov_i64(t2, t0);
+            tcg_gen_sub_i64(t0, t1, t2);
+            if (opc == OPC_SUB_CP2) {
+                tcg_gen_ext32s_i64(t0, t0);
+            }
+            tcg_gen_xor_i64(t1, t1, t2);
+            tcg_gen_xor_i64(t2, t2, t0);
+            tcg_gen_and_i64(t1, t1, t2);
+            tcg_temp_free_i64(t2);
+            tcg_gen_brcondi_i64(TCG_COND_GE, t1, 0, lab);
+            generate_exception(ctx, EXCP_OVERFLOW);
+            gen_set_label(lab);
+            break;
+        }
+
+    case OPC_PMULUW:
+        tcg_gen_ext32u_i64(t0, t0);
+        tcg_gen_ext32u_i64(t1, t1);
+        tcg_gen_mul_i64(t0, t0, t1);
+        break;
+
+    case OPC_SEQU_CP2:
+    case OPC_SEQ_CP2:
+        cond = TCG_COND_EQ;
+        goto do_cc_cond;
+        break;
+    case OPC_SLTU_CP2:
+        cond = TCG_COND_LTU;
+        goto do_cc_cond;
+        break;
+    case OPC_SLT_CP2:
+        cond = TCG_COND_LT;
+        goto do_cc_cond;
+        break;
+    case OPC_SLEU_CP2:
+        cond = TCG_COND_LEU;
+        goto do_cc_cond;
+        break;
+    case OPC_SLE_CP2:
+        cond = TCG_COND_LE;
+    do_cc_cond:
+        {
+            int cc = (ctx->opcode >> 8) & 0x7;
+            TCGv_i64 t64 = tcg_temp_new_i64();
+            TCGv_i32 t32 = tcg_temp_new_i32();
+
+            tcg_gen_setcond_i64(cond, t64, t0, t1);
+            tcg_gen_extrl_i64_i32(t32, t64);
+            tcg_gen_deposit_i32(fpu_fcr31, fpu_fcr31, t32,
+                                get_fp_bit(cc), 1);
+
+            tcg_temp_free_i32(t32);
+            tcg_temp_free_i64(t64);
+        }
+        goto no_rd;
+        break;
+    default:
+        MIPS_INVAL("loongson_cp2");
+        gen_reserved_instruction(ctx);
+        return;
+    }
+
+    gen_store_fpr64(ctx, t0, rd);
+
+no_rd:
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+static void gen_loongson_lswc2(DisasContext *ctx, int rt,
+                               int rs, int rd)
+{
+    TCGv t0, t1, t2;
+    TCGv_i32 fp0;
+#if defined(TARGET_MIPS64)
+    int lsq_rt1 = ctx->opcode & 0x1f;
+    int lsq_offset = sextract32(ctx->opcode, 6, 9) << 4;
+#endif
+    int shf_offset = sextract32(ctx->opcode, 6, 8);
+
+    t0 = tcg_temp_new();
+
+    switch (MASK_LOONGSON_GSLSQ(ctx->opcode)) {
+#if defined(TARGET_MIPS64)
+    case OPC_GSLQ:
+        t1 = tcg_temp_new();
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        gen_store_gpr(t1, rt);
+        gen_store_gpr(t0, lsq_rt1);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSLQC1:
+        check_cp1_enabled(ctx);
+        t1 = tcg_temp_new();
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        gen_store_fpr64(ctx, t1, rt);
+        gen_store_fpr64(ctx, t0, lsq_rt1);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSSQ:
+        t1 = tcg_temp_new();
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
+        gen_load_gpr(t1, lsq_rt1);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSSQC1:
+        check_cp1_enabled(ctx);
+        t1 = tcg_temp_new();
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        gen_load_fpr64(ctx, t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
+        gen_load_fpr64(ctx, t1, lsq_rt1);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+#endif
+    case OPC_GSSHFL:
+        switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
+        case OPC_GSLWLC1:
+            check_cp1_enabled(ctx);
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            t1 = tcg_temp_new();
+            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+            tcg_gen_andi_tl(t1, t0, 3);
+            if (!cpu_is_bigendian(ctx)) {
+                tcg_gen_xori_tl(t1, t1, 3);
+            }
+            tcg_gen_shli_tl(t1, t1, 3);
+            tcg_gen_andi_tl(t0, t0, ~3);
+            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
+            tcg_gen_shl_tl(t0, t0, t1);
+            t2 = tcg_const_tl(-1);
+            tcg_gen_shl_tl(t2, t2, t1);
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(ctx, fp0, rt);
+            tcg_gen_ext_i32_tl(t1, fp0);
+            tcg_gen_andc_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+#if defined(TARGET_MIPS64)
+            tcg_gen_extrl_i64_i32(fp0, t0);
+#else
+            tcg_gen_ext32s_tl(fp0, t0);
+#endif
+            gen_store_fpr32(ctx, fp0, rt);
+            tcg_temp_free_i32(fp0);
+            break;
+        case OPC_GSLWRC1:
+            check_cp1_enabled(ctx);
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            t1 = tcg_temp_new();
+            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+            tcg_gen_andi_tl(t1, t0, 3);
+            if (cpu_is_bigendian(ctx)) {
+                tcg_gen_xori_tl(t1, t1, 3);
+            }
+            tcg_gen_shli_tl(t1, t1, 3);
+            tcg_gen_andi_tl(t0, t0, ~3);
+            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
+            tcg_gen_shr_tl(t0, t0, t1);
+            tcg_gen_xori_tl(t1, t1, 31);
+            t2 = tcg_const_tl(0xfffffffeull);
+            tcg_gen_shl_tl(t2, t2, t1);
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(ctx, fp0, rt);
+            tcg_gen_ext_i32_tl(t1, fp0);
+            tcg_gen_and_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+#if defined(TARGET_MIPS64)
+            tcg_gen_extrl_i64_i32(fp0, t0);
+#else
+            tcg_gen_ext32s_tl(fp0, t0);
+#endif
+            gen_store_fpr32(ctx, fp0, rt);
+            tcg_temp_free_i32(fp0);
+            break;
+#if defined(TARGET_MIPS64)
+        case OPC_GSLDLC1:
+            check_cp1_enabled(ctx);
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            t1 = tcg_temp_new();
+            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+            tcg_gen_andi_tl(t1, t0, 7);
+            if (!cpu_is_bigendian(ctx)) {
+                tcg_gen_xori_tl(t1, t1, 7);
+            }
+            tcg_gen_shli_tl(t1, t1, 3);
+            tcg_gen_andi_tl(t0, t0, ~7);
+            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ);
+            tcg_gen_shl_tl(t0, t0, t1);
+            t2 = tcg_const_tl(-1);
+            tcg_gen_shl_tl(t2, t2, t1);
+            gen_load_fpr64(ctx, t1, rt);
+            tcg_gen_andc_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+            gen_store_fpr64(ctx, t0, rt);
+            break;
+        case OPC_GSLDRC1:
+            check_cp1_enabled(ctx);
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            t1 = tcg_temp_new();
+            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+            tcg_gen_andi_tl(t1, t0, 7);
+            if (cpu_is_bigendian(ctx)) {
+                tcg_gen_xori_tl(t1, t1, 7);
+            }
+            tcg_gen_shli_tl(t1, t1, 3);
+            tcg_gen_andi_tl(t0, t0, ~7);
+            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ);
+            tcg_gen_shr_tl(t0, t0, t1);
+            tcg_gen_xori_tl(t1, t1, 63);
+            t2 = tcg_const_tl(0xfffffffffffffffeull);
+            tcg_gen_shl_tl(t2, t2, t1);
+            gen_load_fpr64(ctx, t1, rt);
+            tcg_gen_and_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+            gen_store_fpr64(ctx, t0, rt);
+            break;
+#endif
+        default:
+            MIPS_INVAL("loongson_gsshfl");
+            gen_reserved_instruction(ctx);
+            break;
+        }
+        break;
+    case OPC_GSSHFS:
+        switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
+        case OPC_GSSWLC1:
+            check_cp1_enabled(ctx);
+            t1 = tcg_temp_new();
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(ctx, fp0, rt);
+            tcg_gen_ext_i32_tl(t1, fp0);
+            gen_helper_0e2i(swl, t1, t0, ctx->mem_idx);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free(t1);
+            break;
+        case OPC_GSSWRC1:
+            check_cp1_enabled(ctx);
+            t1 = tcg_temp_new();
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(ctx, fp0, rt);
+            tcg_gen_ext_i32_tl(t1, fp0);
+            gen_helper_0e2i(swr, t1, t0, ctx->mem_idx);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free(t1);
+            break;
+#if defined(TARGET_MIPS64)
+        case OPC_GSSDLC1:
+            check_cp1_enabled(ctx);
+            t1 = tcg_temp_new();
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            gen_load_fpr64(ctx, t1, rt);
+            gen_helper_0e2i(sdl, t1, t0, ctx->mem_idx);
+            tcg_temp_free(t1);
+            break;
+        case OPC_GSSDRC1:
+            check_cp1_enabled(ctx);
+            t1 = tcg_temp_new();
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            gen_load_fpr64(ctx, t1, rt);
+            gen_helper_0e2i(sdr, t1, t0, ctx->mem_idx);
+            tcg_temp_free(t1);
+            break;
+#endif
+        default:
+            MIPS_INVAL("loongson_gsshfs");
+            gen_reserved_instruction(ctx);
+            break;
+        }
+        break;
+    default:
+        MIPS_INVAL("loongson_gslsq");
+        gen_reserved_instruction(ctx);
+        break;
+    }
+    tcg_temp_free(t0);
+}
+
+/* Loongson EXT LDC2/SDC2 */
+static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
+                               int rs, int rd)
+{
+    int offset = sextract32(ctx->opcode, 3, 8);
+    uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
+    TCGv t0, t1;
+    TCGv_i32 fp0;
+
+    /* Pre-conditions */
+    switch (opc) {
+    case OPC_GSLBX:
+    case OPC_GSLHX:
+    case OPC_GSLWX:
+    case OPC_GSLDX:
+        /* prefetch, implement as NOP */
+        if (rt == 0) {
+            return;
+        }
+        break;
+    case OPC_GSSBX:
+    case OPC_GSSHX:
+    case OPC_GSSWX:
+    case OPC_GSSDX:
+        break;
+    case OPC_GSLWXC1:
+#if defined(TARGET_MIPS64)
+    case OPC_GSLDXC1:
+#endif
+        check_cp1_enabled(ctx);
+        /* prefetch, implement as NOP */
+        if (rt == 0) {
+            return;
+        }
+        break;
+    case OPC_GSSWXC1:
+#if defined(TARGET_MIPS64)
+    case OPC_GSSDXC1:
+#endif
+        check_cp1_enabled(ctx);
+        break;
+    default:
+        MIPS_INVAL("loongson_lsdc2");
+        gen_reserved_instruction(ctx);
+        return;
+        break;
+    }
+
+    t0 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, rs, offset);
+    gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+
+    switch (opc) {
+    case OPC_GSLBX:
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
+        gen_store_gpr(t0, rt);
+        break;
+    case OPC_GSLHX:
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
+                           ctx->default_tcg_memop_mask);
+        gen_store_gpr(t0, rt);
+        break;
+    case OPC_GSLWX:
+        gen_base_offset_addr(ctx, t0, rs, offset);
+        if (rd) {
+            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+        }
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL |
+                           ctx->default_tcg_memop_mask);
+        gen_store_gpr(t0, rt);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_GSLDX:
+        gen_base_offset_addr(ctx, t0, rs, offset);
+        if (rd) {
+            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+        }
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        gen_store_gpr(t0, rt);
+        break;
+#endif
+    case OPC_GSLWXC1:
+        gen_base_offset_addr(ctx, t0, rs, offset);
+        if (rd) {
+            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+        }
+        fp0 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL |
+                            ctx->default_tcg_memop_mask);
+        gen_store_fpr32(ctx, fp0, rt);
+        tcg_temp_free_i32(fp0);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_GSLDXC1:
+        gen_base_offset_addr(ctx, t0, rs, offset);
+        if (rd) {
+            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+        }
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        gen_store_fpr64(ctx, t0, rt);
+        break;
+#endif
+    case OPC_GSSBX:
+        t1 = tcg_temp_new();
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_SB);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSSHX:
+        t1 = tcg_temp_new();
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
+                           ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSSWX:
+        t1 = tcg_temp_new();
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+                           ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_GSSDX:
+        t1 = tcg_temp_new();
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+                           ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+#endif
+    case OPC_GSSWXC1:
+        fp0 = tcg_temp_new_i32();
+        gen_load_fpr32(ctx, fp0, rt);
+        tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free_i32(fp0);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_GSSDXC1:
+        t1 = tcg_temp_new();
+        gen_load_fpr64(ctx, t1, rt);
+        tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEUQ |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+#endif
+    default:
+        break;
+    }
+
+    tcg_temp_free(t0);
+}
+
+bool decode_ext_loongson2e(DisasContext *ctx, uint32_t insn)
+{
+    int rs, rt, rd;
+    uint32_t op;
+
+    op = MASK_2E_SPECIAL3(insn);
+    rs = (insn >> 21) & 0x1f;
+    rt = (insn >> 16) & 0x1f;
+    rd = (insn >> 11) & 0x1f;
+
+    switch (op) {
+    case OPC_DIV_G_2E:
+    case OPC_DIVU_G_2E:
+    case OPC_MOD_G_2E:
+    case OPC_MODU_G_2E:
+    case OPC_MULT_G_2E:
+    case OPC_MULTU_G_2E:
+        gen_loongson_integer(ctx, op, rd, rs, rt);
+        return true;
+#if defined(TARGET_MIPS64)
+    case OPC_DDIV_G_2E:
+    case OPC_DDIVU_G_2E:
+    case OPC_DMULT_G_2E:
+    case OPC_DMULTU_G_2E:
+    case OPC_DMOD_G_2E:
+    case OPC_DMODU_G_2E:
+        gen_loongson_integer(ctx, op, rd, rs, rt);
+        return true;
+#endif
+    default:
+        return false;
+    }
+}
+
+bool decode_ext_loongson2f(DisasContext *ctx, uint32_t insn)
+{
+    int rs, rt, rd;
+    uint32_t op;
+
+    op = MASK_2F_SPECIAL2(insn);
+    rs = (insn >> 21) & 0x1f;
+    rt = (insn >> 16) & 0x1f;
+    rd = (insn >> 11) & 0x1f;
+
+    switch (op) {
+    case OPC_DIV_G_2F:
+    case OPC_DIVU_G_2F:
+    case OPC_MULT_G_2F:
+    case OPC_MULTU_G_2F:
+    case OPC_MOD_G_2F:
+    case OPC_MODU_G_2F:
+        gen_loongson_integer(ctx, op, rd, rs, rt);
+        return true;
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT_G_2F:
+    case OPC_DMULTU_G_2F:
+    case OPC_DDIV_G_2F:
+    case OPC_DDIVU_G_2F:
+    case OPC_DMOD_G_2F:
+    case OPC_DMODU_G_2F:
+        gen_loongson_integer(ctx, op, rd, rs, rt);
+        return true;
+#endif
+    default:
+        return false;
+    }
+}
+
+bool decode_ase_lext(DisasContext *ctx, uint32_t insn)
+{
+    int rs, rt, rd;
+    uint32_t op;
+
+    op = MASK_OP_MAJOR(insn);
+    rs = (insn >> 21) & 0x1f;
+    rt = (insn >> 16) & 0x1f;
+    rd = (insn >> 11) & 0x1f;
+
+    switch (op) {
+    case OPC_SPECIAL2:
+        /* LEXT inherits Loongson2F integer extensions */
+        return decode_ext_loongson2f(ctx, insn);
+    case OPC_LWC2:
+    case OPC_SWC2:
+        gen_loongson_lswc2(ctx, rt, rs, rd);
+        return true;
+    case OPC_LDC2:
+    case OPC_SDC2:
+        gen_loongson_lsdc2(ctx, rt, rs, rd);
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool decode_ase_lmmi(DisasContext *ctx, uint32_t insn)
+{
+    int sa, rt, rd;
+    uint32_t op;
+
+    op = MASK_OP_MAJOR(insn);
+    rt = (insn >> 16) & 0x1f;
+    rd = (insn >> 11) & 0x1f;
+    sa = (insn >> 6) & 0x1f;
+
+    switch (op) {
+    case OPC_CP2:
+        gen_loongson_multimedia(ctx, sa, rd, rt);
+        return true;
+    default:
+        return false;
+    }
+}
diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build
index 7a27fe93e0..a615cd81b6 100644
--- a/target/mips/tcg/meson.build
+++ b/target/mips/tcg/meson.build
@@ -14,6 +14,7 @@ mips_ss.add(files(
   'fpu_helper.c',
   'ldst_helper.c',
   'lmmi_helper.c',
+  'loongson_translate.c',
   'msa_helper.c',
   'msa_translate.c',
   'op_helper.c',
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index bcb267e6bd..d398b2f44d 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -332,19 +332,6 @@ enum {
     OPC_MUL      = 0x02 | OPC_SPECIAL2,
     OPC_MSUB     = 0x04 | OPC_SPECIAL2,
     OPC_MSUBU    = 0x05 | OPC_SPECIAL2,
-    /* Loongson 2F */
-    OPC_MULT_G_2F   = 0x10 | OPC_SPECIAL2,
-    OPC_DMULT_G_2F  = 0x11 | OPC_SPECIAL2,
-    OPC_MULTU_G_2F  = 0x12 | OPC_SPECIAL2,
-    OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2,
-    OPC_DIV_G_2F    = 0x14 | OPC_SPECIAL2,
-    OPC_DDIV_G_2F   = 0x15 | OPC_SPECIAL2,
-    OPC_DIVU_G_2F   = 0x16 | OPC_SPECIAL2,
-    OPC_DDIVU_G_2F  = 0x17 | OPC_SPECIAL2,
-    OPC_MOD_G_2F    = 0x1c | OPC_SPECIAL2,
-    OPC_DMOD_G_2F   = 0x1d | OPC_SPECIAL2,
-    OPC_MODU_G_2F   = 0x1e | OPC_SPECIAL2,
-    OPC_DMODU_G_2F  = 0x1f | OPC_SPECIAL2,
     /* Misc */
     OPC_CLZ      = 0x20 | OPC_SPECIAL2,
     OPC_CLO      = 0x21 | OPC_SPECIAL2,
@@ -373,20 +360,6 @@ enum {
     OPC_RDHWR    = 0x3B | OPC_SPECIAL3,
     OPC_GINV     = 0x3D | OPC_SPECIAL3,
 
-    /* Loongson 2E */
-    OPC_MULT_G_2E   = 0x18 | OPC_SPECIAL3,
-    OPC_MULTU_G_2E  = 0x19 | OPC_SPECIAL3,
-    OPC_DIV_G_2E    = 0x1A | OPC_SPECIAL3,
-    OPC_DIVU_G_2E   = 0x1B | OPC_SPECIAL3,
-    OPC_DMULT_G_2E  = 0x1C | OPC_SPECIAL3,
-    OPC_DMULTU_G_2E = 0x1D | OPC_SPECIAL3,
-    OPC_DDIV_G_2E   = 0x1E | OPC_SPECIAL3,
-    OPC_DDIVU_G_2E  = 0x1F | OPC_SPECIAL3,
-    OPC_MOD_G_2E    = 0x22 | OPC_SPECIAL3,
-    OPC_MODU_G_2E   = 0x23 | OPC_SPECIAL3,
-    OPC_DMOD_G_2E   = 0x26 | OPC_SPECIAL3,
-    OPC_DMODU_G_2E  = 0x27 | OPC_SPECIAL3,
-
     /* MIPS DSP Load */
     OPC_LX_DSP         = 0x0A | OPC_SPECIAL3,
     /* MIPS DSP Arithmetic */
@@ -394,8 +367,7 @@ enum {
     OPC_ADDU_OB_DSP    = 0x14 | OPC_SPECIAL3,
     OPC_ABSQ_S_PH_DSP  = 0x12 | OPC_SPECIAL3,
     OPC_ABSQ_S_QH_DSP  = 0x16 | OPC_SPECIAL3,
-    /* OPC_ADDUH_QB_DSP is same as OPC_MULT_G_2E.  */
-    /* OPC_ADDUH_QB_DSP   = 0x18 | OPC_SPECIAL3,  */
+    OPC_ADDUH_QB_DSP   = 0x18 | OPC_SPECIAL3,
     OPC_CMPU_EQ_QB_DSP = 0x11 | OPC_SPECIAL3,
     OPC_CMPU_EQ_OB_DSP = 0x15 | OPC_SPECIAL3,
     /* MIPS DSP GPR-Based Shift Sub-class */
@@ -443,48 +415,6 @@ enum {
     R6_OPC_SCD         = 0x27 | OPC_SPECIAL3,
 };
 
-/* Loongson EXT load/store quad word opcodes */
-#define MASK_LOONGSON_GSLSQ(op)           (MASK_OP_MAJOR(op) | (op & 0x8020))
-enum {
-    OPC_GSLQ        = 0x0020 | OPC_LWC2,
-    OPC_GSLQC1      = 0x8020 | OPC_LWC2,
-    OPC_GSSHFL      = OPC_LWC2,
-    OPC_GSSQ        = 0x0020 | OPC_SWC2,
-    OPC_GSSQC1      = 0x8020 | OPC_SWC2,
-    OPC_GSSHFS      = OPC_SWC2,
-};
-
-/* Loongson EXT shifted load/store opcodes */
-#define MASK_LOONGSON_GSSHFLS(op)         (MASK_OP_MAJOR(op) | (op & 0xc03f))
-enum {
-    OPC_GSLWLC1     = 0x4 | OPC_GSSHFL,
-    OPC_GSLWRC1     = 0x5 | OPC_GSSHFL,
-    OPC_GSLDLC1     = 0x6 | OPC_GSSHFL,
-    OPC_GSLDRC1     = 0x7 | OPC_GSSHFL,
-    OPC_GSSWLC1     = 0x4 | OPC_GSSHFS,
-    OPC_GSSWRC1     = 0x5 | OPC_GSSHFS,
-    OPC_GSSDLC1     = 0x6 | OPC_GSSHFS,
-    OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
-};
-
-/* Loongson EXT LDC2/SDC2 opcodes */
-#define MASK_LOONGSON_LSDC2(op)           (MASK_OP_MAJOR(op) | (op & 0x7))
-
-enum {
-    OPC_GSLBX      = 0x0 | OPC_LDC2,
-    OPC_GSLHX      = 0x1 | OPC_LDC2,
-    OPC_GSLWX      = 0x2 | OPC_LDC2,
-    OPC_GSLDX      = 0x3 | OPC_LDC2,
-    OPC_GSLWXC1    = 0x6 | OPC_LDC2,
-    OPC_GSLDXC1    = 0x7 | OPC_LDC2,
-    OPC_GSSBX      = 0x0 | OPC_SDC2,
-    OPC_GSSHX      = 0x1 | OPC_SDC2,
-    OPC_GSSWX      = 0x2 | OPC_SDC2,
-    OPC_GSSDX      = 0x3 | OPC_SDC2,
-    OPC_GSSWXC1    = 0x6 | OPC_SDC2,
-    OPC_GSSDXC1    = 0x7 | OPC_SDC2,
-};
-
 /* BSHFL opcodes */
 #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
 
@@ -561,7 +491,6 @@ enum {
     OPC_MULQ_S_PH      = (0x1E << 6) | OPC_ADDU_QB_DSP,
 };
 
-#define OPC_ADDUH_QB_DSP OPC_MULT_G_2E
 #define MASK_ADDUH_QB(op)           (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
 enum {
     /* MIPS DSP Arithmetic Sub-class */
@@ -1002,103 +931,6 @@ enum {
     OPC_BC2NEZ  = (0x0D << 21) | OPC_CP2,
 };
 
-#define MASK_LMMI(op)    (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F))
-
-enum {
-    OPC_PADDSH      = (24 << 21) | (0x00) | OPC_CP2,
-    OPC_PADDUSH     = (25 << 21) | (0x00) | OPC_CP2,
-    OPC_PADDH       = (26 << 21) | (0x00) | OPC_CP2,
-    OPC_PADDW       = (27 << 21) | (0x00) | OPC_CP2,
-    OPC_PADDSB      = (28 << 21) | (0x00) | OPC_CP2,
-    OPC_PADDUSB     = (29 << 21) | (0x00) | OPC_CP2,
-    OPC_PADDB       = (30 << 21) | (0x00) | OPC_CP2,
-    OPC_PADDD       = (31 << 21) | (0x00) | OPC_CP2,
-
-    OPC_PSUBSH      = (24 << 21) | (0x01) | OPC_CP2,
-    OPC_PSUBUSH     = (25 << 21) | (0x01) | OPC_CP2,
-    OPC_PSUBH       = (26 << 21) | (0x01) | OPC_CP2,
-    OPC_PSUBW       = (27 << 21) | (0x01) | OPC_CP2,
-    OPC_PSUBSB      = (28 << 21) | (0x01) | OPC_CP2,
-    OPC_PSUBUSB     = (29 << 21) | (0x01) | OPC_CP2,
-    OPC_PSUBB       = (30 << 21) | (0x01) | OPC_CP2,
-    OPC_PSUBD       = (31 << 21) | (0x01) | OPC_CP2,
-
-    OPC_PSHUFH      = (24 << 21) | (0x02) | OPC_CP2,
-    OPC_PACKSSWH    = (25 << 21) | (0x02) | OPC_CP2,
-    OPC_PACKSSHB    = (26 << 21) | (0x02) | OPC_CP2,
-    OPC_PACKUSHB    = (27 << 21) | (0x02) | OPC_CP2,
-    OPC_XOR_CP2     = (28 << 21) | (0x02) | OPC_CP2,
-    OPC_NOR_CP2     = (29 << 21) | (0x02) | OPC_CP2,
-    OPC_AND_CP2     = (30 << 21) | (0x02) | OPC_CP2,
-    OPC_PANDN       = (31 << 21) | (0x02) | OPC_CP2,
-
-    OPC_PUNPCKLHW   = (24 << 21) | (0x03) | OPC_CP2,
-    OPC_PUNPCKHHW   = (25 << 21) | (0x03) | OPC_CP2,
-    OPC_PUNPCKLBH   = (26 << 21) | (0x03) | OPC_CP2,
-    OPC_PUNPCKHBH   = (27 << 21) | (0x03) | OPC_CP2,
-    OPC_PINSRH_0    = (28 << 21) | (0x03) | OPC_CP2,
-    OPC_PINSRH_1    = (29 << 21) | (0x03) | OPC_CP2,
-    OPC_PINSRH_2    = (30 << 21) | (0x03) | OPC_CP2,
-    OPC_PINSRH_3    = (31 << 21) | (0x03) | OPC_CP2,
-
-    OPC_PAVGH       = (24 << 21) | (0x08) | OPC_CP2,
-    OPC_PAVGB       = (25 << 21) | (0x08) | OPC_CP2,
-    OPC_PMAXSH      = (26 << 21) | (0x08) | OPC_CP2,
-    OPC_PMINSH      = (27 << 21) | (0x08) | OPC_CP2,
-    OPC_PMAXUB      = (28 << 21) | (0x08) | OPC_CP2,
-    OPC_PMINUB      = (29 << 21) | (0x08) | OPC_CP2,
-
-    OPC_PCMPEQW     = (24 << 21) | (0x09) | OPC_CP2,
-    OPC_PCMPGTW     = (25 << 21) | (0x09) | OPC_CP2,
-    OPC_PCMPEQH     = (26 << 21) | (0x09) | OPC_CP2,
-    OPC_PCMPGTH     = (27 << 21) | (0x09) | OPC_CP2,
-    OPC_PCMPEQB     = (28 << 21) | (0x09) | OPC_CP2,
-    OPC_PCMPGTB     = (29 << 21) | (0x09) | OPC_CP2,
-
-    OPC_PSLLW       = (24 << 21) | (0x0A) | OPC_CP2,
-    OPC_PSLLH       = (25 << 21) | (0x0A) | OPC_CP2,
-    OPC_PMULLH      = (26 << 21) | (0x0A) | OPC_CP2,
-    OPC_PMULHH      = (27 << 21) | (0x0A) | OPC_CP2,
-    OPC_PMULUW      = (28 << 21) | (0x0A) | OPC_CP2,
-    OPC_PMULHUH     = (29 << 21) | (0x0A) | OPC_CP2,
-
-    OPC_PSRLW       = (24 << 21) | (0x0B) | OPC_CP2,
-    OPC_PSRLH       = (25 << 21) | (0x0B) | OPC_CP2,
-    OPC_PSRAW       = (26 << 21) | (0x0B) | OPC_CP2,
-    OPC_PSRAH       = (27 << 21) | (0x0B) | OPC_CP2,
-    OPC_PUNPCKLWD   = (28 << 21) | (0x0B) | OPC_CP2,
-    OPC_PUNPCKHWD   = (29 << 21) | (0x0B) | OPC_CP2,
-
-    OPC_ADDU_CP2    = (24 << 21) | (0x0C) | OPC_CP2,
-    OPC_OR_CP2      = (25 << 21) | (0x0C) | OPC_CP2,
-    OPC_ADD_CP2     = (26 << 21) | (0x0C) | OPC_CP2,
-    OPC_DADD_CP2    = (27 << 21) | (0x0C) | OPC_CP2,
-    OPC_SEQU_CP2    = (28 << 21) | (0x0C) | OPC_CP2,
-    OPC_SEQ_CP2     = (29 << 21) | (0x0C) | OPC_CP2,
-
-    OPC_SUBU_CP2    = (24 << 21) | (0x0D) | OPC_CP2,
-    OPC_PASUBUB     = (25 << 21) | (0x0D) | OPC_CP2,
-    OPC_SUB_CP2     = (26 << 21) | (0x0D) | OPC_CP2,
-    OPC_DSUB_CP2    = (27 << 21) | (0x0D) | OPC_CP2,
-    OPC_SLTU_CP2    = (28 << 21) | (0x0D) | OPC_CP2,
-    OPC_SLT_CP2     = (29 << 21) | (0x0D) | OPC_CP2,
-
-    OPC_SLL_CP2     = (24 << 21) | (0x0E) | OPC_CP2,
-    OPC_DSLL_CP2    = (25 << 21) | (0x0E) | OPC_CP2,
-    OPC_PEXTRH      = (26 << 21) | (0x0E) | OPC_CP2,
-    OPC_PMADDHW     = (27 << 21) | (0x0E) | OPC_CP2,
-    OPC_SLEU_CP2    = (28 << 21) | (0x0E) | OPC_CP2,
-    OPC_SLE_CP2     = (29 << 21) | (0x0E) | OPC_CP2,
-
-    OPC_SRL_CP2     = (24 << 21) | (0x0F) | OPC_CP2,
-    OPC_DSRL_CP2    = (25 << 21) | (0x0F) | OPC_CP2,
-    OPC_SRA_CP2     = (26 << 21) | (0x0F) | OPC_CP2,
-    OPC_DSRA_CP2    = (27 << 21) | (0x0F) | OPC_CP2,
-    OPC_BIADD       = (28 << 21) | (0x0F) | OPC_CP2,
-    OPC_PMOVMSKB    = (29 << 21) | (0x0F) | OPC_CP2,
-};
-
-
 #define MASK_CP3(op)                (MASK_OP_MAJOR(op) | (op & 0x3F))
 
 enum {
@@ -3684,1163 +3516,184 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc,
         gen_reserved_instruction(ctx);
         goto out;
     }
- out:
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-}
-
-/*
- * These MULT[U] and MADD[U] instructions implemented in for example
- * the Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core
- * architectures are special three-operand variants with the syntax
- *
- *     MULT[U][1] rd, rs, rt
- *
- * such that
- *
- *     (rd, LO, HI) <- rs * rt
- *
- * and
- *
- *     MADD[U][1] rd, rs, rt
- *
- * such that
- *
- *     (rd, LO, HI) <- (LO, HI) + rs * rt
- *
- * where the low-order 32-bits of the result is placed into both the
- * GPR rd and the special register LO. The high-order 32-bits of the
- * result is placed into the special register HI.
- *
- * If the GPR rd is omitted in assembly language, it is taken to be 0,
- * which is the zero register that always reads as 0.
- */
-static void gen_mul_txx9(DisasContext *ctx, uint32_t opc,
-                         int rd, int rs, int rt)
-{
-    TCGv t0 = tcg_temp_new();
-    TCGv t1 = tcg_temp_new();
-    int acc = 0;
-
-    gen_load_gpr(t0, rs);
-    gen_load_gpr(t1, rt);
-
-    switch (opc) {
-    case MMI_OPC_MULT1:
-        acc = 1;
-        /* Fall through */
-    case OPC_MULT:
-        {
-            TCGv_i32 t2 = tcg_temp_new_i32();
-            TCGv_i32 t3 = tcg_temp_new_i32();
-            tcg_gen_trunc_tl_i32(t2, t0);
-            tcg_gen_trunc_tl_i32(t3, t1);
-            tcg_gen_muls2_i32(t2, t3, t2, t3);
-            if (rd) {
-                tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
-            }
-            tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
-            tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
-            tcg_temp_free_i32(t2);
-            tcg_temp_free_i32(t3);
-        }
-        break;
-    case MMI_OPC_MULTU1:
-        acc = 1;
-        /* Fall through */
-    case OPC_MULTU:
-        {
-            TCGv_i32 t2 = tcg_temp_new_i32();
-            TCGv_i32 t3 = tcg_temp_new_i32();
-            tcg_gen_trunc_tl_i32(t2, t0);
-            tcg_gen_trunc_tl_i32(t3, t1);
-            tcg_gen_mulu2_i32(t2, t3, t2, t3);
-            if (rd) {
-                tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
-            }
-            tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
-            tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
-            tcg_temp_free_i32(t2);
-            tcg_temp_free_i32(t3);
-        }
-        break;
-    case MMI_OPC_MADD1:
-        acc = 1;
-        /* Fall through */
-    case MMI_OPC_MADD:
-        {
-            TCGv_i64 t2 = tcg_temp_new_i64();
-            TCGv_i64 t3 = tcg_temp_new_i64();
-
-            tcg_gen_ext_tl_i64(t2, t0);
-            tcg_gen_ext_tl_i64(t3, t1);
-            tcg_gen_mul_i64(t2, t2, t3);
-            tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
-            tcg_gen_add_i64(t2, t2, t3);
-            tcg_temp_free_i64(t3);
-            gen_move_low32(cpu_LO[acc], t2);
-            gen_move_high32(cpu_HI[acc], t2);
-            if (rd) {
-                gen_move_low32(cpu_gpr[rd], t2);
-            }
-            tcg_temp_free_i64(t2);
-        }
-        break;
-    case MMI_OPC_MADDU1:
-        acc = 1;
-        /* Fall through */
-    case MMI_OPC_MADDU:
-        {
-            TCGv_i64 t2 = tcg_temp_new_i64();
-            TCGv_i64 t3 = tcg_temp_new_i64();
-
-            tcg_gen_ext32u_tl(t0, t0);
-            tcg_gen_ext32u_tl(t1, t1);
-            tcg_gen_extu_tl_i64(t2, t0);
-            tcg_gen_extu_tl_i64(t3, t1);
-            tcg_gen_mul_i64(t2, t2, t3);
-            tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
-            tcg_gen_add_i64(t2, t2, t3);
-            tcg_temp_free_i64(t3);
-            gen_move_low32(cpu_LO[acc], t2);
-            gen_move_high32(cpu_HI[acc], t2);
-            if (rd) {
-                gen_move_low32(cpu_gpr[rd], t2);
-            }
-            tcg_temp_free_i64(t2);
-        }
-        break;
-    default:
-        MIPS_INVAL("mul/madd TXx9");
-        gen_reserved_instruction(ctx);
-        goto out;
-    }
-
- out:
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-}
-
-static void gen_cl(DisasContext *ctx, uint32_t opc,
-                   int rd, int rs)
-{
-    TCGv t0;
-
-    if (rd == 0) {
-        /* Treat as NOP. */
-        return;
-    }
-    t0 = cpu_gpr[rd];
-    gen_load_gpr(t0, rs);
-
-    switch (opc) {
-    case OPC_CLO:
-    case R6_OPC_CLO:
-#if defined(TARGET_MIPS64)
-    case OPC_DCLO:
-    case R6_OPC_DCLO:
-#endif
-        tcg_gen_not_tl(t0, t0);
-        break;
-    }
-
-    switch (opc) {
-    case OPC_CLO:
-    case R6_OPC_CLO:
-    case OPC_CLZ:
-    case R6_OPC_CLZ:
-        tcg_gen_ext32u_tl(t0, t0);
-        tcg_gen_clzi_tl(t0, t0, TARGET_LONG_BITS);
-        tcg_gen_subi_tl(t0, t0, TARGET_LONG_BITS - 32);
-        break;
-#if defined(TARGET_MIPS64)
-    case OPC_DCLO:
-    case R6_OPC_DCLO:
-    case OPC_DCLZ:
-    case R6_OPC_DCLZ:
-        tcg_gen_clzi_i64(t0, t0, 64);
-        break;
-#endif
-    }
-}
-
-/* Godson integer instructions */
-static void gen_loongson_integer(DisasContext *ctx, uint32_t opc,
-                                 int rd, int rs, int rt)
-{
-    TCGv t0, t1;
-
-    if (rd == 0) {
-        /* Treat as NOP. */
-        return;
-    }
-
-    switch (opc) {
-    case OPC_MULT_G_2E:
-    case OPC_MULT_G_2F:
-    case OPC_MULTU_G_2E:
-    case OPC_MULTU_G_2F:
-#if defined(TARGET_MIPS64)
-    case OPC_DMULT_G_2E:
-    case OPC_DMULT_G_2F:
-    case OPC_DMULTU_G_2E:
-    case OPC_DMULTU_G_2F:
-#endif
-        t0 = tcg_temp_new();
-        t1 = tcg_temp_new();
-        break;
-    default:
-        t0 = tcg_temp_local_new();
-        t1 = tcg_temp_local_new();
-        break;
-    }
-
-    gen_load_gpr(t0, rs);
-    gen_load_gpr(t1, rt);
-
-    switch (opc) {
-    case OPC_MULT_G_2E:
-    case OPC_MULT_G_2F:
-        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
-        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
-        break;
-    case OPC_MULTU_G_2E:
-    case OPC_MULTU_G_2F:
-        tcg_gen_ext32u_tl(t0, t0);
-        tcg_gen_ext32u_tl(t1, t1);
-        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
-        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
-        break;
-    case OPC_DIV_G_2E:
-    case OPC_DIV_G_2F:
-        {
-            TCGLabel *l1 = gen_new_label();
-            TCGLabel *l2 = gen_new_label();
-            TCGLabel *l3 = gen_new_label();
-            tcg_gen_ext32s_tl(t0, t0);
-            tcg_gen_ext32s_tl(t1, t1);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
-            tcg_gen_movi_tl(cpu_gpr[rd], 0);
-            tcg_gen_br(l3);
-            gen_set_label(l1);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
-            tcg_gen_mov_tl(cpu_gpr[rd], t0);
-            tcg_gen_br(l3);
-            gen_set_label(l2);
-            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
-            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
-            gen_set_label(l3);
-        }
-        break;
-    case OPC_DIVU_G_2E:
-    case OPC_DIVU_G_2F:
-        {
-            TCGLabel *l1 = gen_new_label();
-            TCGLabel *l2 = gen_new_label();
-            tcg_gen_ext32u_tl(t0, t0);
-            tcg_gen_ext32u_tl(t1, t1);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
-            tcg_gen_movi_tl(cpu_gpr[rd], 0);
-            tcg_gen_br(l2);
-            gen_set_label(l1);
-            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
-            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
-            gen_set_label(l2);
-        }
-        break;
-    case OPC_MOD_G_2E:
-    case OPC_MOD_G_2F:
-        {
-            TCGLabel *l1 = gen_new_label();
-            TCGLabel *l2 = gen_new_label();
-            TCGLabel *l3 = gen_new_label();
-            tcg_gen_ext32u_tl(t0, t0);
-            tcg_gen_ext32u_tl(t1, t1);
-            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
-            gen_set_label(l1);
-            tcg_gen_movi_tl(cpu_gpr[rd], 0);
-            tcg_gen_br(l3);
-            gen_set_label(l2);
-            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
-            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
-            gen_set_label(l3);
-        }
-        break;
-    case OPC_MODU_G_2E:
-    case OPC_MODU_G_2F:
-        {
-            TCGLabel *l1 = gen_new_label();
-            TCGLabel *l2 = gen_new_label();
-            tcg_gen_ext32u_tl(t0, t0);
-            tcg_gen_ext32u_tl(t1, t1);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
-            tcg_gen_movi_tl(cpu_gpr[rd], 0);
-            tcg_gen_br(l2);
-            gen_set_label(l1);
-            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
-            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
-            gen_set_label(l2);
-        }
-        break;
-#if defined(TARGET_MIPS64)
-    case OPC_DMULT_G_2E:
-    case OPC_DMULT_G_2F:
-        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
-        break;
-    case OPC_DMULTU_G_2E:
-    case OPC_DMULTU_G_2F:
-        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
-        break;
-    case OPC_DDIV_G_2E:
-    case OPC_DDIV_G_2F:
-        {
-            TCGLabel *l1 = gen_new_label();
-            TCGLabel *l2 = gen_new_label();
-            TCGLabel *l3 = gen_new_label();
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
-            tcg_gen_movi_tl(cpu_gpr[rd], 0);
-            tcg_gen_br(l3);
-            gen_set_label(l1);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
-            tcg_gen_mov_tl(cpu_gpr[rd], t0);
-            tcg_gen_br(l3);
-            gen_set_label(l2);
-            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
-            gen_set_label(l3);
-        }
-        break;
-    case OPC_DDIVU_G_2E:
-    case OPC_DDIVU_G_2F:
-        {
-            TCGLabel *l1 = gen_new_label();
-            TCGLabel *l2 = gen_new_label();
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
-            tcg_gen_movi_tl(cpu_gpr[rd], 0);
-            tcg_gen_br(l2);
-            gen_set_label(l1);
-            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
-            gen_set_label(l2);
-        }
-        break;
-    case OPC_DMOD_G_2E:
-    case OPC_DMOD_G_2F:
-        {
-            TCGLabel *l1 = gen_new_label();
-            TCGLabel *l2 = gen_new_label();
-            TCGLabel *l3 = gen_new_label();
-            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
-            gen_set_label(l1);
-            tcg_gen_movi_tl(cpu_gpr[rd], 0);
-            tcg_gen_br(l3);
-            gen_set_label(l2);
-            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
-            gen_set_label(l3);
-        }
-        break;
-    case OPC_DMODU_G_2E:
-    case OPC_DMODU_G_2F:
-        {
-            TCGLabel *l1 = gen_new_label();
-            TCGLabel *l2 = gen_new_label();
-            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
-            tcg_gen_movi_tl(cpu_gpr[rd], 0);
-            tcg_gen_br(l2);
-            gen_set_label(l1);
-            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
-            gen_set_label(l2);
-        }
-        break;
-#endif
-    }
-
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-}
-
-/* Loongson multimedia instructions */
-static void gen_loongson_multimedia(DisasContext *ctx, int rd, int rs, int rt)
-{
-    uint32_t opc, shift_max;
-    TCGv_i64 t0, t1;
-    TCGCond cond;
-
-    opc = MASK_LMMI(ctx->opcode);
-    switch (opc) {
-    case OPC_ADD_CP2:
-    case OPC_SUB_CP2:
-    case OPC_DADD_CP2:
-    case OPC_DSUB_CP2:
-        t0 = tcg_temp_local_new_i64();
-        t1 = tcg_temp_local_new_i64();
-        break;
-    default:
-        t0 = tcg_temp_new_i64();
-        t1 = tcg_temp_new_i64();
-        break;
-    }
-
-    check_cp1_enabled(ctx);
-    gen_load_fpr64(ctx, t0, rs);
-    gen_load_fpr64(ctx, t1, rt);
-
-    switch (opc) {
-    case OPC_PADDSH:
-        gen_helper_paddsh(t0, t0, t1);
-        break;
-    case OPC_PADDUSH:
-        gen_helper_paddush(t0, t0, t1);
-        break;
-    case OPC_PADDH:
-        gen_helper_paddh(t0, t0, t1);
-        break;
-    case OPC_PADDW:
-        gen_helper_paddw(t0, t0, t1);
-        break;
-    case OPC_PADDSB:
-        gen_helper_paddsb(t0, t0, t1);
-        break;
-    case OPC_PADDUSB:
-        gen_helper_paddusb(t0, t0, t1);
-        break;
-    case OPC_PADDB:
-        gen_helper_paddb(t0, t0, t1);
-        break;
-
-    case OPC_PSUBSH:
-        gen_helper_psubsh(t0, t0, t1);
-        break;
-    case OPC_PSUBUSH:
-        gen_helper_psubush(t0, t0, t1);
-        break;
-    case OPC_PSUBH:
-        gen_helper_psubh(t0, t0, t1);
-        break;
-    case OPC_PSUBW:
-        gen_helper_psubw(t0, t0, t1);
-        break;
-    case OPC_PSUBSB:
-        gen_helper_psubsb(t0, t0, t1);
-        break;
-    case OPC_PSUBUSB:
-        gen_helper_psubusb(t0, t0, t1);
-        break;
-    case OPC_PSUBB:
-        gen_helper_psubb(t0, t0, t1);
-        break;
-
-    case OPC_PSHUFH:
-        gen_helper_pshufh(t0, t0, t1);
-        break;
-    case OPC_PACKSSWH:
-        gen_helper_packsswh(t0, t0, t1);
-        break;
-    case OPC_PACKSSHB:
-        gen_helper_packsshb(t0, t0, t1);
-        break;
-    case OPC_PACKUSHB:
-        gen_helper_packushb(t0, t0, t1);
-        break;
-
-    case OPC_PUNPCKLHW:
-        gen_helper_punpcklhw(t0, t0, t1);
-        break;
-    case OPC_PUNPCKHHW:
-        gen_helper_punpckhhw(t0, t0, t1);
-        break;
-    case OPC_PUNPCKLBH:
-        gen_helper_punpcklbh(t0, t0, t1);
-        break;
-    case OPC_PUNPCKHBH:
-        gen_helper_punpckhbh(t0, t0, t1);
-        break;
-    case OPC_PUNPCKLWD:
-        gen_helper_punpcklwd(t0, t0, t1);
-        break;
-    case OPC_PUNPCKHWD:
-        gen_helper_punpckhwd(t0, t0, t1);
-        break;
-
-    case OPC_PAVGH:
-        gen_helper_pavgh(t0, t0, t1);
-        break;
-    case OPC_PAVGB:
-        gen_helper_pavgb(t0, t0, t1);
-        break;
-    case OPC_PMAXSH:
-        gen_helper_pmaxsh(t0, t0, t1);
-        break;
-    case OPC_PMINSH:
-        gen_helper_pminsh(t0, t0, t1);
-        break;
-    case OPC_PMAXUB:
-        gen_helper_pmaxub(t0, t0, t1);
-        break;
-    case OPC_PMINUB:
-        gen_helper_pminub(t0, t0, t1);
-        break;
-
-    case OPC_PCMPEQW:
-        gen_helper_pcmpeqw(t0, t0, t1);
-        break;
-    case OPC_PCMPGTW:
-        gen_helper_pcmpgtw(t0, t0, t1);
-        break;
-    case OPC_PCMPEQH:
-        gen_helper_pcmpeqh(t0, t0, t1);
-        break;
-    case OPC_PCMPGTH:
-        gen_helper_pcmpgth(t0, t0, t1);
-        break;
-    case OPC_PCMPEQB:
-        gen_helper_pcmpeqb(t0, t0, t1);
-        break;
-    case OPC_PCMPGTB:
-        gen_helper_pcmpgtb(t0, t0, t1);
-        break;
-
-    case OPC_PSLLW:
-        gen_helper_psllw(t0, t0, t1);
-        break;
-    case OPC_PSLLH:
-        gen_helper_psllh(t0, t0, t1);
-        break;
-    case OPC_PSRLW:
-        gen_helper_psrlw(t0, t0, t1);
-        break;
-    case OPC_PSRLH:
-        gen_helper_psrlh(t0, t0, t1);
-        break;
-    case OPC_PSRAW:
-        gen_helper_psraw(t0, t0, t1);
-        break;
-    case OPC_PSRAH:
-        gen_helper_psrah(t0, t0, t1);
-        break;
-
-    case OPC_PMULLH:
-        gen_helper_pmullh(t0, t0, t1);
-        break;
-    case OPC_PMULHH:
-        gen_helper_pmulhh(t0, t0, t1);
-        break;
-    case OPC_PMULHUH:
-        gen_helper_pmulhuh(t0, t0, t1);
-        break;
-    case OPC_PMADDHW:
-        gen_helper_pmaddhw(t0, t0, t1);
-        break;
-
-    case OPC_PASUBUB:
-        gen_helper_pasubub(t0, t0, t1);
-        break;
-    case OPC_BIADD:
-        gen_helper_biadd(t0, t0);
-        break;
-    case OPC_PMOVMSKB:
-        gen_helper_pmovmskb(t0, t0);
-        break;
-
-    case OPC_PADDD:
-        tcg_gen_add_i64(t0, t0, t1);
-        break;
-    case OPC_PSUBD:
-        tcg_gen_sub_i64(t0, t0, t1);
-        break;
-    case OPC_XOR_CP2:
-        tcg_gen_xor_i64(t0, t0, t1);
-        break;
-    case OPC_NOR_CP2:
-        tcg_gen_nor_i64(t0, t0, t1);
-        break;
-    case OPC_AND_CP2:
-        tcg_gen_and_i64(t0, t0, t1);
-        break;
-    case OPC_OR_CP2:
-        tcg_gen_or_i64(t0, t0, t1);
-        break;
-
-    case OPC_PANDN:
-        tcg_gen_andc_i64(t0, t1, t0);
-        break;
-
-    case OPC_PINSRH_0:
-        tcg_gen_deposit_i64(t0, t0, t1, 0, 16);
-        break;
-    case OPC_PINSRH_1:
-        tcg_gen_deposit_i64(t0, t0, t1, 16, 16);
-        break;
-    case OPC_PINSRH_2:
-        tcg_gen_deposit_i64(t0, t0, t1, 32, 16);
-        break;
-    case OPC_PINSRH_3:
-        tcg_gen_deposit_i64(t0, t0, t1, 48, 16);
-        break;
-
-    case OPC_PEXTRH:
-        tcg_gen_andi_i64(t1, t1, 3);
-        tcg_gen_shli_i64(t1, t1, 4);
-        tcg_gen_shr_i64(t0, t0, t1);
-        tcg_gen_ext16u_i64(t0, t0);
-        break;
-
-    case OPC_ADDU_CP2:
-        tcg_gen_add_i64(t0, t0, t1);
-        tcg_gen_ext32s_i64(t0, t0);
-        break;
-    case OPC_SUBU_CP2:
-        tcg_gen_sub_i64(t0, t0, t1);
-        tcg_gen_ext32s_i64(t0, t0);
-        break;
-
-    case OPC_SLL_CP2:
-        shift_max = 32;
-        goto do_shift;
-    case OPC_SRL_CP2:
-        shift_max = 32;
-        goto do_shift;
-    case OPC_SRA_CP2:
-        shift_max = 32;
-        goto do_shift;
-    case OPC_DSLL_CP2:
-        shift_max = 64;
-        goto do_shift;
-    case OPC_DSRL_CP2:
-        shift_max = 64;
-        goto do_shift;
-    case OPC_DSRA_CP2:
-        shift_max = 64;
-        goto do_shift;
-    do_shift:
-        /* Make sure shift count isn't TCG undefined behaviour.  */
-        tcg_gen_andi_i64(t1, t1, shift_max - 1);
-
-        switch (opc) {
-        case OPC_SLL_CP2:
-        case OPC_DSLL_CP2:
-            tcg_gen_shl_i64(t0, t0, t1);
-            break;
-        case OPC_SRA_CP2:
-        case OPC_DSRA_CP2:
-            /*
-             * Since SRA is UndefinedResult without sign-extended inputs,
-             * we can treat SRA and DSRA the same.
-             */
-            tcg_gen_sar_i64(t0, t0, t1);
-            break;
-        case OPC_SRL_CP2:
-            /* We want to shift in zeros for SRL; zero-extend first.  */
-            tcg_gen_ext32u_i64(t0, t0);
-            /* FALLTHRU */
-        case OPC_DSRL_CP2:
-            tcg_gen_shr_i64(t0, t0, t1);
-            break;
-        }
-
-        if (shift_max == 32) {
-            tcg_gen_ext32s_i64(t0, t0);
-        }
-
-        /* Shifts larger than MAX produce zero.  */
-        tcg_gen_setcondi_i64(TCG_COND_LTU, t1, t1, shift_max);
-        tcg_gen_neg_i64(t1, t1);
-        tcg_gen_and_i64(t0, t0, t1);
-        break;
-
-    case OPC_ADD_CP2:
-    case OPC_DADD_CP2:
-        {
-            TCGv_i64 t2 = tcg_temp_new_i64();
-            TCGLabel *lab = gen_new_label();
-
-            tcg_gen_mov_i64(t2, t0);
-            tcg_gen_add_i64(t0, t1, t2);
-            if (opc == OPC_ADD_CP2) {
-                tcg_gen_ext32s_i64(t0, t0);
-            }
-            tcg_gen_xor_i64(t1, t1, t2);
-            tcg_gen_xor_i64(t2, t2, t0);
-            tcg_gen_andc_i64(t1, t2, t1);
-            tcg_temp_free_i64(t2);
-            tcg_gen_brcondi_i64(TCG_COND_GE, t1, 0, lab);
-            generate_exception(ctx, EXCP_OVERFLOW);
-            gen_set_label(lab);
-            break;
-        }
-
-    case OPC_SUB_CP2:
-    case OPC_DSUB_CP2:
-        {
-            TCGv_i64 t2 = tcg_temp_new_i64();
-            TCGLabel *lab = gen_new_label();
-
-            tcg_gen_mov_i64(t2, t0);
-            tcg_gen_sub_i64(t0, t1, t2);
-            if (opc == OPC_SUB_CP2) {
-                tcg_gen_ext32s_i64(t0, t0);
-            }
-            tcg_gen_xor_i64(t1, t1, t2);
-            tcg_gen_xor_i64(t2, t2, t0);
-            tcg_gen_and_i64(t1, t1, t2);
-            tcg_temp_free_i64(t2);
-            tcg_gen_brcondi_i64(TCG_COND_GE, t1, 0, lab);
-            generate_exception(ctx, EXCP_OVERFLOW);
-            gen_set_label(lab);
-            break;
-        }
-
-    case OPC_PMULUW:
-        tcg_gen_ext32u_i64(t0, t0);
-        tcg_gen_ext32u_i64(t1, t1);
-        tcg_gen_mul_i64(t0, t0, t1);
-        break;
-
-    case OPC_SEQU_CP2:
-    case OPC_SEQ_CP2:
-        cond = TCG_COND_EQ;
-        goto do_cc_cond;
-        break;
-    case OPC_SLTU_CP2:
-        cond = TCG_COND_LTU;
-        goto do_cc_cond;
-        break;
-    case OPC_SLT_CP2:
-        cond = TCG_COND_LT;
-        goto do_cc_cond;
-        break;
-    case OPC_SLEU_CP2:
-        cond = TCG_COND_LEU;
-        goto do_cc_cond;
-        break;
-    case OPC_SLE_CP2:
-        cond = TCG_COND_LE;
-    do_cc_cond:
-        {
-            int cc = (ctx->opcode >> 8) & 0x7;
-            TCGv_i64 t64 = tcg_temp_new_i64();
-            TCGv_i32 t32 = tcg_temp_new_i32();
-
-            tcg_gen_setcond_i64(cond, t64, t0, t1);
-            tcg_gen_extrl_i64_i32(t32, t64);
-            tcg_gen_deposit_i32(fpu_fcr31, fpu_fcr31, t32,
-                                get_fp_bit(cc), 1);
-
-            tcg_temp_free_i32(t32);
-            tcg_temp_free_i64(t64);
-        }
-        goto no_rd;
-        break;
-    default:
-        MIPS_INVAL("loongson_cp2");
-        gen_reserved_instruction(ctx);
-        return;
-    }
-
-    gen_store_fpr64(ctx, t0, rd);
-
-no_rd:
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-}
-
-static void gen_loongson_lswc2(DisasContext *ctx, int rt,
-                               int rs, int rd)
-{
-    TCGv t0, t1, t2;
-    TCGv_i32 fp0;
-#if defined(TARGET_MIPS64)
-    int lsq_rt1 = ctx->opcode & 0x1f;
-    int lsq_offset = sextract32(ctx->opcode, 6, 9) << 4;
-#endif
-    int shf_offset = sextract32(ctx->opcode, 6, 8);
-
-    t0 = tcg_temp_new();
-
-    switch (MASK_LOONGSON_GSLSQ(ctx->opcode)) {
-#if defined(TARGET_MIPS64)
-    case OPC_GSLQ:
-        t1 = tcg_temp_new();
-        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
-        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
-        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        gen_store_gpr(t1, rt);
-        gen_store_gpr(t0, lsq_rt1);
-        tcg_temp_free(t1);
-        break;
-    case OPC_GSLQC1:
-        check_cp1_enabled(ctx);
-        t1 = tcg_temp_new();
-        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
-        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
-        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        gen_store_fpr64(ctx, t1, rt);
-        gen_store_fpr64(ctx, t0, lsq_rt1);
-        tcg_temp_free(t1);
-        break;
-    case OPC_GSSQ:
-        t1 = tcg_temp_new();
-        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
-        gen_load_gpr(t1, rt);
-        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
-        gen_load_gpr(t1, lsq_rt1);
-        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        tcg_temp_free(t1);
-        break;
-    case OPC_GSSQC1:
-        check_cp1_enabled(ctx);
-        t1 = tcg_temp_new();
-        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
-        gen_load_fpr64(ctx, t1, rt);
-        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
-        gen_load_fpr64(ctx, t1, lsq_rt1);
-        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        tcg_temp_free(t1);
-        break;
-#endif
-    case OPC_GSSHFL:
-        switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
-        case OPC_GSLWLC1:
-            check_cp1_enabled(ctx);
-            gen_base_offset_addr(ctx, t0, rs, shf_offset);
-            t1 = tcg_temp_new();
-            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
-            tcg_gen_andi_tl(t1, t0, 3);
-            if (!cpu_is_bigendian(ctx)) {
-                tcg_gen_xori_tl(t1, t1, 3);
-            }
-            tcg_gen_shli_tl(t1, t1, 3);
-            tcg_gen_andi_tl(t0, t0, ~3);
-            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
-            tcg_gen_shl_tl(t0, t0, t1);
-            t2 = tcg_const_tl(-1);
-            tcg_gen_shl_tl(t2, t2, t1);
-            fp0 = tcg_temp_new_i32();
-            gen_load_fpr32(ctx, fp0, rt);
-            tcg_gen_ext_i32_tl(t1, fp0);
-            tcg_gen_andc_tl(t1, t1, t2);
-            tcg_temp_free(t2);
-            tcg_gen_or_tl(t0, t0, t1);
-            tcg_temp_free(t1);
-#if defined(TARGET_MIPS64)
-            tcg_gen_extrl_i64_i32(fp0, t0);
-#else
-            tcg_gen_ext32s_tl(fp0, t0);
-#endif
-            gen_store_fpr32(ctx, fp0, rt);
-            tcg_temp_free_i32(fp0);
-            break;
-        case OPC_GSLWRC1:
-            check_cp1_enabled(ctx);
-            gen_base_offset_addr(ctx, t0, rs, shf_offset);
-            t1 = tcg_temp_new();
-            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
-            tcg_gen_andi_tl(t1, t0, 3);
-            if (cpu_is_bigendian(ctx)) {
-                tcg_gen_xori_tl(t1, t1, 3);
-            }
-            tcg_gen_shli_tl(t1, t1, 3);
-            tcg_gen_andi_tl(t0, t0, ~3);
-            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
-            tcg_gen_shr_tl(t0, t0, t1);
-            tcg_gen_xori_tl(t1, t1, 31);
-            t2 = tcg_const_tl(0xfffffffeull);
-            tcg_gen_shl_tl(t2, t2, t1);
-            fp0 = tcg_temp_new_i32();
-            gen_load_fpr32(ctx, fp0, rt);
-            tcg_gen_ext_i32_tl(t1, fp0);
-            tcg_gen_and_tl(t1, t1, t2);
-            tcg_temp_free(t2);
-            tcg_gen_or_tl(t0, t0, t1);
-            tcg_temp_free(t1);
-#if defined(TARGET_MIPS64)
-            tcg_gen_extrl_i64_i32(fp0, t0);
-#else
-            tcg_gen_ext32s_tl(fp0, t0);
-#endif
-            gen_store_fpr32(ctx, fp0, rt);
-            tcg_temp_free_i32(fp0);
-            break;
-#if defined(TARGET_MIPS64)
-        case OPC_GSLDLC1:
-            check_cp1_enabled(ctx);
-            gen_base_offset_addr(ctx, t0, rs, shf_offset);
-            t1 = tcg_temp_new();
-            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
-            tcg_gen_andi_tl(t1, t0, 7);
-            if (!cpu_is_bigendian(ctx)) {
-                tcg_gen_xori_tl(t1, t1, 7);
-            }
-            tcg_gen_shli_tl(t1, t1, 3);
-            tcg_gen_andi_tl(t0, t0, ~7);
-            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ);
-            tcg_gen_shl_tl(t0, t0, t1);
-            t2 = tcg_const_tl(-1);
-            tcg_gen_shl_tl(t2, t2, t1);
-            gen_load_fpr64(ctx, t1, rt);
-            tcg_gen_andc_tl(t1, t1, t2);
-            tcg_temp_free(t2);
-            tcg_gen_or_tl(t0, t0, t1);
-            tcg_temp_free(t1);
-            gen_store_fpr64(ctx, t0, rt);
-            break;
-        case OPC_GSLDRC1:
-            check_cp1_enabled(ctx);
-            gen_base_offset_addr(ctx, t0, rs, shf_offset);
-            t1 = tcg_temp_new();
-            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
-            tcg_gen_andi_tl(t1, t0, 7);
-            if (cpu_is_bigendian(ctx)) {
-                tcg_gen_xori_tl(t1, t1, 7);
-            }
-            tcg_gen_shli_tl(t1, t1, 3);
-            tcg_gen_andi_tl(t0, t0, ~7);
-            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ);
-            tcg_gen_shr_tl(t0, t0, t1);
-            tcg_gen_xori_tl(t1, t1, 63);
-            t2 = tcg_const_tl(0xfffffffffffffffeull);
-            tcg_gen_shl_tl(t2, t2, t1);
-            gen_load_fpr64(ctx, t1, rt);
-            tcg_gen_and_tl(t1, t1, t2);
-            tcg_temp_free(t2);
-            tcg_gen_or_tl(t0, t0, t1);
-            tcg_temp_free(t1);
-            gen_store_fpr64(ctx, t0, rt);
-            break;
-#endif
-        default:
-            MIPS_INVAL("loongson_gsshfl");
-            gen_reserved_instruction(ctx);
-            break;
-        }
-        break;
-    case OPC_GSSHFS:
-        switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
-        case OPC_GSSWLC1:
-            check_cp1_enabled(ctx);
-            t1 = tcg_temp_new();
-            gen_base_offset_addr(ctx, t0, rs, shf_offset);
-            fp0 = tcg_temp_new_i32();
-            gen_load_fpr32(ctx, fp0, rt);
-            tcg_gen_ext_i32_tl(t1, fp0);
-            gen_helper_0e2i(swl, t1, t0, ctx->mem_idx);
-            tcg_temp_free_i32(fp0);
-            tcg_temp_free(t1);
-            break;
-        case OPC_GSSWRC1:
-            check_cp1_enabled(ctx);
-            t1 = tcg_temp_new();
-            gen_base_offset_addr(ctx, t0, rs, shf_offset);
-            fp0 = tcg_temp_new_i32();
-            gen_load_fpr32(ctx, fp0, rt);
-            tcg_gen_ext_i32_tl(t1, fp0);
-            gen_helper_0e2i(swr, t1, t0, ctx->mem_idx);
-            tcg_temp_free_i32(fp0);
-            tcg_temp_free(t1);
-            break;
-#if defined(TARGET_MIPS64)
-        case OPC_GSSDLC1:
-            check_cp1_enabled(ctx);
-            t1 = tcg_temp_new();
-            gen_base_offset_addr(ctx, t0, rs, shf_offset);
-            gen_load_fpr64(ctx, t1, rt);
-            gen_helper_0e2i(sdl, t1, t0, ctx->mem_idx);
-            tcg_temp_free(t1);
-            break;
-        case OPC_GSSDRC1:
-            check_cp1_enabled(ctx);
-            t1 = tcg_temp_new();
-            gen_base_offset_addr(ctx, t0, rs, shf_offset);
-            gen_load_fpr64(ctx, t1, rt);
-            gen_helper_0e2i(sdr, t1, t0, ctx->mem_idx);
-            tcg_temp_free(t1);
-            break;
-#endif
-        default:
-            MIPS_INVAL("loongson_gsshfs");
-            gen_reserved_instruction(ctx);
-            break;
-        }
-        break;
-    default:
-        MIPS_INVAL("loongson_gslsq");
-        gen_reserved_instruction(ctx);
-        break;
-    }
+ out:
     tcg_temp_free(t0);
+    tcg_temp_free(t1);
 }
 
-/* Loongson EXT LDC2/SDC2 */
-static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
-                               int rs, int rd)
+/*
+ * These MULT[U] and MADD[U] instructions implemented in for example
+ * the Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core
+ * architectures are special three-operand variants with the syntax
+ *
+ *     MULT[U][1] rd, rs, rt
+ *
+ * such that
+ *
+ *     (rd, LO, HI) <- rs * rt
+ *
+ * and
+ *
+ *     MADD[U][1] rd, rs, rt
+ *
+ * such that
+ *
+ *     (rd, LO, HI) <- (LO, HI) + rs * rt
+ *
+ * where the low-order 32-bits of the result is placed into both the
+ * GPR rd and the special register LO. The high-order 32-bits of the
+ * result is placed into the special register HI.
+ *
+ * If the GPR rd is omitted in assembly language, it is taken to be 0,
+ * which is the zero register that always reads as 0.
+ */
+static void gen_mul_txx9(DisasContext *ctx, uint32_t opc,
+                         int rd, int rs, int rt)
 {
-    int offset = sextract32(ctx->opcode, 3, 8);
-    uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
-    TCGv t0, t1;
-    TCGv_i32 fp0;
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    int acc = 0;
+
+    gen_load_gpr(t0, rs);
+    gen_load_gpr(t1, rt);
 
-    /* Pre-conditions */
     switch (opc) {
-    case OPC_GSLBX:
-    case OPC_GSLHX:
-    case OPC_GSLWX:
-    case OPC_GSLDX:
-        /* prefetch, implement as NOP */
-        if (rt == 0) {
-            return;
+    case MMI_OPC_MULT1:
+        acc = 1;
+        /* Fall through */
+    case OPC_MULT:
+        {
+            TCGv_i32 t2 = tcg_temp_new_i32();
+            TCGv_i32 t3 = tcg_temp_new_i32();
+            tcg_gen_trunc_tl_i32(t2, t0);
+            tcg_gen_trunc_tl_i32(t3, t1);
+            tcg_gen_muls2_i32(t2, t3, t2, t3);
+            if (rd) {
+                tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
+            }
+            tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
+            tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
+            tcg_temp_free_i32(t2);
+            tcg_temp_free_i32(t3);
         }
         break;
-    case OPC_GSSBX:
-    case OPC_GSSHX:
-    case OPC_GSSWX:
-    case OPC_GSSDX:
+    case MMI_OPC_MULTU1:
+        acc = 1;
+        /* Fall through */
+    case OPC_MULTU:
+        {
+            TCGv_i32 t2 = tcg_temp_new_i32();
+            TCGv_i32 t3 = tcg_temp_new_i32();
+            tcg_gen_trunc_tl_i32(t2, t0);
+            tcg_gen_trunc_tl_i32(t3, t1);
+            tcg_gen_mulu2_i32(t2, t3, t2, t3);
+            if (rd) {
+                tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
+            }
+            tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
+            tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
+            tcg_temp_free_i32(t2);
+            tcg_temp_free_i32(t3);
+        }
         break;
-    case OPC_GSLWXC1:
-#if defined(TARGET_MIPS64)
-    case OPC_GSLDXC1:
-#endif
-        check_cp1_enabled(ctx);
-        /* prefetch, implement as NOP */
-        if (rt == 0) {
-            return;
+    case MMI_OPC_MADD1:
+        acc = 1;
+        /* Fall through */
+    case MMI_OPC_MADD:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGv_i64 t3 = tcg_temp_new_i64();
+
+            tcg_gen_ext_tl_i64(t2, t0);
+            tcg_gen_ext_tl_i64(t3, t1);
+            tcg_gen_mul_i64(t2, t2, t3);
+            tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
+            tcg_gen_add_i64(t2, t2, t3);
+            tcg_temp_free_i64(t3);
+            gen_move_low32(cpu_LO[acc], t2);
+            gen_move_high32(cpu_HI[acc], t2);
+            if (rd) {
+                gen_move_low32(cpu_gpr[rd], t2);
+            }
+            tcg_temp_free_i64(t2);
         }
         break;
-    case OPC_GSSWXC1:
-#if defined(TARGET_MIPS64)
-    case OPC_GSSDXC1:
-#endif
-        check_cp1_enabled(ctx);
+    case MMI_OPC_MADDU1:
+        acc = 1;
+        /* Fall through */
+    case MMI_OPC_MADDU:
+        {
+            TCGv_i64 t2 = tcg_temp_new_i64();
+            TCGv_i64 t3 = tcg_temp_new_i64();
+
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_extu_tl_i64(t2, t0);
+            tcg_gen_extu_tl_i64(t3, t1);
+            tcg_gen_mul_i64(t2, t2, t3);
+            tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
+            tcg_gen_add_i64(t2, t2, t3);
+            tcg_temp_free_i64(t3);
+            gen_move_low32(cpu_LO[acc], t2);
+            gen_move_high32(cpu_HI[acc], t2);
+            if (rd) {
+                gen_move_low32(cpu_gpr[rd], t2);
+            }
+            tcg_temp_free_i64(t2);
+        }
         break;
     default:
-        MIPS_INVAL("loongson_lsdc2");
+        MIPS_INVAL("mul/madd TXx9");
         gen_reserved_instruction(ctx);
-        return;
-        break;
+        goto out;
     }
 
-    t0 = tcg_temp_new();
+ out:
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_cl(DisasContext *ctx, uint32_t opc,
+                   int rd, int rs)
+{
+    TCGv t0;
 
-    gen_base_offset_addr(ctx, t0, rs, offset);
-    gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+    if (rd == 0) {
+        /* Treat as NOP. */
+        return;
+    }
+    t0 = cpu_gpr[rd];
+    gen_load_gpr(t0, rs);
 
     switch (opc) {
-    case OPC_GSLBX:
-        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
-        gen_store_gpr(t0, rt);
-        break;
-    case OPC_GSLHX:
-        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
-                           ctx->default_tcg_memop_mask);
-        gen_store_gpr(t0, rt);
-        break;
-    case OPC_GSLWX:
-        gen_base_offset_addr(ctx, t0, rs, offset);
-        if (rd) {
-            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
-        }
-        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL |
-                           ctx->default_tcg_memop_mask);
-        gen_store_gpr(t0, rt);
-        break;
-#if defined(TARGET_MIPS64)
-    case OPC_GSLDX:
-        gen_base_offset_addr(ctx, t0, rs, offset);
-        if (rd) {
-            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
-        }
-        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        gen_store_gpr(t0, rt);
-        break;
-#endif
-    case OPC_GSLWXC1:
-        gen_base_offset_addr(ctx, t0, rs, offset);
-        if (rd) {
-            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
-        }
-        fp0 = tcg_temp_new_i32();
-        tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL |
-                            ctx->default_tcg_memop_mask);
-        gen_store_fpr32(ctx, fp0, rt);
-        tcg_temp_free_i32(fp0);
-        break;
+    case OPC_CLO:
+    case R6_OPC_CLO:
 #if defined(TARGET_MIPS64)
-    case OPC_GSLDXC1:
-        gen_base_offset_addr(ctx, t0, rs, offset);
-        if (rd) {
-            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
-        }
-        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        gen_store_fpr64(ctx, t0, rt);
-        break;
+    case OPC_DCLO:
+    case R6_OPC_DCLO:
 #endif
-    case OPC_GSSBX:
-        t1 = tcg_temp_new();
-        gen_load_gpr(t1, rt);
-        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_SB);
-        tcg_temp_free(t1);
-        break;
-    case OPC_GSSHX:
-        t1 = tcg_temp_new();
-        gen_load_gpr(t1, rt);
-        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
-                           ctx->default_tcg_memop_mask);
-        tcg_temp_free(t1);
-        break;
-    case OPC_GSSWX:
-        t1 = tcg_temp_new();
-        gen_load_gpr(t1, rt);
-        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
-                           ctx->default_tcg_memop_mask);
-        tcg_temp_free(t1);
-        break;
-#if defined(TARGET_MIPS64)
-    case OPC_GSSDX:
-        t1 = tcg_temp_new();
-        gen_load_gpr(t1, rt);
-        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
-                           ctx->default_tcg_memop_mask);
-        tcg_temp_free(t1);
+        tcg_gen_not_tl(t0, t0);
         break;
-#endif
-    case OPC_GSSWXC1:
-        fp0 = tcg_temp_new_i32();
-        gen_load_fpr32(ctx, fp0, rt);
-        tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL |
-                            ctx->default_tcg_memop_mask);
-        tcg_temp_free_i32(fp0);
+    }
+
+    switch (opc) {
+    case OPC_CLO:
+    case R6_OPC_CLO:
+    case OPC_CLZ:
+    case R6_OPC_CLZ:
+        tcg_gen_ext32u_tl(t0, t0);
+        tcg_gen_clzi_tl(t0, t0, TARGET_LONG_BITS);
+        tcg_gen_subi_tl(t0, t0, TARGET_LONG_BITS - 32);
         break;
 #if defined(TARGET_MIPS64)
-    case OPC_GSSDXC1:
-        t1 = tcg_temp_new();
-        gen_load_fpr64(ctx, t1, rt);
-        tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEUQ |
-                            ctx->default_tcg_memop_mask);
-        tcg_temp_free(t1);
+    case OPC_DCLO:
+    case R6_OPC_DCLO:
+    case OPC_DCLZ:
+    case R6_OPC_DCLZ:
+        tcg_gen_clzi_i64(t0, t0, 64);
         break;
 #endif
-    default:
-        break;
     }
-
-    tcg_temp_free(t0);
 }
 
 /* Traps */
@@ -12347,8 +11200,7 @@ static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2,
     gen_load_gpr(v2_t, v2);
 
     switch (op1) {
-    /* OPC_MULT_G_2E is equal OPC_ADDUH_QB_DSP */
-    case OPC_MULT_G_2E:
+    case OPC_ADDUH_QB_DSP:
         check_dsp_r2(ctx);
         switch (op2) {
         case OPC_ADDUH_QB:
@@ -13042,11 +11894,7 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2,
     gen_load_gpr(v2_t, v2);
 
     switch (op1) {
-    /*
-     * OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
-     * the same mask and op1.
-     */
-    case OPC_MULT_G_2E:
+    case OPC_ADDUH_QB_DSP:
         check_dsp_r2(ctx);
         switch (op2) {
         case  OPC_MUL_PH:
@@ -14413,15 +13261,6 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
     case OPC_MUL:
         gen_arith(ctx, op1, rd, rs, rt);
         break;
-    case OPC_DIV_G_2F:
-    case OPC_DIVU_G_2F:
-    case OPC_MULT_G_2F:
-    case OPC_MULTU_G_2F:
-    case OPC_MOD_G_2F:
-    case OPC_MODU_G_2F:
-        check_insn(ctx, INSN_LOONGSON2F | ASE_LEXT);
-        gen_loongson_integer(ctx, op1, rd, rs, rt);
-        break;
     case OPC_CLO:
     case OPC_CLZ:
         check_insn(ctx, ISA_MIPS_R1);
@@ -14446,15 +13285,6 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
         check_mips_64(ctx);
         gen_cl(ctx, op1, rd, rs);
         break;
-    case OPC_DMULT_G_2F:
-    case OPC_DMULTU_G_2F:
-    case OPC_DDIV_G_2F:
-    case OPC_DDIVU_G_2F:
-    case OPC_DMOD_G_2F:
-    case OPC_DMODU_G_2F:
-        check_insn(ctx, INSN_LOONGSON2F | ASE_LEXT);
-        gen_loongson_integer(ctx, op1, rd, rs, rt);
-        break;
 #endif
     default:            /* Invalid */
         MIPS_INVAL("special2_legacy");
@@ -14587,48 +13417,33 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
 
     op1 = MASK_SPECIAL3(ctx->opcode);
     switch (op1) {
-    case OPC_DIV_G_2E:
-    case OPC_DIVU_G_2E:
-    case OPC_MOD_G_2E:
-    case OPC_MODU_G_2E:
-    case OPC_MULT_G_2E:
-    case OPC_MULTU_G_2E:
-        /*
-         * OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
-         * the same mask and op1.
-         */
-        if ((ctx->insn_flags & ASE_DSP_R2) && (op1 == OPC_MULT_G_2E)) {
-            op2 = MASK_ADDUH_QB(ctx->opcode);
-            switch (op2) {
-            case OPC_ADDUH_QB:
-            case OPC_ADDUH_R_QB:
-            case OPC_ADDQH_PH:
-            case OPC_ADDQH_R_PH:
-            case OPC_ADDQH_W:
-            case OPC_ADDQH_R_W:
-            case OPC_SUBUH_QB:
-            case OPC_SUBUH_R_QB:
-            case OPC_SUBQH_PH:
-            case OPC_SUBQH_R_PH:
-            case OPC_SUBQH_W:
-            case OPC_SUBQH_R_W:
-                gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
-                break;
-            case OPC_MUL_PH:
-            case OPC_MUL_S_PH:
-            case OPC_MULQ_S_W:
-            case OPC_MULQ_RS_W:
-                gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
-                break;
-            default:
-                MIPS_INVAL("MASK ADDUH.QB");
-                gen_reserved_instruction(ctx);
-                break;
-            }
-        } else if (ctx->insn_flags & INSN_LOONGSON2E) {
-            gen_loongson_integer(ctx, op1, rd, rs, rt);
-        } else {
+    case OPC_ADDUH_QB_DSP:
+        op2 = MASK_ADDUH_QB(ctx->opcode);
+        switch (op2) {
+        case OPC_ADDUH_QB:
+        case OPC_ADDUH_R_QB:
+        case OPC_ADDQH_PH:
+        case OPC_ADDQH_R_PH:
+        case OPC_ADDQH_W:
+        case OPC_ADDQH_R_W:
+        case OPC_SUBUH_QB:
+        case OPC_SUBUH_R_QB:
+        case OPC_SUBQH_PH:
+        case OPC_SUBQH_R_PH:
+        case OPC_SUBQH_W:
+        case OPC_SUBQH_R_W:
+            gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
+            break;
+        case OPC_MUL_PH:
+        case OPC_MUL_S_PH:
+        case OPC_MULQ_S_W:
+        case OPC_MULQ_RS_W:
+            gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
+            break;
+        default:
+            MIPS_INVAL("MASK ADDUH.QB");
             gen_reserved_instruction(ctx);
+            break;
         }
         break;
     case OPC_LX_DSP:
@@ -14858,15 +13673,6 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
         }
         break;
 #if defined(TARGET_MIPS64)
-    case OPC_DDIV_G_2E:
-    case OPC_DDIVU_G_2E:
-    case OPC_DMULT_G_2E:
-    case OPC_DMULTU_G_2E:
-    case OPC_DMOD_G_2E:
-    case OPC_DMODU_G_2E:
-        check_insn(ctx, INSN_LOONGSON2E);
-        gen_loongson_integer(ctx, op1, rd, rs, rt);
-        break;
     case OPC_ABSQ_S_QH_DSP:
         op2 = MASK_ABSQ_S_QH(ctx->opcode);
         switch (op2) {
@@ -15867,8 +14673,6 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
             /* OPC_BC, OPC_BALC */
             gen_compute_compact_branch(ctx, op, 0, 0,
                                        sextract32(ctx->opcode << 2, 0, 28));
-        } else if (ctx->insn_flags & ASE_LEXT) {
-            gen_loongson_lswc2(ctx, rt, rs, rd);
         } else {
             /* OPC_LWC2, OPC_SWC2 */
             /* COP2: Not implemented. */
@@ -15886,8 +14690,6 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
                 /* OPC_JIC, OPC_JIALC */
                 gen_compute_compact_branch(ctx, op, 0, rt, imm);
             }
-        } else if (ctx->insn_flags & ASE_LEXT) {
-            gen_loongson_lsdc2(ctx, rt, rs, rd);
         } else {
             /* OPC_LWC2, OPC_SWC2 */
             /* COP2: Not implemented. */
@@ -15895,9 +14697,8 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
         }
         break;
     case OPC_CP2:
-        check_insn(ctx, ASE_LMMI);
-        /* Note that these instructions use different fields.  */
-        gen_loongson_multimedia(ctx, sa, rd, rt);
+        MIPS_INVAL("cp2");
+        gen_reserved_instruction(ctx);
         break;
 
     case OPC_CP3:
@@ -16075,8 +14876,22 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
         return;
     }
 #endif
+    if (cpu_supports_isa(env, INSN_LOONGSON2E) &&
+        decode_ext_loongson2e(ctx, ctx->opcode)) {
+        return;
+    }
+    if (cpu_supports_isa(env, INSN_LOONGSON2F) &&
+        decode_ext_loongson2f(ctx, ctx->opcode)) {
+        return;
+    }
 
     /* ISA extensions */
+    if (cpu_supports_isa(env, ASE_LEXT) && decode_ase_lext(ctx, ctx->opcode)) {
+        return;
+    }
+    if (cpu_supports_isa(env, ASE_LMMI) && decode_ase_lmmi(ctx, ctx->opcode)) {
+        return;
+    }
     if (ase_msa_available(env) && decode_ase_msa(ctx, ctx->opcode)) {
         return;
     }
diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h
index 980aa8682d..c5fd16e657 100644
--- a/target/mips/tcg/translate.h
+++ b/target/mips/tcg/translate.h
@@ -241,6 +241,12 @@ void msa_translate_init(void);
 void mxu_translate_init(void);
 bool decode_ase_mxu(DisasContext *ctx, uint32_t insn);
 
+/* loongson */
+bool decode_ext_loongson2e(DisasContext *ctx, uint32_t insn);
+bool decode_ext_loongson2f(DisasContext *ctx, uint32_t insn);
+bool decode_ase_lext(DisasContext *ctx, uint32_t insn);
+bool decode_ase_lmmi(DisasContext *ctx, uint32_t insn);
+
 /* decodetree generated */
 bool decode_isa_rel6(DisasContext *ctx, uint32_t insn);
 bool decode_ase_msa(DisasContext *ctx, uint32_t insn);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/6] target/mips: Move all tx79 instructions to decodetree
  2022-10-24 15:23 [PATCH 0/6] MIPS decodetree conversion Jiaxun Yang
                   ` (3 preceding siblings ...)
  2022-10-24 15:23 ` [PATCH 4/6] target/mips: Split Loongson extention translation into standalone file Jiaxun Yang
@ 2022-10-24 15:23 ` Jiaxun Yang
  2022-10-24 15:23 ` [PATCH 6/6] target/mips: Make MXU decoder standalone Jiaxun Yang
  5 siblings, 0 replies; 8+ messages in thread
From: Jiaxun Yang @ 2022-10-24 15:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: f4bug, richard.henderson, Jiaxun Yang

Move MUL family instructions into decodetree.
Also implement RDHWR emulation for user instructions in decodetree
SQ translation.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/tcg/translate.c      | 410 +------------------------------
 target/mips/tcg/tx79.decode      |  14 ++
 target/mips/tcg/tx79_translate.c | 205 +++++++++++++++-
 3 files changed, 219 insertions(+), 410 deletions(-)

diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index d398b2f44d..c8a3f63203 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -956,82 +956,6 @@ enum {
     OPC_NMSUB_PS    = 0x3E | OPC_CP3,
 };
 
-/*
- *     MMI (MultiMedia Instruction) encodings
- *     ======================================
- *
- * MMI instructions encoding table keys:
- *
- *     *   This code is reserved for future use. An attempt to execute it
- *         causes a Reserved Instruction exception.
- *     %   This code indicates an instruction class. The instruction word
- *         must be further decoded by examining additional tables that show
- *         the values for other instruction fields.
- *     #   This code is reserved for the unsupported instructions DMULT,
- *         DMULTU, DDIV, DDIVU, LL, LLD, SC, SCD, LWC2 and SWC2. An attempt
- *         to execute it causes a Reserved Instruction exception.
- *
- * MMI instructions encoded by opcode field (MMI, LQ, SQ):
- *
- *  31    26                                        0
- * +--------+----------------------------------------+
- * | opcode |                                        |
- * +--------+----------------------------------------+
- *
- *   opcode  bits 28..26
- *     bits |   0   |   1   |   2   |   3   |   4   |   5   |   6   |   7
- *   31..29 |  000  |  001  |  010  |  011  |  100  |  101  |  110  |  111
- *   -------+-------+-------+-------+-------+-------+-------+-------+-------
- *    0 000 |SPECIAL| REGIMM|   J   |  JAL  |  BEQ  |  BNE  |  BLEZ |  BGTZ
- *    1 001 |  ADDI | ADDIU |  SLTI | SLTIU |  ANDI |  ORI  |  XORI |  LUI
- *    2 010 |  COP0 |  COP1 |   *   |   *   |  BEQL |  BNEL | BLEZL | BGTZL
- *    3 011 | DADDI | DADDIU|  LDL  |  LDR  |  MMI% |   *   |   LQ  |   SQ
- *    4 100 |   LB  |   LH  |  LWL  |   LW  |  LBU  |  LHU  |  LWR  |  LWU
- *    5 101 |   SB  |   SH  |  SWL  |   SW  |  SDL  |  SDR  |  SWR  | CACHE
- *    6 110 |   #   |  LWC1 |   #   |  PREF |   #   |  LDC1 |   #   |   LD
- *    7 111 |   #   |  SWC1 |   #   |   *   |   #   |  SDC1 |   #   |   SD
- */
-
-enum {
-    MMI_OPC_CLASS_MMI = 0x1C << 26,    /* Same as OPC_SPECIAL2 */
-    MMI_OPC_SQ        = 0x1F << 26,    /* Same as OPC_SPECIAL3 */
-};
-
-/*
- * MMI instructions with opcode field = MMI:
- *
- *  31    26                                 5      0
- * +--------+-------------------------------+--------+
- * |   MMI  |                               |function|
- * +--------+-------------------------------+--------+
- *
- * function  bits 2..0
- *     bits |   0   |   1   |   2   |   3   |   4   |   5   |   6   |   7
- *     5..3 |  000  |  001  |  010  |  011  |  100  |  101  |  110  |  111
- *   -------+-------+-------+-------+-------+-------+-------+-------+-------
- *    0 000 |  MADD | MADDU |   *   |   *   | PLZCW |   *   |   *   |   *
- *    1 001 | MMI0% | MMI2% |   *   |   *   |   *   |   *   |   *   |   *
- *    2 010 | MFHI1 | MTHI1 | MFLO1 | MTLO1 |   *   |   *   |   *   |   *
- *    3 011 | MULT1 | MULTU1|  DIV1 | DIVU1 |   *   |   *   |   *   |   *
- *    4 100 | MADD1 | MADDU1|   *   |   *   |   *   |   *   |   *   |   *
- *    5 101 | MMI1% | MMI3% |   *   |   *   |   *   |   *   |   *   |   *
- *    6 110 | PMFHL | PMTHL |   *   |   *   | PSLLH |   *   | PSRLH | PSRAH
- *    7 111 |   *   |   *   |   *   |   *   | PSLLW |   *   | PSRLW | PSRAW
- */
-
-#define MASK_MMI(op) (MASK_OP_MAJOR(op) | ((op) & 0x3F))
-enum {
-    MMI_OPC_MADD       = 0x00 | MMI_OPC_CLASS_MMI, /* Same as OPC_MADD */
-    MMI_OPC_MADDU      = 0x01 | MMI_OPC_CLASS_MMI, /* Same as OPC_MADDU */
-    MMI_OPC_MULT1      = 0x18 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MULT */
-    MMI_OPC_MULTU1     = 0x19 | MMI_OPC_CLASS_MMI, /* Same min. as OPC_MULTU */
-    MMI_OPC_DIV1       = 0x1A | MMI_OPC_CLASS_MMI, /* Same minor as OPC_DIV  */
-    MMI_OPC_DIVU1      = 0x1B | MMI_OPC_CLASS_MMI, /* Same minor as OPC_DIVU */
-    MMI_OPC_MADD1      = 0x20 | MMI_OPC_CLASS_MMI,
-    MMI_OPC_MADDU1     = 0x21 | MMI_OPC_CLASS_MMI,
-};
-
-
 /* global register indices */
 TCGv cpu_gpr[32], cpu_PC;
 /*
@@ -3270,65 +3194,6 @@ static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt)
     tcg_temp_free(t1);
 }
 
-#if defined(TARGET_MIPS64)
-static void gen_div1_tx79(DisasContext *ctx, uint32_t opc, int rs, int rt)
-{
-    TCGv t0, t1;
-
-    t0 = tcg_temp_new();
-    t1 = tcg_temp_new();
-
-    gen_load_gpr(t0, rs);
-    gen_load_gpr(t1, rt);
-
-    switch (opc) {
-    case MMI_OPC_DIV1:
-        {
-            TCGv t2 = tcg_temp_new();
-            TCGv t3 = tcg_temp_new();
-            tcg_gen_ext32s_tl(t0, t0);
-            tcg_gen_ext32s_tl(t1, t1);
-            tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
-            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
-            tcg_gen_and_tl(t2, t2, t3);
-            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
-            tcg_gen_or_tl(t2, t2, t3);
-            tcg_gen_movi_tl(t3, 0);
-            tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
-            tcg_gen_div_tl(cpu_LO[1], t0, t1);
-            tcg_gen_rem_tl(cpu_HI[1], t0, t1);
-            tcg_gen_ext32s_tl(cpu_LO[1], cpu_LO[1]);
-            tcg_gen_ext32s_tl(cpu_HI[1], cpu_HI[1]);
-            tcg_temp_free(t3);
-            tcg_temp_free(t2);
-        }
-        break;
-    case MMI_OPC_DIVU1:
-        {
-            TCGv t2 = tcg_const_tl(0);
-            TCGv t3 = tcg_const_tl(1);
-            tcg_gen_ext32u_tl(t0, t0);
-            tcg_gen_ext32u_tl(t1, t1);
-            tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
-            tcg_gen_divu_tl(cpu_LO[1], t0, t1);
-            tcg_gen_remu_tl(cpu_HI[1], t0, t1);
-            tcg_gen_ext32s_tl(cpu_LO[1], cpu_LO[1]);
-            tcg_gen_ext32s_tl(cpu_HI[1], cpu_HI[1]);
-            tcg_temp_free(t3);
-            tcg_temp_free(t2);
-        }
-        break;
-    default:
-        MIPS_INVAL("div1 TX79");
-        gen_reserved_instruction(ctx);
-        goto out;
-    }
- out:
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-}
-#endif
-
 static void gen_muldiv(DisasContext *ctx, uint32_t opc,
                        int acc, int rs, int rt)
 {
@@ -3521,138 +3386,6 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc,
     tcg_temp_free(t1);
 }
 
-/*
- * These MULT[U] and MADD[U] instructions implemented in for example
- * the Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core
- * architectures are special three-operand variants with the syntax
- *
- *     MULT[U][1] rd, rs, rt
- *
- * such that
- *
- *     (rd, LO, HI) <- rs * rt
- *
- * and
- *
- *     MADD[U][1] rd, rs, rt
- *
- * such that
- *
- *     (rd, LO, HI) <- (LO, HI) + rs * rt
- *
- * where the low-order 32-bits of the result is placed into both the
- * GPR rd and the special register LO. The high-order 32-bits of the
- * result is placed into the special register HI.
- *
- * If the GPR rd is omitted in assembly language, it is taken to be 0,
- * which is the zero register that always reads as 0.
- */
-static void gen_mul_txx9(DisasContext *ctx, uint32_t opc,
-                         int rd, int rs, int rt)
-{
-    TCGv t0 = tcg_temp_new();
-    TCGv t1 = tcg_temp_new();
-    int acc = 0;
-
-    gen_load_gpr(t0, rs);
-    gen_load_gpr(t1, rt);
-
-    switch (opc) {
-    case MMI_OPC_MULT1:
-        acc = 1;
-        /* Fall through */
-    case OPC_MULT:
-        {
-            TCGv_i32 t2 = tcg_temp_new_i32();
-            TCGv_i32 t3 = tcg_temp_new_i32();
-            tcg_gen_trunc_tl_i32(t2, t0);
-            tcg_gen_trunc_tl_i32(t3, t1);
-            tcg_gen_muls2_i32(t2, t3, t2, t3);
-            if (rd) {
-                tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
-            }
-            tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
-            tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
-            tcg_temp_free_i32(t2);
-            tcg_temp_free_i32(t3);
-        }
-        break;
-    case MMI_OPC_MULTU1:
-        acc = 1;
-        /* Fall through */
-    case OPC_MULTU:
-        {
-            TCGv_i32 t2 = tcg_temp_new_i32();
-            TCGv_i32 t3 = tcg_temp_new_i32();
-            tcg_gen_trunc_tl_i32(t2, t0);
-            tcg_gen_trunc_tl_i32(t3, t1);
-            tcg_gen_mulu2_i32(t2, t3, t2, t3);
-            if (rd) {
-                tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
-            }
-            tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
-            tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
-            tcg_temp_free_i32(t2);
-            tcg_temp_free_i32(t3);
-        }
-        break;
-    case MMI_OPC_MADD1:
-        acc = 1;
-        /* Fall through */
-    case MMI_OPC_MADD:
-        {
-            TCGv_i64 t2 = tcg_temp_new_i64();
-            TCGv_i64 t3 = tcg_temp_new_i64();
-
-            tcg_gen_ext_tl_i64(t2, t0);
-            tcg_gen_ext_tl_i64(t3, t1);
-            tcg_gen_mul_i64(t2, t2, t3);
-            tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
-            tcg_gen_add_i64(t2, t2, t3);
-            tcg_temp_free_i64(t3);
-            gen_move_low32(cpu_LO[acc], t2);
-            gen_move_high32(cpu_HI[acc], t2);
-            if (rd) {
-                gen_move_low32(cpu_gpr[rd], t2);
-            }
-            tcg_temp_free_i64(t2);
-        }
-        break;
-    case MMI_OPC_MADDU1:
-        acc = 1;
-        /* Fall through */
-    case MMI_OPC_MADDU:
-        {
-            TCGv_i64 t2 = tcg_temp_new_i64();
-            TCGv_i64 t3 = tcg_temp_new_i64();
-
-            tcg_gen_ext32u_tl(t0, t0);
-            tcg_gen_ext32u_tl(t1, t1);
-            tcg_gen_extu_tl_i64(t2, t0);
-            tcg_gen_extu_tl_i64(t3, t1);
-            tcg_gen_mul_i64(t2, t2, t3);
-            tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
-            tcg_gen_add_i64(t2, t2, t3);
-            tcg_temp_free_i64(t3);
-            gen_move_low32(cpu_LO[acc], t2);
-            gen_move_high32(cpu_HI[acc], t2);
-            if (rd) {
-                gen_move_low32(cpu_gpr[rd], t2);
-            }
-            tcg_temp_free_i64(t2);
-        }
-        break;
-    default:
-        MIPS_INVAL("mul/madd TXx9");
-        gen_reserved_instruction(ctx);
-        goto out;
-    }
-
- out:
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-}
-
 static void gen_cl(DisasContext *ctx, uint32_t opc,
                    int rd, int rs)
 {
@@ -12920,53 +12653,6 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
     }
 }
 
-static void decode_opc_special_tx79(CPUMIPSState *env, DisasContext *ctx)
-{
-    int rs = extract32(ctx->opcode, 21, 5);
-    int rt = extract32(ctx->opcode, 16, 5);
-    int rd = extract32(ctx->opcode, 11, 5);
-    uint32_t op1 = MASK_SPECIAL(ctx->opcode);
-
-    switch (op1) {
-    case OPC_MOVN:         /* Conditional move */
-    case OPC_MOVZ:
-        gen_cond_move(ctx, op1, rd, rs, rt);
-        break;
-    case OPC_MFHI:          /* Move from HI/LO */
-    case OPC_MFLO:
-        gen_HILO(ctx, op1, 0, rd);
-        break;
-    case OPC_MTHI:
-    case OPC_MTLO:          /* Move to HI/LO */
-        gen_HILO(ctx, op1, 0, rs);
-        break;
-    case OPC_MULT:
-    case OPC_MULTU:
-        gen_mul_txx9(ctx, op1, rd, rs, rt);
-        break;
-    case OPC_DIV:
-    case OPC_DIVU:
-        gen_muldiv(ctx, op1, 0, rs, rt);
-        break;
-#if defined(TARGET_MIPS64)
-    case OPC_DMULT:
-    case OPC_DMULTU:
-    case OPC_DDIV:
-    case OPC_DDIVU:
-        check_insn_opc_user_only(ctx, INSN_R5900);
-        gen_muldiv(ctx, op1, 0, rs, rt);
-        break;
-#endif
-    case OPC_JR:
-        gen_compute_branch(ctx, op1, 4, rs, 0, 0, 4);
-        break;
-    default:            /* Invalid */
-        MIPS_INVAL("special_tx79");
-        gen_reserved_instruction(ctx);
-        break;
-    }
-}
-
 static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd;
@@ -13016,6 +12702,7 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
     case OPC_DDIV:
     case OPC_DDIVU:
         check_insn(ctx, ISA_MIPS3);
+        check_insn_opc_user_only(ctx, INSN_R5900);
         check_mips_64(ctx);
         gen_muldiv(ctx, op1, 0, rs, rt);
         break;
@@ -13231,8 +12918,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
     default:
         if (ctx->insn_flags & ISA_MIPS_R6) {
             decode_opc_special_r6(env, ctx);
-        } else if (ctx->insn_flags & INSN_R5900) {
-            decode_opc_special_tx79(env, ctx);
         } else {
             decode_opc_special_legacy(env, ctx);
         }
@@ -13911,85 +13596,6 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
     }
 }
 
-
-#if defined(TARGET_MIPS64)
-
-static void decode_mmi(CPUMIPSState *env, DisasContext *ctx)
-{
-    uint32_t opc = MASK_MMI(ctx->opcode);
-    int rs = extract32(ctx->opcode, 21, 5);
-    int rt = extract32(ctx->opcode, 16, 5);
-    int rd = extract32(ctx->opcode, 11, 5);
-
-    switch (opc) {
-    case MMI_OPC_MULT1:
-    case MMI_OPC_MULTU1:
-    case MMI_OPC_MADD:
-    case MMI_OPC_MADDU:
-    case MMI_OPC_MADD1:
-    case MMI_OPC_MADDU1:
-        gen_mul_txx9(ctx, opc, rd, rs, rt);
-        break;
-    case MMI_OPC_DIV1:
-    case MMI_OPC_DIVU1:
-        gen_div1_tx79(ctx, opc, rs, rt);
-        break;
-    default:
-        MIPS_INVAL("TX79 MMI class");
-        gen_reserved_instruction(ctx);
-        break;
-    }
-}
-
-static void gen_mmi_sq(DisasContext *ctx, int base, int rt, int offset)
-{
-    gen_reserved_instruction(ctx);    /* TODO: MMI_OPC_SQ */
-}
-
-/*
- * The TX79-specific instruction Store Quadword
- *
- * +--------+-------+-------+------------------------+
- * | 011111 |  base |   rt  |           offset       | SQ
- * +--------+-------+-------+------------------------+
- *      6       5       5                 16
- *
- * has the same opcode as the Read Hardware Register instruction
- *
- * +--------+-------+-------+-------+-------+--------+
- * | 011111 | 00000 |   rt  |   rd  | 00000 | 111011 | RDHWR
- * +--------+-------+-------+-------+-------+--------+
- *      6       5       5       5       5        6
- *
- * that is required, trapped and emulated by the Linux kernel. However, all
- * RDHWR encodings yield address error exceptions on the TX79 since the SQ
- * offset is odd. Therefore all valid SQ instructions can execute normally.
- * In user mode, QEMU must verify the upper and lower 11 bits to distinguish
- * between SQ and RDHWR, as the Linux kernel does.
- */
-static void decode_mmi_sq(CPUMIPSState *env, DisasContext *ctx)
-{
-    int base = extract32(ctx->opcode, 21, 5);
-    int rt = extract32(ctx->opcode, 16, 5);
-    int offset = extract32(ctx->opcode, 0, 16);
-
-#ifdef CONFIG_USER_ONLY
-    uint32_t op1 = MASK_SPECIAL3(ctx->opcode);
-    uint32_t op2 = extract32(ctx->opcode, 6, 5);
-
-    if (base == 0 && op2 == 0 && op1 == OPC_RDHWR) {
-        int rd = extract32(ctx->opcode, 11, 5);
-
-        gen_rdhwr(ctx, rt, rd, 0);
-        return;
-    }
-#endif
-
-    gen_mmi_sq(ctx, base, rt, offset);
-}
-
-#endif
-
 static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd, sa;
@@ -14160,12 +13766,6 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
         decode_opc_special(env, ctx);
         break;
     case OPC_SPECIAL2:
-#if defined(TARGET_MIPS64)
-        if ((ctx->insn_flags & INSN_R5900) && (ctx->insn_flags & ASE_MMI)) {
-            decode_mmi(env, ctx);
-            break;
-        }
-#endif
         if (TARGET_LONG_BITS == 32 && (ctx->insn_flags & ASE_MXU)) {
             if (MASK_SPECIAL2(ctx->opcode) == OPC_MUL) {
                 gen_arith(ctx, OPC_MUL, rd, rs, rt);
@@ -14177,15 +13777,7 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
         decode_opc_special2_legacy(env, ctx);
         break;
     case OPC_SPECIAL3:
-#if defined(TARGET_MIPS64)
-        if (ctx->insn_flags & INSN_R5900) {
-            decode_mmi_sq(env, ctx);    /* MMI_OPC_SQ */
-        } else {
-            decode_opc_special3(env, ctx);
-        }
-#else
         decode_opc_special3(env, ctx);
-#endif
         break;
     case OPC_REGIMM:
         op1 = MASK_REGIMM(ctx->opcode);
diff --git a/target/mips/tcg/tx79.decode b/target/mips/tcg/tx79.decode
index 57d87a2076..8629b518bb 100644
--- a/target/mips/tcg/tx79.decode
+++ b/target/mips/tcg/tx79.decode
@@ -33,6 +33,20 @@ MTHI1           011100 .....  0000000000 00000 010001   @rs
 MFLO1           011100 0000000000  ..... 00000 010010   @rd
 MTLO1           011100 .....  0000000000 00000 010011   @rs
 
+# MUL
+# MULT/MULTU are reusing MIPS SPECIAL MAJOR_OP
+MULT            000000 ..... ..... ..... 00000 011000   @rs_rt_rd
+MULTU           000000 ..... ..... ..... 00000 011001   @rs_rt_rd
+# Rests are using SPECIAL2 encoding
+MADD            011100 ..... ..... ..... 00000 000000   @rs_rt_rd
+MADDU           011100 ..... ..... ..... 00000 000001   @rs_rt_rd
+MULT1           011100 ..... ..... ..... 00000 011000   @rs_rt_rd
+MULTU1          011100 ..... ..... ..... 00000 011001   @rs_rt_rd
+DIV1            011100 ..... ..... ..... 00000 011010   @rs_rt_rd
+DIVU1           011100 ..... ..... ..... 00000 011011   @rs_rt_rd
+MADD1           011100 ..... ..... ..... 00000 100000   @rs_rt_rd
+MADDU1          011100 ..... ..... ..... 00000 100001   @rs_rt_rd
+
 # MMI0
 
 PSUBW           011100 ..... ..... ..... 00001 001000   @rs_rt_rd
diff --git a/target/mips/tcg/tx79_translate.c b/target/mips/tcg/tx79_translate.c
index 4e479c2d10..434a1cf13e 100644
--- a/target/mips/tcg/tx79_translate.c
+++ b/target/mips/tcg/tx79_translate.c
@@ -369,7 +369,7 @@ static bool trans_LQ(DisasContext *ctx, arg_i *a)
     return true;
 }
 
-static bool trans_SQ(DisasContext *ctx, arg_i *a)
+static bool gen_SQ(DisasContext *ctx, arg_i *a)
 {
     TCGv_i64 t0 = tcg_temp_new_i64();
     TCGv addr = tcg_temp_new();
@@ -396,6 +396,32 @@ static bool trans_SQ(DisasContext *ctx, arg_i *a)
     return true;
 }
 
+#define RDHWR_MASK(op) (op & 0xffe0063f)
+#define OPC_RDHWR 0x7c00003b
+
+static bool trans_SQ(DisasContext *ctx, arg_i *a)
+{
+#ifdef CONFIG_USER_ONLY
+    /*
+    * that is required, trapped and emulated by the Linux kernel. However, all
+    * RDHWR encodings yield address error exceptions on the TX79 since the SQ
+    * offset is odd. Therefore all valid SQ instructions can execute normally.
+    * In user mode, QEMU must verify the upper and lower 11 bits to distinguish
+    * between SQ and RDHWR, as the Linux kernel does.
+    */
+    if (RDHWR_MASK(ctx->opcode) == OPC_RDHWR) {
+        int rd = extract32(ctx->opcode, 11, 5);
+        int rt = extract32(ctx->opcode, 16, 5);
+        int sel = extract32(ctx->opcode, 6, 3);
+
+        gen_rdhwr(ctx, rt, rd, sel);
+        return true;
+    }
+#endif
+
+    return gen_SQ(ctx, a);
+}
+
 /*
  *     Multiply and Divide (19 instructions)
  *     -------------------------------------
@@ -683,3 +709,180 @@ static bool trans_PROT3W(DisasContext *ctx, arg_r *a)
 
     return true;
 }
+
+/*
+ * These MULT[U] and MADD[U] instructions implemented in for example
+ * the Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core
+ * architectures are special three-operand variants with the syntax
+ *
+ *     MULT[U][1] rd, rs, rt
+ *
+ * such that
+ *
+ *     (rd, LO, HI) <- rs * rt
+ *
+ * and
+ *
+ *     MADD[U][1] rd, rs, rt
+ *
+ * such that
+ *
+ *     (rd, LO, HI) <- (LO, HI) + rs * rt
+ *
+ * where the low-order 32-bits of the result is placed into both the
+ * GPR rd and the special register LO. The high-order 32-bits of the
+ * result is placed into the special register HI.
+ *
+ * If the GPR rd is omitted in assembly language, it is taken to be 0,
+ * which is the zero register that always reads as 0.
+ */
+
+static bool gen_mult(DisasContext *ctx, arg_r *a, int acc,
+                       void (*func)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32))
+{
+    TCGv src1 = get_gpr(ctx, a->rs, EXT_NONE);
+    TCGv src2 = get_gpr(ctx, a->rt, EXT_NONE);
+    TCGv dst_lo = dest_lo(ctx, acc);
+    TCGv dst_hi = dest_hi(ctx, acc);
+    TCGv_i32 t1 = tcg_temp_new_i32();
+    TCGv_i32 t2 = tcg_temp_new_i32();
+
+    tcg_gen_trunc_tl_i32(t1, src1);
+    tcg_gen_trunc_tl_i32(t2, src2);
+
+    func(t1, t2, t1, t2);
+
+    tcg_gen_ext_i32_tl(dst_lo, t1);
+    tcg_gen_ext_i32_tl(dst_hi, t2);
+
+    gen_set_gpr(a->rd, dst_lo, EXT_NONE);
+    gen_set_lo(acc, dst_lo, EXT_NONE);
+    gen_set_hi(acc, dst_hi, EXT_NONE);
+
+    return true;
+}
+
+TRANS_6R(MULT, gen_mult, 0, tcg_gen_muls2_i32)
+TRANS_6R(MULTU, gen_mult, 0, tcg_gen_mulu2_i32)
+TRANS_6R(MULT1, gen_mult, 1, tcg_gen_muls2_i32)
+TRANS_6R(MULTU1, gen_mult, 1, tcg_gen_mulu2_i32)
+
+static bool gen_mul_addsub(DisasContext *ctx, arg_r *a, int acc, DisasExtend ext,
+                            void (*func)(TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv src1 = get_gpr(ctx, a->rs, ext);
+    TCGv src2 = get_gpr(ctx, a->rt, ext);
+    TCGv_i64 src3 = get_hilo(ctx, acc);
+    TCGv_i64 dst = dest_hilo(ctx, acc);
+    TCGv_i64 t2 = tcg_temp_new_i64();
+    TCGv_i64 t3 = tcg_temp_new_i64();
+
+    switch (ext) {
+    case EXT_SIGN:
+        tcg_gen_ext_tl_i64(t2, src1);
+        tcg_gen_ext_tl_i64(t3, src2);
+        break;
+    case EXT_ZERO:
+        tcg_gen_extu_tl_i64(t2, src1);
+        tcg_gen_extu_tl_i64(t3, src2);
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+
+    tcg_gen_mul_i64(dst, t2, t3);
+    tcg_temp_free_i64(t2);
+    tcg_temp_free_i64(t3);
+    func(dst, dst, src3);
+
+    gen_set_hilo(acc, dst);
+
+    return true;
+}
+
+TRANS(MADD, gen_mul_addsub, 0, EXT_SIGN, tcg_gen_add_i64)
+TRANS(MADDU, gen_mul_addsub, 0, EXT_ZERO, tcg_gen_add_i64)
+TRANS(MADD1, gen_mul_addsub, 1, EXT_SIGN, tcg_gen_add_i64)
+TRANS(MADDU1, gen_mul_addsub, 1, EXT_ZERO, tcg_gen_add_i64)
+
+static bool gen_div(DisasContext *ctx, arg_r *a, int acc,
+                    DisasExtend src_ext, DisasExtend dst_ext)
+{
+    TCGv temp1, temp2, zero, one, mone, min;
+    TCGv src1 = get_gpr(ctx, a->rs, src_ext);
+    TCGv src2 = get_gpr(ctx, a->rt, src_ext);
+    TCGv dst_lo = dest_lo(ctx, acc);
+    TCGv dst_hi = dest_hi(ctx, acc);
+
+    temp1 = tcg_temp_new();
+    temp2 = tcg_temp_new();
+    zero = tcg_constant_tl(0);
+    one = tcg_constant_tl(1);
+    mone = tcg_constant_tl(-1);
+    min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
+
+    /*
+     * If overflow, set temp2 to 1, else source2.
+     * This produces the required result of min.
+     */
+    tcg_gen_setcond_tl(TCG_COND_EQ, temp1, src1, min);
+    tcg_gen_setcond_tl(TCG_COND_EQ, temp2, src2, mone);
+    tcg_gen_and_tl(temp1, temp1, temp2);
+    tcg_gen_movcond_tl(TCG_COND_NE, temp2, temp1, zero, one, src2);
+
+    /*
+     * If div by zero, set temp1 to -1 and temp2 to 1 to
+     * produce the required result of -1.
+     */
+    tcg_gen_movcond_tl(TCG_COND_EQ, temp1, src2, zero, mone, src1);
+    tcg_gen_movcond_tl(TCG_COND_EQ, temp2, src2, zero, one, src2);
+
+    tcg_gen_div_tl(dst_lo, temp1, temp2);
+    tcg_gen_rem_tl(dst_hi, temp1, temp2);
+
+    tcg_temp_free(temp1);
+    tcg_temp_free(temp2);
+
+    gen_set_lo(acc, dst_lo, dst_ext);
+    gen_set_hi(acc, dst_hi, dst_ext);
+
+    return true;
+}
+
+static bool gen_divu(DisasContext *ctx, arg_r *a, int acc,
+                    DisasExtend src_ext, DisasExtend dst_ext)
+{
+    TCGv temp1, temp2, zero, one, max;
+    TCGv src1 = get_gpr(ctx, a->rs, src_ext);
+    TCGv src2 = get_gpr(ctx, a->rt, src_ext);
+    TCGv dst_lo = dest_lo(ctx, acc);
+    TCGv dst_hi = dest_hi(ctx, acc);
+
+    temp1 = tcg_temp_new();
+    temp2 = tcg_temp_new();
+    zero = tcg_constant_tl(0);
+    one = tcg_constant_tl(1);
+    max = tcg_constant_tl(~0);
+
+    /*
+     * If div by zero, set temp1 to max and temp2 to 1 to
+     * produce the required result of max.
+     */
+    tcg_gen_movcond_tl(TCG_COND_EQ, temp1, src2, zero, max, src1);
+    tcg_gen_movcond_tl(TCG_COND_EQ, temp2, src2, zero, one, src2);
+
+    tcg_gen_divu_tl(dst_lo, temp1, temp2);
+    tcg_gen_remu_tl(dst_hi, temp1, temp2);
+
+    tcg_temp_free(temp1);
+    tcg_temp_free(temp2);
+
+    gen_set_lo(acc, dst_lo, dst_ext);
+    gen_set_hi(acc, dst_hi, dst_ext);
+
+    return true;
+}
+
+TRANS(DIV1, gen_div, 1, EXT_SIGN, EXT_SIGN)
+TRANS(DIVU1, gen_divu, 1, EXT_ZERO, EXT_SIGN)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6/6] target/mips: Make MXU decoder standalone
  2022-10-24 15:23 [PATCH 0/6] MIPS decodetree conversion Jiaxun Yang
                   ` (4 preceding siblings ...)
  2022-10-24 15:23 ` [PATCH 5/6] target/mips: Move all tx79 instructions to decodetree Jiaxun Yang
@ 2022-10-24 15:23 ` Jiaxun Yang
  5 siblings, 0 replies; 8+ messages in thread
From: Jiaxun Yang @ 2022-10-24 15:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: f4bug, richard.henderson, Jiaxun Yang

MXU is treated as an ISA extension for now.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/tcg/mxu_translate.c | 98 ++++++++++++++++++---------------
 target/mips/tcg/translate.c     | 13 ++---
 2 files changed, 60 insertions(+), 51 deletions(-)

diff --git a/target/mips/tcg/mxu_translate.c b/target/mips/tcg/mxu_translate.c
index f52244e1b2..9be37da620 100644
--- a/target/mips/tcg/mxu_translate.c
+++ b/target/mips/tcg/mxu_translate.c
@@ -354,6 +354,8 @@
  *   Programming Manual", Ingenic Semiconductor Co, Ltd., revision June 2, 2017
  */
 
+#define OPC_SPECIAL2 (0x1C << 26)
+
 enum {
     OPC_MXU__POOL00  = 0x03,
     OPC_MXU_D16MUL   = 0x08,
@@ -1552,54 +1554,64 @@ bool decode_ase_mxu(DisasContext *ctx, uint32_t insn)
 {
     uint32_t opcode = extract32(insn, 0, 6);
 
-    if (opcode == OPC_MXU_S32M2I) {
-        gen_mxu_s32m2i(ctx);
-        return true;
+    if (MASK_OP_MAJOR(insn) != OPC_SPECIAL2) {
+        return false;
     }
 
-    if (opcode == OPC_MXU_S32I2M) {
+    switch (opcode) {
+    case OPC_MXU_S32M2I:
+        gen_mxu_s32m2i(ctx);
+        return true;
+    case OPC_MXU_S32I2M:
         gen_mxu_s32i2m(ctx);
         return true;
-    }
-
-    {
-        TCGv t_mxu_cr = tcg_temp_new();
-        TCGLabel *l_exit = gen_new_label();
-
-        gen_load_mxu_cr(t_mxu_cr);
-        tcg_gen_andi_tl(t_mxu_cr, t_mxu_cr, MXU_CR_MXU_EN);
-        tcg_gen_brcondi_tl(TCG_COND_NE, t_mxu_cr, MXU_CR_MXU_EN, l_exit);
+    case OPC_MXU__POOL00:
+    case OPC_MXU_D16MUL:
+    case OPC_MXU_D16MAC:
+    case OPC_MXU__POOL04:
+    case OPC_MXU_S8LDD:
+    case OPC_MXU__POOL16:
+    case OPC_MXU__POOL19:
+        {
+            TCGv t_mxu_cr = tcg_temp_new();
+            TCGLabel *l_exit = gen_new_label();
+
+            gen_load_mxu_cr(t_mxu_cr);
+            tcg_gen_andi_tl(t_mxu_cr, t_mxu_cr, MXU_CR_MXU_EN);
+            tcg_gen_brcondi_tl(TCG_COND_NE, t_mxu_cr, MXU_CR_MXU_EN, l_exit);
+
+            switch (opcode) {
+            case OPC_MXU__POOL00:
+                decode_opc_mxu__pool00(ctx);
+                break;
+            case OPC_MXU_D16MUL:
+                gen_mxu_d16mul(ctx);
+                break;
+            case OPC_MXU_D16MAC:
+                gen_mxu_d16mac(ctx);
+                break;
+            case OPC_MXU__POOL04:
+                decode_opc_mxu__pool04(ctx);
+                break;
+            case OPC_MXU_S8LDD:
+                gen_mxu_s8ldd(ctx);
+                break;
+            case OPC_MXU__POOL16:
+                decode_opc_mxu__pool16(ctx);
+                break;
+            case OPC_MXU__POOL19:
+                decode_opc_mxu__pool19(ctx);
+                break;
+            default:
+                MIPS_INVAL("decode_opc_mxu");
+                gen_reserved_instruction(ctx);
+            }
 
-        switch (opcode) {
-        case OPC_MXU__POOL00:
-            decode_opc_mxu__pool00(ctx);
-            break;
-        case OPC_MXU_D16MUL:
-            gen_mxu_d16mul(ctx);
-            break;
-        case OPC_MXU_D16MAC:
-            gen_mxu_d16mac(ctx);
-            break;
-        case OPC_MXU__POOL04:
-            decode_opc_mxu__pool04(ctx);
-            break;
-        case OPC_MXU_S8LDD:
-            gen_mxu_s8ldd(ctx);
-            break;
-        case OPC_MXU__POOL16:
-            decode_opc_mxu__pool16(ctx);
-            break;
-        case OPC_MXU__POOL19:
-            decode_opc_mxu__pool19(ctx);
-            break;
-        default:
-            MIPS_INVAL("decode_opc_mxu");
-            gen_reserved_instruction(ctx);
+            gen_set_label(l_exit);
+            tcg_temp_free(t_mxu_cr);
         }
-
-        gen_set_label(l_exit);
-        tcg_temp_free(t_mxu_cr);
+        return true;
+    default:
+        return false;
     }
-
-    return true;
 }
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index c8a3f63203..a5e89c528d 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -13766,14 +13766,6 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
         decode_opc_special(env, ctx);
         break;
     case OPC_SPECIAL2:
-        if (TARGET_LONG_BITS == 32 && (ctx->insn_flags & ASE_MXU)) {
-            if (MASK_SPECIAL2(ctx->opcode) == OPC_MUL) {
-                gen_arith(ctx, OPC_MUL, rd, rs, rt);
-            } else {
-                decode_ase_mxu(ctx, ctx->opcode);
-            }
-            break;
-        }
         decode_opc_special2_legacy(env, ctx);
         break;
     case OPC_SPECIAL3:
@@ -14484,6 +14476,11 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
     if (cpu_supports_isa(env, ASE_LMMI) && decode_ase_lmmi(ctx, ctx->opcode)) {
         return;
     }
+    if (TARGET_LONG_BITS == 32) {
+        if (cpu_supports_isa(env, ASE_MXU) && decode_ase_mxu(ctx, ctx->opcode)) {
+            return;
+        }
+    }
     if (ase_msa_available(env) && decode_ase_msa(ctx, ctx->opcode)) {
         return;
     }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/6] target/mips: Introduce register access helper functions
  2022-10-24 15:23 ` [PATCH 1/6] target/mips: Introduce register access helper functions Jiaxun Yang
@ 2022-10-24 22:47   ` Richard Henderson
  0 siblings, 0 replies; 8+ messages in thread
From: Richard Henderson @ 2022-10-24 22:47 UTC (permalink / raw)
  To: Jiaxun Yang, qemu-devel; +Cc: f4bug

On 10/25/22 01:23, Jiaxun Yang wrote:
> 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(-)
> 
> 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;

Remove as duplicate -- this is also in translate.h.  I'm surprised no compile error.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-10-24 22:55 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-24 15:23 [PATCH 0/6] MIPS decodetree conversion Jiaxun Yang
2022-10-24 15:23 ` [PATCH 1/6] target/mips: Introduce register access helper functions Jiaxun Yang
2022-10-24 22:47   ` Richard Henderson
2022-10-24 15:23 ` [PATCH 2/6] target/mips: Convert legacy arithmatic instructions to decodetree Jiaxun Yang
2022-10-24 15:23 ` [PATCH 3/6] tests/tcg/mips: Add mips32 arithmatic instruction test cases Jiaxun Yang
2022-10-24 15:23 ` [PATCH 4/6] target/mips: Split Loongson extention translation into standalone file Jiaxun Yang
2022-10-24 15:23 ` [PATCH 5/6] target/mips: Move all tx79 instructions to decodetree Jiaxun Yang
2022-10-24 15:23 ` [PATCH 6/6] target/mips: Make MXU decoder standalone Jiaxun Yang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).