]> git.proxmox.com Git - qemu.git/blobdiff - target-mips/translate.c
Use glib memory allocation and free functions
[qemu.git] / target-mips / translate.c
index d43d72deea1f3a942debdcc0b2a8c1242129784b..6c4e0d7675025d8432491a308580eaf35cf1cb9e 100644 (file)
@@ -27,7 +27,6 @@
 #include <inttypes.h>
 
 #include "cpu.h"
-#include "exec-all.h"
 #include "disas.h"
 #include "tcg-op.h"
 #include "qemu-common.h"
@@ -267,6 +266,19 @@ 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,
@@ -293,6 +305,20 @@ enum {
     OPC_BSHFL    = 0x20 | OPC_SPECIAL3,
     OPC_DBSHFL   = 0x24 | OPC_SPECIAL3,
     OPC_RDHWR    = 0x3B | 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,
 };
 
 /* BSHFL opcodes */
@@ -886,7 +912,7 @@ FOP_CONDS(abs, 1, ps, FMT_PS, 64)
 
 /* load/store instructions. */
 #define OP_LD(insn,fname)                                                 \
-static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \
+static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)   \
 {                                                                         \
     tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx);                        \
 }
@@ -902,7 +928,7 @@ OP_LD(ld,ld64);
 #undef OP_LD
 
 #define OP_ST(insn,fname)                                                  \
-static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, DisasContext *ctx) \
+static inline void op_st_##insn(TCGv arg1, TCGv arg2, DisasContext *ctx)   \
 {                                                                          \
     tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx);                        \
 }
@@ -916,7 +942,7 @@ OP_ST(sd,st64);
 
 #ifdef CONFIG_USER_ONLY
 #define OP_LD_ATOMIC(insn,fname)                                           \
-static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)  \
+static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)    \
 {                                                                          \
     TCGv t0 = tcg_temp_new();                                              \
     tcg_gen_mov_tl(t0, arg1);                                              \
@@ -927,7 +953,7 @@ static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)  \
 }
 #else
 #define OP_LD_ATOMIC(insn,fname)                                           \
-static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)  \
+static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)    \
 {                                                                          \
     gen_helper_2i(insn, ret, arg1, ctx->mem_idx);                          \
 }
@@ -940,7 +966,7 @@ OP_LD_ATOMIC(lld,ld64);
 
 #ifdef CONFIG_USER_ONLY
 #define OP_ST_ATOMIC(insn,fname,ldname,almask)                               \
-static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
+static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
 {                                                                            \
     TCGv t0 = tcg_temp_new();                                                \
     int l1 = gen_new_label();                                                \
@@ -964,7 +990,7 @@ static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ct
 }
 #else
 #define OP_ST_ATOMIC(insn,fname,ldname,almask)                               \
-static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
+static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
 {                                                                            \
     TCGv t0 = tcg_temp_new();                                                \
     gen_helper_3i(insn, t0, arg1, arg2, ctx->mem_idx);                       \
@@ -1005,43 +1031,45 @@ static target_ulong pc_relative_pc (DisasContext *ctx)
     return pc;
 }
 
-/* Load and store */
-static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
-                      int base, int16_t offset)
+/* Load */
+static void gen_ld (CPUState *env, DisasContext *ctx, uint32_t opc,
+                    int rt, int base, int16_t offset)
 {
-    const char *opn = "ldst";
-    TCGv t0 = tcg_temp_new();
-    TCGv t1 = tcg_temp_new();
+    const char *opn = "ld";
+    TCGv t0, t1;
+
+    if (rt == 0 && env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) {
+        /* Loongson CPU uses a load to zero register for prefetch.
+           We emulate it as a NOP. On other CPU we must perform the
+           actual memory access. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
 
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
     gen_base_offset_addr(ctx, t0, base, offset);
-    /* Don't do NOP if destination is zero: we must perform the actual
-       memory access. */
+
     switch (opc) {
 #if defined(TARGET_MIPS64)
     case OPC_LWU:
         save_cpu_state(ctx, 0);
-        op_ldst_lwu(t0, t0, ctx);
+        op_ld_lwu(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "lwu";
         break;
     case OPC_LD:
         save_cpu_state(ctx, 0);
-        op_ldst_ld(t0, t0, ctx);
+        op_ld_ld(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "ld";
         break;
     case OPC_LLD:
-        save_cpu_state(ctx, 0);
-        op_ldst_lld(t0, t0, ctx);
+        save_cpu_state(ctx, 1);
+        op_ld_lld(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "lld";
         break;
-    case OPC_SD:
-        save_cpu_state(ctx, 0);
-        gen_load_gpr(t1, rt);
-        op_ldst_sd(t1, t0, ctx);
-        opn = "sd";
-        break;
     case OPC_LDL:
         save_cpu_state(ctx, 1);
         gen_load_gpr(t1, rt);
@@ -1049,12 +1077,6 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
         gen_store_gpr(t1, rt);
         opn = "ldl";
         break;
-    case OPC_SDL:
-        save_cpu_state(ctx, 1);
-        gen_load_gpr(t1, rt);
-        gen_helper_2i(sdl, t1, t0, ctx->mem_idx);
-        opn = "sdl";
-        break;
     case OPC_LDR:
         save_cpu_state(ctx, 1);
         gen_load_gpr(t1, rt);
@@ -1062,72 +1084,50 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
         gen_store_gpr(t1, rt);
         opn = "ldr";
         break;
-    case OPC_SDR:
-        save_cpu_state(ctx, 1);
-        gen_load_gpr(t1, rt);
-        gen_helper_2i(sdr, t1, t0, ctx->mem_idx);
-        opn = "sdr";
-        break;
     case OPC_LDPC:
-        save_cpu_state(ctx, 1);
+        save_cpu_state(ctx, 0);
         tcg_gen_movi_tl(t1, pc_relative_pc(ctx));
         gen_op_addr_add(ctx, t0, t0, t1);
-        op_ldst_ld(t0, t0, ctx);
+        op_ld_ld(t0, t0, ctx);
         gen_store_gpr(t0, rt);
+        opn = "ldpc";
         break;
 #endif
     case OPC_LWPC:
-        save_cpu_state(ctx, 1);
+        save_cpu_state(ctx, 0);
         tcg_gen_movi_tl(t1, pc_relative_pc(ctx));
         gen_op_addr_add(ctx, t0, t0, t1);
-        op_ldst_lw(t0, t0, ctx);
+        op_ld_lw(t0, t0, ctx);
         gen_store_gpr(t0, rt);
+        opn = "lwpc";
         break;
     case OPC_LW:
         save_cpu_state(ctx, 0);
-        op_ldst_lw(t0, t0, ctx);
+        op_ld_lw(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "lw";
         break;
-    case OPC_SW:
-        save_cpu_state(ctx, 0);
-        gen_load_gpr(t1, rt);
-        op_ldst_sw(t1, t0, ctx);
-        opn = "sw";
-        break;
     case OPC_LH:
         save_cpu_state(ctx, 0);
-        op_ldst_lh(t0, t0, ctx);
+        op_ld_lh(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "lh";
         break;
-    case OPC_SH:
-        save_cpu_state(ctx, 0);
-        gen_load_gpr(t1, rt);
-        op_ldst_sh(t1, t0, ctx);
-        opn = "sh";
-        break;
     case OPC_LHU:
         save_cpu_state(ctx, 0);
-        op_ldst_lhu(t0, t0, ctx);
+        op_ld_lhu(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "lhu";
         break;
     case OPC_LB:
         save_cpu_state(ctx, 0);
-        op_ldst_lb(t0, t0, ctx);
+        op_ld_lb(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "lb";
         break;
-    case OPC_SB:
-        save_cpu_state(ctx, 0);
-        gen_load_gpr(t1, rt);
-        op_ldst_sb(t1, t0, ctx);
-        opn = "sb";
-        break;
     case OPC_LBU:
         save_cpu_state(ctx, 0);
-        op_ldst_lbu(t0, t0, ctx);
+        op_ld_lbu(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "lbu";
         break;
@@ -1138,12 +1138,6 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
         gen_store_gpr(t1, rt);
         opn = "lwl";
         break;
-    case OPC_SWL:
-        save_cpu_state(ctx, 1);
-        gen_load_gpr(t1, rt);
-        gen_helper_2i(swl, t1, t0, ctx->mem_idx);
-        opn = "swr";
-        break;
     case OPC_LWR:
         save_cpu_state(ctx, 1);
         gen_load_gpr(t1, rt);
@@ -1151,24 +1145,80 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
         gen_store_gpr(t1, rt);
         opn = "lwr";
         break;
-    case OPC_SWR:
-        save_cpu_state(ctx, 1);
-        gen_load_gpr(t1, rt);
-        gen_helper_2i(swr, t1, t0, ctx->mem_idx);
-        opn = "swr";
-        break;
     case OPC_LL:
         save_cpu_state(ctx, 1);
-        op_ldst_ll(t0, t0, ctx);
+        op_ld_ll(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "ll";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
 }
 
+/* Store */
+static void gen_st (DisasContext *ctx, uint32_t opc, int rt,
+                    int base, int16_t offset)
+{
+    const char *opn = "st";
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, base, offset);
+    gen_load_gpr(t1, rt);
+    switch (opc) {
+#if defined(TARGET_MIPS64)
+    case OPC_SD:
+        save_cpu_state(ctx, 0);
+        op_st_sd(t1, t0, ctx);
+        opn = "sd";
+        break;
+    case OPC_SDL:
+        save_cpu_state(ctx, 1);
+        gen_helper_2i(sdl, t1, t0, ctx->mem_idx);
+        opn = "sdl";
+        break;
+    case OPC_SDR:
+        save_cpu_state(ctx, 1);
+        gen_helper_2i(sdr, t1, t0, ctx->mem_idx);
+        opn = "sdr";
+        break;
+#endif
+    case OPC_SW:
+        save_cpu_state(ctx, 0);
+        op_st_sw(t1, t0, ctx);
+        opn = "sw";
+        break;
+    case OPC_SH:
+        save_cpu_state(ctx, 0);
+        op_st_sh(t1, t0, ctx);
+        opn = "sh";
+        break;
+    case OPC_SB:
+        save_cpu_state(ctx, 0);
+        op_st_sb(t1, t0, ctx);
+        opn = "sb";
+        break;
+    case OPC_SWL:
+        save_cpu_state(ctx, 1);
+        gen_helper_2i(swl, t1, t0, ctx->mem_idx);
+        opn = "swl";
+        break;
+    case OPC_SWR:
+        save_cpu_state(ctx, 1);
+        gen_helper_2i(swr, t1, t0, ctx->mem_idx);
+        opn = "swr";
+        break;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+
 /* Store conditional */
 static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
                          int base, int16_t offset)
@@ -1187,17 +1237,18 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
     switch (opc) {
 #if defined(TARGET_MIPS64)
     case OPC_SCD:
-        save_cpu_state(ctx, 0);
-        op_ldst_scd(t1, t0, rt, ctx);
+        save_cpu_state(ctx, 1);
+        op_st_scd(t1, t0, rt, ctx);
         opn = "scd";
         break;
 #endif
     case OPC_SC:
         save_cpu_state(ctx, 1);
-        op_ldst_sc(t1, t0, rt, ctx);
+        op_st_sc(t1, t0, rt, ctx);
         opn = "sc";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
     tcg_temp_free(t1);
     tcg_temp_free(t0);
@@ -1263,6 +1314,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
         generate_exception(ctx, EXCP_RI);
         goto out;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
  out:
     tcg_temp_free(t0);
@@ -1363,6 +1415,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
 }
 
@@ -1405,6 +1458,7 @@ static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t
         opn = "lui";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
 }
 
@@ -1432,6 +1486,7 @@ static void gen_slt_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t im
         opn = "sltiu";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
     tcg_temp_free(t0);
 }
@@ -1523,6 +1578,7 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
     tcg_temp_free(t0);
 }
@@ -1703,6 +1759,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
         opn = "mul";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
 }
 
@@ -1740,6 +1797,7 @@ static void gen_cond_move (CPUState *env, uint32_t opc, int rd, int rs, int rt)
         tcg_gen_movi_tl(cpu_gpr[rd], 0);
     gen_set_label(l1);
 
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
 }
 
@@ -1800,6 +1858,7 @@ static void gen_logic (CPUState *env, uint32_t opc, int rd, int rs, int rt)
         opn = "xor";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
 }
 
@@ -1829,6 +1888,7 @@ static void gen_slt (CPUState *env, uint32_t opc, int rd, int rs, int rt)
         opn = "sltu";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -1909,6 +1969,7 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -1948,6 +2009,7 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
         opn = "mtlo";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s", opn, regnames[reg]);
 }
 
@@ -2180,6 +2242,7 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
         generate_exception(ctx, EXCP_RI);
         goto out;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
  out:
     tcg_temp_free(t0);
@@ -2259,6 +2322,7 @@ static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc,
         goto out;
     }
     gen_store_gpr(t0, rd);
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
 
  out:
@@ -2299,10 +2363,226 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
     tcg_temp_free(t0);
 }
 
+/* Godson integer instructions */
+static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
+                                int rd, int rs, int rt)
+{
+    const char *opn = "loongson";
+    TCGv t0, t1;
+
+    if (rd == 0) {
+        /* Treat as NOP. */
+        MIPS_DEBUG("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]);
+        opn = "mult.g";
+        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]);
+        opn = "multu.g";
+        break;
+    case OPC_DIV_G_2E:
+    case OPC_DIV_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            int 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);
+        }
+        opn = "div.g";
+        break;
+    case OPC_DIVU_G_2E:
+    case OPC_DIVU_G_2F:
+        {
+            int l1 = gen_new_label();
+            int 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);
+        }
+        opn = "divu.g";
+        break;
+    case OPC_MOD_G_2E:
+    case OPC_MOD_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            int 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);
+        }
+        opn = "mod.g";
+        break;
+    case OPC_MODU_G_2E:
+    case OPC_MODU_G_2F:
+        {
+            int l1 = gen_new_label();
+            int 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);
+        }
+        opn = "modu.g";
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT_G_2E:
+    case OPC_DMULT_G_2F:
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        opn = "dmult.g";
+        break;
+    case OPC_DMULTU_G_2E:
+    case OPC_DMULTU_G_2F:
+        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
+        opn = "dmultu.g";
+        break;
+    case OPC_DDIV_G_2E:
+    case OPC_DDIV_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            int 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);
+        }
+        opn = "ddiv.g";
+        break;
+    case OPC_DDIVU_G_2E:
+    case OPC_DDIVU_G_2F:
+        {
+            int l1 = gen_new_label();
+            int 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);
+        }
+        opn = "ddivu.g";
+        break;
+    case OPC_DMOD_G_2E:
+    case OPC_DMOD_G_2F:
+        {
+            int l1 = gen_new_label();
+            int l2 = gen_new_label();
+            int 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);
+        }
+        opn = "dmod.g";
+        break;
+    case OPC_DMODU_G_2E:
+    case OPC_DMODU_G_2F:
+        {
+            int l1 = gen_new_label();
+            int 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);
+        }
+        opn = "dmodu.g";
+        break;
+#endif
+    }
+
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
 /* Traps */
 static void gen_trap (DisasContext *ctx, uint32_t opc,
                       int rs, int rt, int16_t imm)
@@ -2405,7 +2685,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
         likely(!ctx->singlestep_enabled)) {
         tcg_gen_goto_tb(n);
         gen_save_pc(dest);
-        tcg_gen_exit_tb((long)tb + n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
     } else {
         gen_save_pc(dest);
         if (ctx->singlestep_enabled) {
@@ -2764,7 +3044,7 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
     case OPC_DINSU:
         if (lsb > msb)
             goto fail;
-        mask = ((1ULL << (msb - lsb + 1)) - 1) << lsb;
+        mask = ((1ULL << (msb - lsb + 1)) - 1) << (lsb + 32);
         gen_load_gpr(t0, rt);
         tcg_gen_andi_tl(t0, t0, ~mask);
         tcg_gen_shli_tl(t1, t1, lsb + 32);
@@ -3129,8 +3409,10 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
             gen_helper_mfc0_count(arg);
             if (use_icount) {
                 gen_io_end();
-                ctx->bstate = BS_STOP;
             }
+            /* Break the TB to be able to take timer interrupts immediately
+               after reading count.  */
+            ctx->bstate = BS_STOP;
             rn = "Count";
             break;
         /* 6,7 are implementation dependent */
@@ -3467,6 +3749,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
     default:
        goto die;
     }
+    (void)rn; /* avoid a compiler warning */
     LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel);
     return;
 
@@ -4057,6 +4340,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
     default:
        goto die;
     }
+    (void)rn; /* avoid a compiler warning */
     LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel);
     /* For simplicity assume that all writes can cause interrupts.  */
     if (use_icount) {
@@ -4298,8 +4582,10 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
             gen_helper_mfc0_count(arg);
             if (use_icount) {
                 gen_io_end();
-                ctx->bstate = BS_STOP;
             }
+            /* Break the TB to be able to take timer interrupts immediately
+               after reading count.  */
+            ctx->bstate = BS_STOP;
             rn = "Count";
             break;
         /* 6,7 are implementation dependent */
@@ -4629,6 +4915,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
     default:
         goto die;
     }
+    (void)rn; /* avoid a compiler warning */
     LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel);
     return;
 
@@ -4927,7 +5214,17 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
         switch (sel) {
         case 0:
             save_cpu_state(ctx, 1);
+            /* Mark as an IO operation because we may trigger a software
+               interrupt.  */
+            if (use_icount) {
+                gen_io_start();
+            }
             gen_helper_mtc0_cause(arg);
+            if (use_icount) {
+                gen_io_end();
+            }
+            /* Stop translation as we may have triggered an intetrupt */
+            ctx->bstate = BS_STOP;
             rn = "Cause";
             break;
         default:
@@ -5210,6 +5507,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
     default:
         goto die;
     }
+    (void)rn; /* avoid a compiler warning */
     LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel);
     /* For simplicity assume that all writes can cause interrupts.  */
     if (use_icount) {
@@ -5670,6 +5968,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
         generate_exception(ctx, EXCP_RI);
         return;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
 }
 #endif /* !CONFIG_USER_ONLY */
@@ -5779,6 +6078,7 @@ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
         generate_exception (ctx, EXCP_RI);
         goto out;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
                ctx->hflags, btarget);
     ctx->btarget = btarget;
@@ -6008,6 +6308,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
         generate_exception (ctx, EXCP_RI);
         goto out;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
 
  out:
@@ -7335,6 +7636,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         generate_exception (ctx, EXCP_RI);
         return;
     }
+    (void)opn; /* avoid a compiler warning */
     switch (optype) {
     case BINOP:
         MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
@@ -7447,6 +7749,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
         break;
     }
     tcg_temp_free(t0);
+    (void)opn; (void)store; /* avoid compiler warnings */
     MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd],
                regnames[index], regnames[base]);
 }
@@ -7720,6 +8023,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
         generate_exception (ctx, EXCP_RI);
         return;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr],
                fregnames[fs], fregnames[ft]);
 }
@@ -8003,22 +8307,22 @@ static void gen_mips16_save (DisasContext *ctx,
     case 4:
         gen_base_offset_addr(ctx, t0, 29, 12);
         gen_load_gpr(t1, 7);
-        op_ldst_sw(t1, t0, ctx);
+        op_st_sw(t1, t0, ctx);
         /* Fall through */
     case 3:
         gen_base_offset_addr(ctx, t0, 29, 8);
         gen_load_gpr(t1, 6);
-        op_ldst_sw(t1, t0, ctx);
+        op_st_sw(t1, t0, ctx);
         /* Fall through */
     case 2:
         gen_base_offset_addr(ctx, t0, 29, 4);
         gen_load_gpr(t1, 5);
-        op_ldst_sw(t1, t0, ctx);
+        op_st_sw(t1, t0, ctx);
         /* Fall through */
     case 1:
         gen_base_offset_addr(ctx, t0, 29, 0);
         gen_load_gpr(t1, 4);
-        op_ldst_sw(t1, t0, ctx);
+        op_st_sw(t1, t0, ctx);
     }
 
     gen_load_gpr(t0, 29);
@@ -8026,7 +8330,7 @@ static void gen_mips16_save (DisasContext *ctx,
 #define DECR_AND_STORE(reg) do {                \
         tcg_gen_subi_tl(t0, t0, 4);             \
         gen_load_gpr(t1, reg);                  \
-        op_ldst_sw(t1, t0, ctx);                \
+        op_st_sw(t1, t0, ctx);                  \
     } while (0)
 
     if (do_ra) {
@@ -8126,7 +8430,7 @@ static void gen_mips16_restore (DisasContext *ctx,
 
 #define DECR_AND_LOAD(reg) do {                 \
         tcg_gen_subi_tl(t0, t0, 4);             \
-        op_ldst_lw(t1, t0, ctx);                \
+        op_ld_lw(t1, t0, ctx);                  \
         gen_store_gpr(t1, reg);                 \
     } while (0)
 
@@ -8244,17 +8548,17 @@ static void decode_i64_mips16 (CPUState *env, DisasContext *ctx,
     case I64_LDSP:
         check_mips_64(ctx);
         offset = extended ? offset : offset << 3;
-        gen_ldst(ctx, OPC_LD, ry, 29, offset);
+        gen_ld(env, ctx, OPC_LD, ry, 29, offset);
         break;
     case I64_SDSP:
         check_mips_64(ctx);
         offset = extended ? offset : offset << 3;
-        gen_ldst(ctx, OPC_SD, ry, 29, offset);
+        gen_st(ctx, OPC_SD, ry, 29, offset);
         break;
     case I64_SDRASP:
         check_mips_64(ctx);
         offset = extended ? offset : (ctx->opcode & 0xff) << 3;
-        gen_ldst(ctx, OPC_SD, 31, 29, offset);
+        gen_st(ctx, OPC_SD, 31, 29, offset);
         break;
     case I64_DADJSP:
         check_mips_64(ctx);
@@ -8266,7 +8570,7 @@ static void decode_i64_mips16 (CPUState *env, DisasContext *ctx,
             generate_exception(ctx, EXCP_RI);
         } else {
             offset = extended ? offset : offset << 3;
-            gen_ldst(ctx, OPC_LDPC, ry, 0, offset);
+            gen_ld(env, ctx, OPC_LDPC, ry, 0, offset);
         }
         break;
     case I64_DADDIU5:
@@ -8350,7 +8654,7 @@ static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx,
 #if defined(TARGET_MIPS64)
     case M16_OPC_LD:
             check_mips_64(ctx);
-        gen_ldst(ctx, OPC_LD, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LD, ry, rx, offset);
         break;
 #endif
     case M16_OPC_RRIA:
@@ -8387,7 +8691,7 @@ static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx,
             gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1);
             break;
         case I8_SWRASP:
-            gen_ldst(ctx, OPC_SW, 31, 29, imm);
+            gen_st(ctx, OPC_SW, 31, 29, imm);
             break;
         case I8_ADJSP:
             gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm);
@@ -8426,46 +8730,46 @@ static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx,
         break;
 #if defined(TARGET_MIPS64)
     case M16_OPC_SD:
-        gen_ldst(ctx, OPC_SD, ry, rx, offset);
+        gen_st(ctx, OPC_SD, ry, rx, offset);
         break;
 #endif
     case M16_OPC_LB:
-        gen_ldst(ctx, OPC_LB, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LB, ry, rx, offset);
         break;
     case M16_OPC_LH:
-        gen_ldst(ctx, OPC_LH, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LH, ry, rx, offset);
         break;
     case M16_OPC_LWSP:
-        gen_ldst(ctx, OPC_LW, rx, 29, offset);
+        gen_ld(env, ctx, OPC_LW, rx, 29, offset);
         break;
     case M16_OPC_LW:
-        gen_ldst(ctx, OPC_LW, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LW, ry, rx, offset);
         break;
     case M16_OPC_LBU:
-        gen_ldst(ctx, OPC_LBU, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LBU, ry, rx, offset);
         break;
     case M16_OPC_LHU:
-        gen_ldst(ctx, OPC_LHU, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LHU, ry, rx, offset);
         break;
     case M16_OPC_LWPC:
-        gen_ldst(ctx, OPC_LWPC, rx, 0, offset);
+        gen_ld(env, ctx, OPC_LWPC, rx, 0, offset);
         break;
 #if defined(TARGET_MIPS64)
     case M16_OPC_LWU:
-        gen_ldst(ctx, OPC_LWU, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LWU, ry, rx, offset);
         break;
 #endif
     case M16_OPC_SB:
-        gen_ldst(ctx, OPC_SB, ry, rx, offset);
+        gen_st(ctx, OPC_SB, ry, rx, offset);
         break;
     case M16_OPC_SH:
-        gen_ldst(ctx, OPC_SH, ry, rx, offset);
+        gen_st(ctx, OPC_SH, ry, rx, offset);
         break;
     case M16_OPC_SWSP:
-        gen_ldst(ctx, OPC_SW, rx, 29, offset);
+        gen_st(ctx, OPC_SW, rx, 29, offset);
         break;
     case M16_OPC_SW:
-        gen_ldst(ctx, OPC_SW, ry, rx, offset);
+        gen_st(ctx, OPC_SW, ry, rx, offset);
         break;
 #if defined(TARGET_MIPS64)
     case M16_OPC_I64:
@@ -8558,7 +8862,7 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
 #if defined(TARGET_MIPS64)
     case M16_OPC_LD:
         check_mips_64(ctx);
-        gen_ldst(ctx, OPC_LD, ry, rx, offset << 3);
+        gen_ld(env, ctx, OPC_LD, ry, rx, offset << 3);
         break;
 #endif
     case M16_OPC_RRIA:
@@ -8613,7 +8917,7 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
                                    ((int8_t)ctx->opcode) << 1);
                 break;
             case I8_SWRASP:
-                gen_ldst(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
+                gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
                 break;
             case I8_ADJSP:
                 gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29,
@@ -8677,47 +8981,47 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
 #if defined(TARGET_MIPS64)
     case M16_OPC_SD:
         check_mips_64(ctx);
-        gen_ldst(ctx, OPC_SD, ry, rx, offset << 3);
+        gen_st(ctx, OPC_SD, ry, rx, offset << 3);
         break;
 #endif
     case M16_OPC_LB:
-        gen_ldst(ctx, OPC_LB, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LB, ry, rx, offset);
         break;
     case M16_OPC_LH:
-        gen_ldst(ctx, OPC_LH, ry, rx, offset << 1);
+        gen_ld(env, ctx, OPC_LH, ry, rx, offset << 1);
         break;
     case M16_OPC_LWSP:
-        gen_ldst(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2);
+        gen_ld(env, ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2);
         break;
     case M16_OPC_LW:
-        gen_ldst(ctx, OPC_LW, ry, rx, offset << 2);
+        gen_ld(env, ctx, OPC_LW, ry, rx, offset << 2);
         break;
     case M16_OPC_LBU:
-        gen_ldst(ctx, OPC_LBU, ry, rx, offset);
+        gen_ld(env, ctx, OPC_LBU, ry, rx, offset);
         break;
     case M16_OPC_LHU:
-        gen_ldst(ctx, OPC_LHU, ry, rx, offset << 1);
+        gen_ld(env, ctx, OPC_LHU, ry, rx, offset << 1);
         break;
     case M16_OPC_LWPC:
-        gen_ldst(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2);
+        gen_ld(env, ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2);
         break;
 #if defined (TARGET_MIPS64)
     case M16_OPC_LWU:
         check_mips_64(ctx);
-        gen_ldst(ctx, OPC_LWU, ry, rx, offset << 2);
+        gen_ld(env, ctx, OPC_LWU, ry, rx, offset << 2);
         break;
 #endif
     case M16_OPC_SB:
-        gen_ldst(ctx, OPC_SB, ry, rx, offset);
+        gen_st(ctx, OPC_SB, ry, rx, offset);
         break;
     case M16_OPC_SH:
-        gen_ldst(ctx, OPC_SH, ry, rx, offset << 1);
+        gen_st(ctx, OPC_SH, ry, rx, offset << 1);
         break;
     case M16_OPC_SWSP:
-        gen_ldst(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2);
+        gen_st(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2);
         break;
     case M16_OPC_SW:
-        gen_ldst(ctx, OPC_SW, ry, rx, offset << 2);
+        gen_st(ctx, OPC_SW, ry, rx, offset << 2);
         break;
     case M16_OPC_RRR:
         {
@@ -9631,7 +9935,7 @@ static void gen_ldxs (DisasContext *ctx, int base, int index, int rd)
     }
 
     save_cpu_state(ctx, 0);
-    op_ldst_lw(t1, t0, ctx);
+    op_ld_lw(t1, t0, ctx);
     gen_store_gpr(t1, rd);
 
     tcg_temp_free(t0);
@@ -9657,47 +9961,48 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
     switch (opc) {
     case LWP:
         save_cpu_state(ctx, 0);
-        op_ldst_lw(t1, t0, ctx);
+        op_ld_lw(t1, t0, ctx);
         gen_store_gpr(t1, rd);
         tcg_gen_movi_tl(t1, 4);
         gen_op_addr_add(ctx, t0, t0, t1);
-        op_ldst_lw(t1, t0, ctx);
+        op_ld_lw(t1, t0, ctx);
         gen_store_gpr(t1, rd+1);
         opn = "lwp";
         break;
     case SWP:
-        save_cpu_state(ctx, 1);
+        save_cpu_state(ctx, 0);
         gen_load_gpr(t1, rd);
-        op_ldst_sw(t1, t0, ctx);
+        op_st_sw(t1, t0, ctx);
         tcg_gen_movi_tl(t1, 4);
         gen_op_addr_add(ctx, t0, t0, t1);
         gen_load_gpr(t1, rd+1);
-        op_ldst_sw(t1, t0, ctx);
+        op_st_sw(t1, t0, ctx);
         opn = "swp";
         break;
 #ifdef TARGET_MIPS64
     case LDP:
         save_cpu_state(ctx, 0);
-        op_ldst_ld(t1, t0, ctx);
+        op_ld_ld(t1, t0, ctx);
         gen_store_gpr(t1, rd);
         tcg_gen_movi_tl(t1, 8);
         gen_op_addr_add(ctx, t0, t0, t1);
-        op_ldst_ld(t1, t0, ctx);
+        op_ld_ld(t1, t0, ctx);
         gen_store_gpr(t1, rd+1);
         opn = "ldp";
         break;
     case SDP:
-        save_cpu_state(ctx, 1);
+        save_cpu_state(ctx, 0);
         gen_load_gpr(t1, rd);
-        op_ldst_sd(t1, t0, ctx);
+        op_st_sd(t1, t0, ctx);
         tcg_gen_movi_tl(t1, 8);
         gen_op_addr_add(ctx, t0, t0, t1);
         gen_load_gpr(t1, rd+1);
-        op_ldst_sd(t1, t0, ctx);
+        op_st_sd(t1, t0, ctx);
         opn = "sdp";
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s, %s, %d(%s)", opn, regnames[rd], offset, regnames[base]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -10798,40 +11103,44 @@ static void decode_micromips32_opc (CPUState *env, DisasContext *ctx,
         switch (minor) {
         case LWL:
             mips32_op = OPC_LWL;
-            goto do_ldst_lr;
+            goto do_ld_lr;
         case SWL:
             mips32_op = OPC_SWL;
-            goto do_ldst_lr;
+            goto do_st_lr;
         case LWR:
             mips32_op = OPC_LWR;
-            goto do_ldst_lr;
+            goto do_ld_lr;
         case SWR:
             mips32_op = OPC_SWR;
-            goto do_ldst_lr;
+            goto do_st_lr;
 #if defined(TARGET_MIPS64)
         case LDL:
             mips32_op = OPC_LDL;
-            goto do_ldst_lr;
+            goto do_ld_lr;
         case SDL:
             mips32_op = OPC_SDL;
-            goto do_ldst_lr;
+            goto do_st_lr;
         case LDR:
             mips32_op = OPC_LDR;
-            goto do_ldst_lr;
+            goto do_ld_lr;
         case SDR:
             mips32_op = OPC_SDR;
-            goto do_ldst_lr;
+            goto do_st_lr;
         case LWU:
             mips32_op = OPC_LWU;
-            goto do_ldst_lr;
+            goto do_ld_lr;
         case LLD:
             mips32_op = OPC_LLD;
-            goto do_ldst_lr;
+            goto do_ld_lr;
 #endif
         case LL:
             mips32_op = OPC_LL;
-        do_ldst_lr:
-            gen_ldst(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));
+            goto do_ld_lr;
+        do_ld_lr:
+            gen_ld(env, ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+        do_st_lr:
+            gen_st(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));
             break;
         case SC:
             gen_st_cond(ctx, OPC_SC, rt, rs, SIMM(ctx->opcode, 0, 12));
@@ -10935,37 +11244,41 @@ static void decode_micromips32_opc (CPUState *env, DisasContext *ctx,
         /* Loads and stores */
     case LB32:
         mips32_op = OPC_LB;
-        goto do_ldst;
+        goto do_ld;
     case LBU32:
         mips32_op = OPC_LBU;
-        goto do_ldst;
+        goto do_ld;
     case LH32:
         mips32_op = OPC_LH;
-        goto do_ldst;
+        goto do_ld;
     case LHU32:
         mips32_op = OPC_LHU;
-        goto do_ldst;
+        goto do_ld;
     case LW32:
         mips32_op = OPC_LW;
-        goto do_ldst;
+        goto do_ld;
 #ifdef TARGET_MIPS64
     case LD32:
         mips32_op = OPC_LD;
-        goto do_ldst;
+        goto do_ld;
     case SD32:
         mips32_op = OPC_SD;
-        goto do_ldst;
+        goto do_st;
 #endif
     case SB32:
         mips32_op = OPC_SB;
-        goto do_ldst;
+        goto do_st;
     case SH32:
         mips32_op = OPC_SH;
-        goto do_ldst;
+        goto do_st;
     case SW32:
         mips32_op = OPC_SW;
-    do_ldst:
-        gen_ldst(ctx, mips32_op, rt, rs, imm);
+        goto do_st;
+    do_ld:
+        gen_ld(env, ctx, mips32_op, rt, rs, imm);
+        break;
+    do_st:
+        gen_st(ctx, mips32_op, rt, rs, imm);
         break;
     default:
         generate_exception(ctx, EXCP_RI);
@@ -11115,7 +11428,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int rb = 28;            /* GP */
             int16_t offset = SIMM(ctx->opcode, 0, 7) << 2;
 
-            gen_ldst(ctx, OPC_LW, rd, rb, offset);
+            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
         }
         break;
     case POOL16F:
@@ -11147,7 +11460,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int16_t offset = ZIMM(ctx->opcode, 0, 4);
             offset = (offset == 0xf ? -1 : offset);
 
-            gen_ldst(ctx, OPC_LBU, rd, rb, offset);
+            gen_ld(env, ctx, OPC_LBU, rd, rb, offset);
         }
         break;
     case LHU16:
@@ -11156,7 +11469,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int rb = mmreg(uMIPS_RS(ctx->opcode));
             int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;
 
-            gen_ldst(ctx, OPC_LHU, rd, rb, offset);
+            gen_ld(env, ctx, OPC_LHU, rd, rb, offset);
         }
         break;
     case LWSP16:
@@ -11165,7 +11478,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int rb = 29;            /* SP */
             int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;
 
-            gen_ldst(ctx, OPC_LW, rd, rb, offset);
+            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
         }
         break;
     case LW16:
@@ -11174,7 +11487,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int rb = mmreg(uMIPS_RS(ctx->opcode));
             int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;
 
-            gen_ldst(ctx, OPC_LW, rd, rb, offset);
+            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
         }
         break;
     case SB16:
@@ -11183,7 +11496,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int rb = mmreg(uMIPS_RS(ctx->opcode));
             int16_t offset = ZIMM(ctx->opcode, 0, 4);
 
-            gen_ldst(ctx, OPC_SB, rd, rb, offset);
+            gen_st(ctx, OPC_SB, rd, rb, offset);
         }
         break;
     case SH16:
@@ -11192,7 +11505,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int rb = mmreg(uMIPS_RS(ctx->opcode));
             int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;
 
-            gen_ldst(ctx, OPC_SH, rd, rb, offset);
+            gen_st(ctx, OPC_SH, rd, rb, offset);
         }
         break;
     case SWSP16:
@@ -11201,7 +11514,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int rb = 29;            /* SP */
             int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;
 
-            gen_ldst(ctx, OPC_SW, rd, rb, offset);
+            gen_st(ctx, OPC_SW, rd, rb, offset);
         }
         break;
     case SW16:
@@ -11210,7 +11523,7 @@ static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branc
             int rb = mmreg(uMIPS_RS(ctx->opcode));
             int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;
 
-            gen_ldst(ctx, OPC_SW, rd, rb, offset);
+            gen_st(ctx, OPC_SW, rd, rb, offset);
         }
         break;
     case MOVE16:
@@ -11350,7 +11663,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
             break;
         case OPC_MOVN:         /* Conditional move */
         case OPC_MOVZ:
-            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
+            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32 |
+                                 INSN_LOONGSON2E | INSN_LOONGSON2F);
             gen_cond_move(env, op1, rd, rs, rt);
             break;
         case OPC_ADD ... OPC_SUBU:
@@ -11565,6 +11879,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
             }
             /* Treat as NOP. */
             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(env, ctx, INSN_LOONGSON2F);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            break;
 #if defined(TARGET_MIPS64)
         case OPC_DCLO:
         case OPC_DCLZ:
@@ -11572,6 +11895,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
             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(env, ctx, INSN_LOONGSON2F);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            break;
 #endif
         default:            /* Invalid */
             MIPS_INVAL("special2");
@@ -11620,6 +11952,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
                 tcg_temp_free(t0);
             }
             break;
+        case OPC_DIV_G_2E ... OPC_DIVU_G_2E:
+        case OPC_MULT_G_2E ... OPC_MULTU_G_2E:
+        case OPC_MOD_G_2E ... OPC_MODU_G_2E:
+            check_insn(env, ctx, INSN_LOONGSON2E);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            break;
 #if defined(TARGET_MIPS64)
         case OPC_DEXTM ... OPC_DEXT:
         case OPC_DINSM ... OPC_DINS:
@@ -11633,6 +11971,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
             op2 = MASK_DBSHFL(ctx->opcode);
             gen_bshfl(ctx, op2, rt, rd);
             break;
+        case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
+        case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
+        case OPC_DMOD_G_2E ... OPC_DMODU_G_2E:
+            check_insn(env, ctx, INSN_LOONGSON2E);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            break;
 #endif
         default:            /* Invalid */
             MIPS_INVAL("special3");
@@ -11692,22 +12036,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
                 switch (op2) {
                 case OPC_DMT:
                     check_insn(env, ctx, ASE_MT);
-                    gen_helper_dmt(t0, t0);
+                    gen_helper_dmt(t0);
                     gen_store_gpr(t0, rt);
                     break;
                 case OPC_EMT:
                     check_insn(env, ctx, ASE_MT);
-                    gen_helper_emt(t0, t0);
+                    gen_helper_emt(t0);
                     gen_store_gpr(t0, rt);
                     break;
                 case OPC_DVPE:
                     check_insn(env, ctx, ASE_MT);
-                    gen_helper_dvpe(t0, t0);
+                    gen_helper_dvpe(t0);
                     gen_store_gpr(t0, rt);
                     break;
                 case OPC_EVPE:
                     check_insn(env, ctx, ASE_MT);
-                    gen_helper_evpe(t0, t0);
+                    gen_helper_evpe(t0);
                     gen_store_gpr(t0, rt);
                     break;
                 case OPC_DI:
@@ -11774,10 +12118,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
          *is_branch = 1;
          break;
     case OPC_LB ... OPC_LWR: /* Load and stores */
+    case OPC_LL:
+         gen_ld(env, ctx, op, rt, rs, imm);
+         break;
     case OPC_SB ... OPC_SW:
     case OPC_SWR:
-    case OPC_LL:
-         gen_ldst(ctx, op, rt, rs, imm);
+         gen_st(ctx, op, rt, rs, imm);
          break;
     case OPC_SC:
          gen_st_cond(ctx, op, rt, rs, imm);
@@ -11903,13 +12249,17 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
     /* MIPS64 opcodes */
     case OPC_LWU:
     case OPC_LDL ... OPC_LDR:
-    case OPC_SDL ... OPC_SDR:
     case OPC_LLD:
     case OPC_LD:
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_ld(env, ctx, op, rt, rs, imm);
+        break;
+    case OPC_SDL ... OPC_SDR:
     case OPC_SD:
         check_insn(env, ctx, ISA_MIPS3);
         check_mips_64(ctx);
-        gen_ldst(ctx, op, rt, rs, imm);
+        gen_st(ctx, op, rt, rs, imm);
         break;
     case OPC_SCD:
         check_insn(env, ctx, ISA_MIPS3);
@@ -12057,7 +12407,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     } else {
         switch (ctx.bstate) {
         case BS_STOP:
-            gen_helper_interrupt_restart();
             gen_goto_tb(&ctx, 0, ctx.pc);
             break;
         case BS_NONE:
@@ -12065,7 +12414,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
             gen_goto_tb(&ctx, 0, ctx.pc);
             break;
         case BS_EXCP:
-            gen_helper_interrupt_restart();
             tcg_gen_exit_tb(0);
             break;
         case BS_BRANCH:
@@ -12105,8 +12453,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-static void fpu_dump_state(CPUState *env, FILE *f,
-                           int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
+static void fpu_dump_state(CPUState *env, FILE *f, fprintf_function fpu_fprintf,
                            int flags)
 {
     int i;
@@ -12135,8 +12482,8 @@ static void fpu_dump_state(CPUState *env, FILE *f,
     } while(0)
 
 
-    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d  fp_status 0x%08x(0x%02x)\n",
-                env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, env->active_fpu.fp_status,
+    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d  fp_status 0x%02x\n",
+                env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64,
                 get_float_exception_flags(&env->active_fpu.fp_status));
     for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
         fpu_fprintf(f, "%3s: ", fregnames[i]);
@@ -12154,7 +12501,7 @@ static void fpu_dump_state(CPUState *env, FILE *f,
 
 static void
 cpu_mips_check_sign_extensions (CPUState *env, FILE *f,
-                                int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                                fprintf_function cpu_fprintf,
                                 int flags)
 {
     int i;
@@ -12180,8 +12527,7 @@ cpu_mips_check_sign_extensions (CPUState *env, FILE *f,
 }
 #endif
 
-void cpu_dump_state (CPUState *env, FILE *f,
-                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                      int flags)
 {
     int i;
@@ -12272,7 +12618,7 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model)
     def = cpu_mips_find_by_name(cpu_model);
     if (!def)
         return NULL;
-    env = qemu_mallocz(sizeof(CPUMIPSState));
+    env = g_malloc0(sizeof(CPUMIPSState));
     env->cpu_model = def;
     env->cpu_model_str = cpu_model;
 
@@ -12363,8 +12709,7 @@ void cpu_reset (CPUMIPSState *env)
     env->CP0_Random = env->tlb->nb_tlb - 1;
     env->tlb->tlb_in_use = env->tlb->nb_tlb;
     env->CP0_Wired = 0;
-    /* SMP not implemented */
-    env->CP0_EBase = 0x80000000;
+    env->CP0_EBase = 0x80000000 | (env->cpu_index & 0x3FF);
     env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
     /* vectored interrupts not implemented, timer on int 7,
        no performance counters. */
@@ -12391,8 +12736,7 @@ void cpu_reset (CPUMIPSState *env)
     env->exception_index = EXCP_NONE;
 }
 
-void gen_pc_load(CPUState *env, TranslationBlock *tb,
-                unsigned long searched_pc, int pc_pos, void *puc)
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
 {
     env->active_tc.PC = gen_opc_pc[pc_pos];
     env->hflags &= ~MIPS_HFLAG_BMASK;