All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3
@ 2010-06-08 20:29 Nathan Froyd
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 1/8] target-mips: define constants for magic numbers Nathan Froyd
                   ` (8 more replies)
  0 siblings, 9 replies; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien

This patch series adds support for the microMIPS ASE.  microMIPS is a
new ASE similar to MIPS16, but re-encodes the entire instruction set
into 16-bit and 32-bit instructions--in contrast to MIPS16, which
re-encodes only integer instructions.  The mechanisms for going in and
out of microMIPS mode are identical to those for MIPS16; a given chip
cannot support both ASEs simultaneously.

changes from v2:
  give actual name to FOP constants; assign names to FOPs for c{,abs}
  fix up coding style violations
  fix helpers for recent ldl_*/stl_* prototype changes
  split out mips16-related changes into separate patch
  group patches more logically

changes from v1:
  fix re-introduction of previously deleted code noted by rth

Nathan Froyd (8):
  target-mips: define constants for magic numbers
  target-mips: refactor c{,abs}.cond.fmt insns
  target-mips: mips16 cleanups
  target-mips: microMIPS ASE support
  target-mips: add microMIPS CPUs
  target-mips: add microMIPS exception handler support
  linux-user: honor low bit of entry PC for MIPS
  hw: honor low bit in mipssim machine

 hw/mips_mipssim.c            |    5 +-
 linux-user/main.c            |    5 +-
 target-mips/cpu.h            |    1 +
 target-mips/helper.c         |   21 +-
 target-mips/helper.h         |    9 +
 target-mips/mips-defs.h      |    1 +
 target-mips/op_helper.c      |  136 ++
 target-mips/translate.c      | 3015 ++++++++++++++++++++++++++++++++++++++----
 target-mips/translate_init.c |   61 +
 9 files changed, 3009 insertions(+), 245 deletions(-)

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

* [Qemu-devel] [PATCH 1/8] target-mips: define constants for magic numbers
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
@ 2010-06-08 20:29 ` Nathan Froyd
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 2/8] target-mips: refactor c{, abs}.cond.fmt insns Nathan Froyd
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien

Add FMT_* constants for the floating-point format field in opcodes and
tweak a few places to use them.  Add enums for various invocations of
FOP and tweak gen_farith and its lone caller accordingly.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 target-mips/translate.c |  437 ++++++++++++++++++++++++++++++++---------------
 1 files changed, 295 insertions(+), 142 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 2075d09..4e54940 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -354,6 +354,19 @@ enum {
 /* Coprocessor 1 (rs field) */
 #define MASK_CP1(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
 
+/* Values for the fmt field in FP instructions */
+enum {
+    /* 0 - 15 are reserved */
+    FMT_S = 16,
+    FMT_D = 17,
+    FMT_E = 18,
+    FMT_Q = 19,
+    FMT_W = 20,
+    FMT_L = 21,
+    FMT_PS = 22,
+    /* 23 - 31 are reserved */
+};
+
 enum {
     OPC_MFC1     = (0x00 << 21) | OPC_CP1,
     OPC_DMFC1    = (0x01 << 21) | OPC_CP1,
@@ -366,13 +379,13 @@ enum {
     OPC_BC1      = (0x08 << 21) | OPC_CP1, /* bc */
     OPC_BC1ANY2  = (0x09 << 21) | OPC_CP1,
     OPC_BC1ANY4  = (0x0A << 21) | OPC_CP1,
-    OPC_S_FMT    = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */
-    OPC_D_FMT    = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */
-    OPC_E_FMT    = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */
-    OPC_Q_FMT    = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */
-    OPC_W_FMT    = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */
-    OPC_L_FMT    = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */
-    OPC_PS_FMT   = (0x16 << 21) | OPC_CP1, /* 22: fmt=paired single fp */
+    OPC_S_FMT    = (FMT_S << 21) | OPC_CP1,  /* 16: fmt=single fp */
+    OPC_D_FMT    = (FMT_D << 21) | OPC_CP1,  /* 17: fmt=double fp */
+    OPC_E_FMT    = (FMT_E << 21) | OPC_CP1,  /* 18: fmt=extended fp */
+    OPC_Q_FMT    = (FMT_Q << 21) | OPC_CP1,  /* 19: fmt=quad fp */
+    OPC_W_FMT    = (FMT_W << 21) | OPC_CP1,  /* 20: fmt=32bit fixed */
+    OPC_L_FMT    = (FMT_L << 21) | OPC_CP1,  /* 21: fmt=64bit fixed */
+    OPC_PS_FMT   = (FMT_PS << 21) | OPC_CP1, /* 22: fmt=paired single fp */
 };
 
 #define MASK_CP1_FUNC(op)       MASK_CP1(op) | (op & 0x3F)
@@ -5714,6 +5727,146 @@ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
 
 #define FOP(func, fmt) (((fmt) << 21) | (func))
 
+enum fopcode {
+    OPC_ADD_S = FOP(0, FMT_S),
+    OPC_SUB_S = FOP(1, FMT_S),
+    OPC_MUL_S = FOP(2, FMT_S),
+    OPC_DIV_S = FOP(3, FMT_S),
+    OPC_SQRT_S = FOP(4, FMT_S),
+    OPC_ABS_S = FOP(5, FMT_S),
+    OPC_MOV_S = FOP(6, FMT_S),
+    OPC_NEG_S = FOP(7, FMT_S),
+    OPC_ROUND_L_S = FOP(8, FMT_S),
+    OPC_TRUNC_L_S = FOP(9, FMT_S),
+    OPC_CEIL_L_S = FOP(10, FMT_S),
+    OPC_FLOOR_L_S = FOP(11, FMT_S),
+    OPC_ROUND_W_S = FOP(12, FMT_S),
+    OPC_TRUNC_W_S = FOP(13, FMT_S),
+    OPC_CEIL_W_S = FOP(14, FMT_S),
+    OPC_FLOOR_W_S = FOP(15, FMT_S),
+    OPC_MOVCF_S = FOP(17, FMT_S),
+    OPC_MOVZ_S = FOP(18, FMT_S),
+    OPC_MOVN_S = FOP(19, FMT_S),
+    OPC_RECIP_S = FOP(21, FMT_S),
+    OPC_RSQRT_S = FOP(22, FMT_S),
+    OPC_RECIP2_S = FOP(28, FMT_S),
+    OPC_RECIP1_S = FOP(29, FMT_S),
+    OPC_RSQRT1_S = FOP(30, FMT_S),
+    OPC_RSQRT2_S = FOP(31, FMT_S),
+    OPC_CVT_D_S = FOP(33, FMT_S),
+    OPC_CVT_W_S = FOP(36, FMT_S),
+    OPC_CVT_L_S = FOP(37, FMT_S),
+    OPC_CVT_PS_S = FOP(38, FMT_S),
+    OPC_CMP_F_S = FOP (48, FMT_S),
+    OPC_CMP_UN_S = FOP (49, FMT_S),
+    OPC_CMP_EQ_S = FOP (50, FMT_S),
+    OPC_CMP_UEQ_S = FOP (51, FMT_S),
+    OPC_CMP_OLT_S = FOP (52, FMT_S),
+    OPC_CMP_ULT_S = FOP (53, FMT_S),
+    OPC_CMP_OLE_S = FOP (54, FMT_S),
+    OPC_CMP_ULE_S = FOP (55, FMT_S),
+    OPC_CMP_SF_S = FOP (56, FMT_S),
+    OPC_CMP_NGLE_S = FOP (57, FMT_S),
+    OPC_CMP_SEQ_S = FOP (58, FMT_S),
+    OPC_CMP_NGL_S = FOP (59, FMT_S),
+    OPC_CMP_LT_S = FOP (60, FMT_S),
+    OPC_CMP_NGE_S = FOP (61, FMT_S),
+    OPC_CMP_LE_S = FOP (62, FMT_S),
+    OPC_CMP_NGT_S = FOP (63, FMT_S),
+
+    OPC_ADD_D = FOP(0, FMT_D),
+    OPC_SUB_D = FOP(1, FMT_D),
+    OPC_MUL_D = FOP(2, FMT_D),
+    OPC_DIV_D = FOP(3, FMT_D),
+    OPC_SQRT_D = FOP(4, FMT_D),
+    OPC_ABS_D = FOP(5, FMT_D),
+    OPC_MOV_D = FOP(6, FMT_D),
+    OPC_NEG_D = FOP(7, FMT_D),
+    OPC_ROUND_L_D = FOP(8, FMT_D),
+    OPC_TRUNC_L_D = FOP(9, FMT_D),
+    OPC_CEIL_L_D = FOP(10, FMT_D),
+    OPC_FLOOR_L_D = FOP(11, FMT_D),
+    OPC_ROUND_W_D = FOP(12, FMT_D),
+    OPC_TRUNC_W_D = FOP(13, FMT_D),
+    OPC_CEIL_W_D = FOP(14, FMT_D),
+    OPC_FLOOR_W_D = FOP(15, FMT_D),
+    OPC_MOVCF_D = FOP(17, FMT_D),
+    OPC_MOVZ_D = FOP(18, FMT_D),
+    OPC_MOVN_D = FOP(19, FMT_D),
+    OPC_RECIP_D = FOP(21, FMT_D),
+    OPC_RSQRT_D = FOP(22, FMT_D),
+    OPC_RECIP2_D = FOP(28, FMT_D),
+    OPC_RECIP1_D = FOP(29, FMT_D),
+    OPC_RSQRT1_D = FOP(30, FMT_D),
+    OPC_RSQRT2_D = FOP(31, FMT_D),
+    OPC_CVT_S_D = FOP(32, FMT_D),
+    OPC_CVT_W_D = FOP(36, FMT_D),
+    OPC_CVT_L_D = FOP(37, FMT_D),
+    OPC_CMP_F_D = FOP (48, FMT_D),
+    OPC_CMP_UN_D = FOP (49, FMT_D),
+    OPC_CMP_EQ_D = FOP (50, FMT_D),
+    OPC_CMP_UEQ_D = FOP (51, FMT_D),
+    OPC_CMP_OLT_D = FOP (52, FMT_D),
+    OPC_CMP_ULT_D = FOP (53, FMT_D),
+    OPC_CMP_OLE_D = FOP (54, FMT_D),
+    OPC_CMP_ULE_D = FOP (55, FMT_D),
+    OPC_CMP_SF_D = FOP (56, FMT_D),
+    OPC_CMP_NGLE_D = FOP (57, FMT_D),
+    OPC_CMP_SEQ_D = FOP (58, FMT_D),
+    OPC_CMP_NGL_D = FOP (59, FMT_D),
+    OPC_CMP_LT_D = FOP (60, FMT_D),
+    OPC_CMP_NGE_D = FOP (61, FMT_D),
+    OPC_CMP_LE_D = FOP (62, FMT_D),
+    OPC_CMP_NGT_D = FOP (63, FMT_D),
+
+    OPC_CVT_S_W = FOP(32, FMT_W),
+    OPC_CVT_D_W = FOP(33, FMT_W),
+    OPC_CVT_S_L = FOP(32, FMT_L),
+    OPC_CVT_D_L = FOP(33, FMT_L),
+    OPC_CVT_PS_PW = FOP(38, FMT_W),
+
+    OPC_ADD_PS = FOP(0, FMT_PS),
+    OPC_SUB_PS = FOP(1, FMT_PS),
+    OPC_MUL_PS = FOP(2, FMT_PS),
+    OPC_DIV_PS = FOP(3, FMT_PS),
+    OPC_ABS_PS = FOP(5, FMT_PS),
+    OPC_MOV_PS = FOP(6, FMT_PS),
+    OPC_NEG_PS = FOP(7, FMT_PS),
+    OPC_MOVCF_PS = FOP(17, FMT_PS),
+    OPC_MOVZ_PS = FOP(18, FMT_PS),
+    OPC_MOVN_PS = FOP(19, FMT_PS),
+    OPC_ADDR_PS = FOP(24, FMT_PS),
+    OPC_MULR_PS = FOP(26, FMT_PS),
+    OPC_RECIP2_PS = FOP(28, FMT_PS),
+    OPC_RECIP1_PS = FOP(29, FMT_PS),
+    OPC_RSQRT1_PS = FOP(30, FMT_PS),
+    OPC_RSQRT2_PS = FOP(31, FMT_PS),
+
+    OPC_CVT_S_PU = FOP(32, FMT_PS),
+    OPC_CVT_PW_PS = FOP(36, FMT_PS),
+    OPC_CVT_S_PL = FOP(40, FMT_PS),
+    OPC_PLL_PS = FOP(44, FMT_PS),
+    OPC_PLU_PS = FOP(45, FMT_PS),
+    OPC_PUL_PS = FOP(46, FMT_PS),
+    OPC_PUU_PS = FOP(47, FMT_PS),
+    OPC_CMP_F_PS = FOP (48, FMT_PS),
+    OPC_CMP_UN_PS = FOP (49, FMT_PS),
+    OPC_CMP_EQ_PS = FOP (50, FMT_PS),
+    OPC_CMP_UEQ_PS = FOP (51, FMT_PS),
+    OPC_CMP_OLT_PS = FOP (52, FMT_PS),
+    OPC_CMP_ULT_PS = FOP (53, FMT_PS),
+    OPC_CMP_OLE_PS = FOP (54, FMT_PS),
+    OPC_CMP_ULE_PS = FOP (55, FMT_PS),
+    OPC_CMP_SF_PS = FOP (56, FMT_PS),
+    OPC_CMP_NGLE_PS = FOP (57, FMT_PS),
+    OPC_CMP_SEQ_PS = FOP (58, FMT_PS),
+    OPC_CMP_NGL_PS = FOP (59, FMT_PS),
+    OPC_CMP_LT_PS = FOP (60, FMT_PS),
+    OPC_CMP_NGE_PS = FOP (61, FMT_PS),
+    OPC_CMP_LE_PS = FOP (62, FMT_PS),
+    OPC_CMP_NGT_PS = FOP (63, FMT_PS),
+};
+
 static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
 {
     const char *opn = "cp1 move";
@@ -5894,7 +6047,7 @@ static inline void gen_movcf_ps (int fs, int fd, int cc, int tf)
 }
 
 
-static void gen_farith (DisasContext *ctx, uint32_t op1,
+static void gen_farith (DisasContext *ctx, enum fopcode op1,
                         int ft, int fs, int fd, int cc)
 {
     const char *opn = "farith";
@@ -5937,8 +6090,8 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
     enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
     uint32_t func = ctx->opcode & 0x3f;
 
-    switch (ctx->opcode & FOP(0x3f, 0x1f)) {
-    case FOP(0, 16):
+    switch (op1) {
+    case OPC_ADD_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -5953,7 +6106,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         opn = "add.s";
         optype = BINOP;
         break;
-    case FOP(1, 16):
+    case OPC_SUB_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -5968,7 +6121,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         opn = "sub.s";
         optype = BINOP;
         break;
-    case FOP(2, 16):
+    case OPC_MUL_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -5983,7 +6136,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         opn = "mul.s";
         optype = BINOP;
         break;
-    case FOP(3, 16):
+    case OPC_DIV_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -5998,7 +6151,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         opn = "div.s";
         optype = BINOP;
         break;
-    case FOP(4, 16):
+    case OPC_SQRT_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6009,7 +6162,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "sqrt.s";
         break;
-    case FOP(5, 16):
+    case OPC_ABS_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6020,7 +6173,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "abs.s";
         break;
-    case FOP(6, 16):
+    case OPC_MOV_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6030,7 +6183,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "mov.s";
         break;
-    case FOP(7, 16):
+    case OPC_NEG_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6041,7 +6194,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "neg.s";
         break;
-    case FOP(8, 16):
+    case OPC_ROUND_L_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6055,7 +6208,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "round.l.s";
         break;
-    case FOP(9, 16):
+    case OPC_TRUNC_L_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6069,7 +6222,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "trunc.l.s";
         break;
-    case FOP(10, 16):
+    case OPC_CEIL_L_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6083,7 +6236,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "ceil.l.s";
         break;
-    case FOP(11, 16):
+    case OPC_FLOOR_L_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6097,7 +6250,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "floor.l.s";
         break;
-    case FOP(12, 16):
+    case OPC_ROUND_W_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6108,7 +6261,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "round.w.s";
         break;
-    case FOP(13, 16):
+    case OPC_TRUNC_W_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6119,7 +6272,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "trunc.w.s";
         break;
-    case FOP(14, 16):
+    case OPC_CEIL_W_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6130,7 +6283,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "ceil.w.s";
         break;
-    case FOP(15, 16):
+    case OPC_FLOOR_W_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6141,11 +6294,11 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "floor.w.s";
         break;
-    case FOP(17, 16):
+    case OPC_MOVCF_S:
         gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
         opn = "movcf.s";
         break;
-    case FOP(18, 16):
+    case OPC_MOVZ_S:
         {
             int l1 = gen_new_label();
             TCGv_i32 fp0;
@@ -6161,7 +6314,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "movz.s";
         break;
-    case FOP(19, 16):
+    case OPC_MOVN_S:
         {
             int l1 = gen_new_label();
             TCGv_i32 fp0;
@@ -6177,7 +6330,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "movn.s";
         break;
-    case FOP(21, 16):
+    case OPC_RECIP_S:
         check_cop1x(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6189,7 +6342,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "recip.s";
         break;
-    case FOP(22, 16):
+    case OPC_RSQRT_S:
         check_cop1x(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6201,7 +6354,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "rsqrt.s";
         break;
-    case FOP(28, 16):
+    case OPC_RECIP2_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6216,7 +6369,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "recip2.s";
         break;
-    case FOP(29, 16):
+    case OPC_RECIP1_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6228,7 +6381,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "recip1.s";
         break;
-    case FOP(30, 16):
+    case OPC_RSQRT1_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6240,7 +6393,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "rsqrt1.s";
         break;
-    case FOP(31, 16):
+    case OPC_RSQRT2_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6255,7 +6408,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "rsqrt2.s";
         break;
-    case FOP(33, 16):
+    case OPC_CVT_D_S:
         check_cp1_registers(ctx, fd);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6269,7 +6422,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.d.s";
         break;
-    case FOP(36, 16):
+    case OPC_CVT_W_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6280,7 +6433,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.w.s";
         break;
-    case FOP(37, 16):
+    case OPC_CVT_L_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6294,7 +6447,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.l.s";
         break;
-    case FOP(38, 16):
+    case OPC_CVT_PS_S:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp64 = tcg_temp_new_i64();
@@ -6311,22 +6464,22 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.ps.s";
         break;
-    case FOP(48, 16):
-    case FOP(49, 16):
-    case FOP(50, 16):
-    case FOP(51, 16):
-    case FOP(52, 16):
-    case FOP(53, 16):
-    case FOP(54, 16):
-    case FOP(55, 16):
-    case FOP(56, 16):
-    case FOP(57, 16):
-    case FOP(58, 16):
-    case FOP(59, 16):
-    case FOP(60, 16):
-    case FOP(61, 16):
-    case FOP(62, 16):
-    case FOP(63, 16):
+    case OPC_CMP_F_S:
+    case OPC_CMP_UN_S:
+    case OPC_CMP_EQ_S:
+    case OPC_CMP_UEQ_S:
+    case OPC_CMP_OLT_S:
+    case OPC_CMP_ULT_S:
+    case OPC_CMP_OLE_S:
+    case OPC_CMP_ULE_S:
+    case OPC_CMP_SF_S:
+    case OPC_CMP_NGLE_S:
+    case OPC_CMP_SEQ_S:
+    case OPC_CMP_NGL_S:
+    case OPC_CMP_LT_S:
+    case OPC_CMP_NGE_S:
+    case OPC_CMP_LE_S:
+    case OPC_CMP_NGT_S:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -6345,7 +6498,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
             tcg_temp_free_i32(fp1);
         }
         break;
-    case FOP(0, 17):
+    case OPC_ADD_D:
         check_cp1_registers(ctx, fs | ft | fd);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6361,7 +6514,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         opn = "add.d";
         optype = BINOP;
         break;
-    case FOP(1, 17):
+    case OPC_SUB_D:
         check_cp1_registers(ctx, fs | ft | fd);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6377,7 +6530,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         opn = "sub.d";
         optype = BINOP;
         break;
-    case FOP(2, 17):
+    case OPC_MUL_D:
         check_cp1_registers(ctx, fs | ft | fd);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6393,7 +6546,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         opn = "mul.d";
         optype = BINOP;
         break;
-    case FOP(3, 17):
+    case OPC_DIV_D:
         check_cp1_registers(ctx, fs | ft | fd);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6409,7 +6562,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         opn = "div.d";
         optype = BINOP;
         break;
-    case FOP(4, 17):
+    case OPC_SQRT_D:
         check_cp1_registers(ctx, fs | fd);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6421,7 +6574,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "sqrt.d";
         break;
-    case FOP(5, 17):
+    case OPC_ABS_D:
         check_cp1_registers(ctx, fs | fd);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6433,7 +6586,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "abs.d";
         break;
-    case FOP(6, 17):
+    case OPC_MOV_D:
         check_cp1_registers(ctx, fs | fd);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6444,7 +6597,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "mov.d";
         break;
-    case FOP(7, 17):
+    case OPC_NEG_D:
         check_cp1_registers(ctx, fs | fd);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6456,7 +6609,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "neg.d";
         break;
-    case FOP(8, 17):
+    case OPC_ROUND_L_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6468,7 +6621,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "round.l.d";
         break;
-    case FOP(9, 17):
+    case OPC_TRUNC_L_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6480,7 +6633,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "trunc.l.d";
         break;
-    case FOP(10, 17):
+    case OPC_CEIL_L_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6492,7 +6645,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "ceil.l.d";
         break;
-    case FOP(11, 17):
+    case OPC_FLOOR_L_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6504,7 +6657,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "floor.l.d";
         break;
-    case FOP(12, 17):
+    case OPC_ROUND_W_D:
         check_cp1_registers(ctx, fs);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6518,7 +6671,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "round.w.d";
         break;
-    case FOP(13, 17):
+    case OPC_TRUNC_W_D:
         check_cp1_registers(ctx, fs);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6532,7 +6685,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "trunc.w.d";
         break;
-    case FOP(14, 17):
+    case OPC_CEIL_W_D:
         check_cp1_registers(ctx, fs);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6546,7 +6699,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "ceil.w.d";
         break;
-    case FOP(15, 17):
+    case OPC_FLOOR_W_D:
         check_cp1_registers(ctx, fs);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6560,11 +6713,11 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "floor.w.d";
         break;
-    case FOP(17, 17):
+    case OPC_MOVCF_D:
         gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
         opn = "movcf.d";
         break;
-    case FOP(18, 17):
+    case OPC_MOVZ_D:
         {
             int l1 = gen_new_label();
             TCGv_i64 fp0;
@@ -6580,7 +6733,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "movz.d";
         break;
-    case FOP(19, 17):
+    case OPC_MOVN_D:
         {
             int l1 = gen_new_label();
             TCGv_i64 fp0;
@@ -6596,7 +6749,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "movn.d";
         break;
-    case FOP(21, 17):
+    case OPC_RECIP_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6608,7 +6761,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "recip.d";
         break;
-    case FOP(22, 17):
+    case OPC_RSQRT_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6620,7 +6773,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "rsqrt.d";
         break;
-    case FOP(28, 17):
+    case OPC_RECIP2_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6635,7 +6788,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "recip2.d";
         break;
-    case FOP(29, 17):
+    case OPC_RECIP1_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6647,7 +6800,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "recip1.d";
         break;
-    case FOP(30, 17):
+    case OPC_RSQRT1_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6659,7 +6812,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "rsqrt1.d";
         break;
-    case FOP(31, 17):
+    case OPC_RSQRT2_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6674,22 +6827,22 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "rsqrt2.d";
         break;
-    case FOP(48, 17):
-    case FOP(49, 17):
-    case FOP(50, 17):
-    case FOP(51, 17):
-    case FOP(52, 17):
-    case FOP(53, 17):
-    case FOP(54, 17):
-    case FOP(55, 17):
-    case FOP(56, 17):
-    case FOP(57, 17):
-    case FOP(58, 17):
-    case FOP(59, 17):
-    case FOP(60, 17):
-    case FOP(61, 17):
-    case FOP(62, 17):
-    case FOP(63, 17):
+    case OPC_CMP_F_D:
+    case OPC_CMP_UN_D:
+    case OPC_CMP_EQ_D:
+    case OPC_CMP_UEQ_D:
+    case OPC_CMP_OLT_D:
+    case OPC_CMP_ULT_D:
+    case OPC_CMP_OLE_D:
+    case OPC_CMP_ULE_D:
+    case OPC_CMP_SF_D:
+    case OPC_CMP_NGLE_D:
+    case OPC_CMP_SEQ_D:
+    case OPC_CMP_NGL_D:
+    case OPC_CMP_LT_D:
+    case OPC_CMP_NGE_D:
+    case OPC_CMP_LE_D:
+    case OPC_CMP_NGT_D:
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -6710,7 +6863,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
             tcg_temp_free_i64(fp1);
         }
         break;
-    case FOP(32, 17):
+    case OPC_CVT_S_D:
         check_cp1_registers(ctx, fs);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6724,7 +6877,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.s.d";
         break;
-    case FOP(36, 17):
+    case OPC_CVT_W_D:
         check_cp1_registers(ctx, fs);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6738,7 +6891,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.w.d";
         break;
-    case FOP(37, 17):
+    case OPC_CVT_L_D:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6750,7 +6903,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.l.d";
         break;
-    case FOP(32, 20):
+    case OPC_CVT_S_W:
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
@@ -6761,7 +6914,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.s.w";
         break;
-    case FOP(33, 20):
+    case OPC_CVT_D_W:
         check_cp1_registers(ctx, fd);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6775,7 +6928,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.d.w";
         break;
-    case FOP(32, 21):
+    case OPC_CVT_S_L:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6789,7 +6942,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.s.l";
         break;
-    case FOP(33, 21):
+    case OPC_CVT_D_L:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6801,7 +6954,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.d.l";
         break;
-    case FOP(38, 20):
+    case OPC_CVT_PS_PW:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6813,7 +6966,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.ps.pw";
         break;
-    case FOP(0, 22):
+    case OPC_ADD_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6828,7 +6981,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "add.ps";
         break;
-    case FOP(1, 22):
+    case OPC_SUB_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6843,7 +6996,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "sub.ps";
         break;
-    case FOP(2, 22):
+    case OPC_MUL_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6858,7 +7011,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "mul.ps";
         break;
-    case FOP(5, 22):
+    case OPC_ABS_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6870,7 +7023,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "abs.ps";
         break;
-    case FOP(6, 22):
+    case OPC_MOV_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6881,7 +7034,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "mov.ps";
         break;
-    case FOP(7, 22):
+    case OPC_NEG_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6893,12 +7046,12 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "neg.ps";
         break;
-    case FOP(17, 22):
+    case OPC_MOVCF_PS:
         check_cp1_64bitmode(ctx);
         gen_movcf_ps(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
         opn = "movcf.ps";
         break;
-    case FOP(18, 22):
+    case OPC_MOVZ_PS:
         check_cp1_64bitmode(ctx);
         {
             int l1 = gen_new_label();
@@ -6914,7 +7067,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "movz.ps";
         break;
-    case FOP(19, 22):
+    case OPC_MOVN_PS:
         check_cp1_64bitmode(ctx);
         {
             int l1 = gen_new_label();
@@ -6931,7 +7084,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "movn.ps";
         break;
-    case FOP(24, 22):
+    case OPC_ADDR_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6946,7 +7099,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "addr.ps";
         break;
-    case FOP(26, 22):
+    case OPC_MULR_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6961,7 +7114,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "mulr.ps";
         break;
-    case FOP(28, 22):
+    case OPC_RECIP2_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6976,7 +7129,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "recip2.ps";
         break;
-    case FOP(29, 22):
+    case OPC_RECIP1_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6988,7 +7141,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "recip1.ps";
         break;
-    case FOP(30, 22):
+    case OPC_RSQRT1_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -7000,7 +7153,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "rsqrt1.ps";
         break;
-    case FOP(31, 22):
+    case OPC_RSQRT2_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -7015,7 +7168,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "rsqrt2.ps";
         break;
-    case FOP(32, 22):
+    case OPC_CVT_S_PU:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7027,7 +7180,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.s.pu";
         break;
-    case FOP(36, 22):
+    case OPC_CVT_PW_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -7039,7 +7192,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.pw.ps";
         break;
-    case FOP(40, 22):
+    case OPC_CVT_S_PL:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7051,7 +7204,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "cvt.s.pl";
         break;
-    case FOP(44, 22):
+    case OPC_PLL_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7066,7 +7219,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "pll.ps";
         break;
-    case FOP(45, 22):
+    case OPC_PLU_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7081,7 +7234,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "plu.ps";
         break;
-    case FOP(46, 22):
+    case OPC_PUL_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7096,7 +7249,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "pul.ps";
         break;
-    case FOP(47, 22):
+    case OPC_PUU_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7111,22 +7264,22 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
         }
         opn = "puu.ps";
         break;
-    case FOP(48, 22):
-    case FOP(49, 22):
-    case FOP(50, 22):
-    case FOP(51, 22):
-    case FOP(52, 22):
-    case FOP(53, 22):
-    case FOP(54, 22):
-    case FOP(55, 22):
-    case FOP(56, 22):
-    case FOP(57, 22):
-    case FOP(58, 22):
-    case FOP(59, 22):
-    case FOP(60, 22):
-    case FOP(61, 22):
-    case FOP(62, 22):
-    case FOP(63, 22):
+    case OPC_CMP_F_PS:
+    case OPC_CMP_UN_PS:
+    case OPC_CMP_EQ_PS:
+    case OPC_CMP_UEQ_PS:
+    case OPC_CMP_OLT_PS:
+    case OPC_CMP_ULT_PS:
+    case OPC_CMP_OLE_PS:
+    case OPC_CMP_ULE_PS:
+    case OPC_CMP_SF_PS:
+    case OPC_CMP_NGLE_PS:
+    case OPC_CMP_SEQ_PS:
+    case OPC_CMP_NGL_PS:
+    case OPC_CMP_LT_PS:
+    case OPC_CMP_NGE_PS:
+    case OPC_CMP_LE_PS:
+    case OPC_CMP_NGT_PS:
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -9298,7 +9451,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
             case OPC_W_FMT:
             case OPC_L_FMT:
             case OPC_PS_FMT:
-                gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa,
+                gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
                            (imm >> 8) & 0x7);
                 break;
             default:
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 2/8] target-mips: refactor c{, abs}.cond.fmt insns
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 1/8] target-mips: define constants for magic numbers Nathan Froyd
@ 2010-06-08 20:29 ` Nathan Froyd
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 3/8] target-mips: mips16 cleanups Nathan Froyd
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien

Move all knowledge about coprocessor-checking and register numbering
into the gen_cmp* helper functions.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 target-mips/translate.c |  164 +++++++++++++++++++++++------------------------
 1 files changed, 81 insertions(+), 83 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 4e54940..8d532d5 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -676,39 +676,6 @@ static inline int get_fp_bit (int cc)
         return 23;
 }
 
-#define FOP_CONDS(type, fmt, bits)                                            \
-static inline void gen_cmp ## type ## _ ## fmt(int n, TCGv_i##bits a,         \
-                                               TCGv_i##bits b, int cc)        \
-{                                                                             \
-    switch (n) {                                                              \
-    case  0: gen_helper_2i(cmp ## type ## _ ## fmt ## _f, a, b, cc);    break;\
-    case  1: gen_helper_2i(cmp ## type ## _ ## fmt ## _un, a, b, cc);   break;\
-    case  2: gen_helper_2i(cmp ## type ## _ ## fmt ## _eq, a, b, cc);   break;\
-    case  3: gen_helper_2i(cmp ## type ## _ ## fmt ## _ueq, a, b, cc);  break;\
-    case  4: gen_helper_2i(cmp ## type ## _ ## fmt ## _olt, a, b, cc);  break;\
-    case  5: gen_helper_2i(cmp ## type ## _ ## fmt ## _ult, a, b, cc);  break;\
-    case  6: gen_helper_2i(cmp ## type ## _ ## fmt ## _ole, a, b, cc);  break;\
-    case  7: gen_helper_2i(cmp ## type ## _ ## fmt ## _ule, a, b, cc);  break;\
-    case  8: gen_helper_2i(cmp ## type ## _ ## fmt ## _sf, a, b, cc);   break;\
-    case  9: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngle, a, b, cc); break;\
-    case 10: gen_helper_2i(cmp ## type ## _ ## fmt ## _seq, a, b, cc);  break;\
-    case 11: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngl, a, b, cc);  break;\
-    case 12: gen_helper_2i(cmp ## type ## _ ## fmt ## _lt, a, b, cc);   break;\
-    case 13: gen_helper_2i(cmp ## type ## _ ## fmt ## _nge, a, b, cc);  break;\
-    case 14: gen_helper_2i(cmp ## type ## _ ## fmt ## _le, a, b, cc);   break;\
-    case 15: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngt, a, b, cc);  break;\
-    default: abort();                                                         \
-    }                                                                         \
-}
-
-FOP_CONDS(, d, 64)
-FOP_CONDS(abs, d, 64)
-FOP_CONDS(, s, 32)
-FOP_CONDS(abs, s, 32)
-FOP_CONDS(, ps, 64)
-FOP_CONDS(abs, ps, 64)
-#undef FOP_CONDS
-
 /* Tests */
 static inline void gen_save_pc(target_ulong pc)
 {
@@ -849,6 +816,69 @@ static inline void check_mips_64(DisasContext *ctx)
         generate_exception(ctx, EXCP_RI);
 }
 
+/* Define small wrappers for gen_load_fpr* so that we have a uniform
+   calling interface for 32 and 64-bit FPRs.  No sense in changing
+   all callers for gen_load_fpr32 when we need the CTX parameter for
+   this one use.  */
+#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(x, y)
+#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y)
+#define FOP_CONDS(type, abs, fmt, ifmt, bits)                                 \
+static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n,      \
+                                               int ft, int fs, int cc)        \
+{                                                                             \
+    TCGv_i##bits fp0 = tcg_temp_new_i##bits ();                               \
+    TCGv_i##bits fp1 = tcg_temp_new_i##bits ();                               \
+    switch (ifmt) {                                                           \
+    case FMT_PS:                                                              \
+        check_cp1_64bitmode(ctx);                                             \
+        break;                                                                \
+    case FMT_D:                                                               \
+        if (abs) {                                                            \
+            check_cop1x(ctx);                                                 \
+        }                                                                     \
+        check_cp1_registers(ctx, fs | ft);                                    \
+        break;                                                                \
+    case FMT_S:                                                               \
+        if (abs) {                                                            \
+            check_cop1x(ctx);                                                 \
+        }                                                                     \
+        break;                                                                \
+    }                                                                         \
+    gen_ldcmp_fpr##bits (ctx, fp0, fs);                                       \
+    gen_ldcmp_fpr##bits (ctx, fp1, ft);                                       \
+    switch (n) {                                                              \
+    case  0: gen_helper_2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc);    break;\
+    case  1: gen_helper_2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc);   break;\
+    case  2: gen_helper_2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc);   break;\
+    case  3: gen_helper_2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc);  break;\
+    case  4: gen_helper_2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc);  break;\
+    case  5: gen_helper_2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc);  break;\
+    case  6: gen_helper_2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc);  break;\
+    case  7: gen_helper_2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc);  break;\
+    case  8: gen_helper_2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc);   break;\
+    case  9: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\
+    case 10: gen_helper_2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc);  break;\
+    case 11: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc);  break;\
+    case 12: gen_helper_2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc);   break;\
+    case 13: gen_helper_2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc);  break;\
+    case 14: gen_helper_2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc);   break;\
+    case 15: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc);  break;\
+    default: abort();                                                         \
+    }                                                                         \
+    tcg_temp_free_i##bits (fp0);                                              \
+    tcg_temp_free_i##bits (fp1);                                              \
+}
+
+FOP_CONDS(, 0, d, FMT_D, 64)
+FOP_CONDS(abs, 1, d, FMT_D, 64)
+FOP_CONDS(, 0, s, FMT_S, 32)
+FOP_CONDS(abs, 1, s, FMT_S, 32)
+FOP_CONDS(, 0, ps, FMT_PS, 64)
+FOP_CONDS(abs, 1, ps, FMT_PS, 64)
+#undef FOP_CONDS
+#undef gen_ldcmp_fpr32
+#undef gen_ldcmp_fpr64
+
 /* load/store instructions. */
 #define OP_LD(insn,fname)                                                 \
 static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \
@@ -6480,22 +6510,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
     case OPC_CMP_NGE_S:
     case OPC_CMP_LE_S:
     case OPC_CMP_NGT_S:
-        {
-            TCGv_i32 fp0 = tcg_temp_new_i32();
-            TCGv_i32 fp1 = tcg_temp_new_i32();
-
-            gen_load_fpr32(fp0, fs);
-            gen_load_fpr32(fp1, ft);
-            if (ctx->opcode & (1 << 6)) {
-                check_cop1x(ctx);
-                gen_cmpabs_s(func-48, fp0, fp1, cc);
-                opn = condnames_abs[func-48];
-            } else {
-                gen_cmp_s(func-48, fp0, fp1, cc);
-                opn = condnames[func-48];
-            }
-            tcg_temp_free_i32(fp0);
-            tcg_temp_free_i32(fp1);
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_s(ctx, func-48, ft, fs, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_s(ctx, func-48, ft, fs, cc);
+            opn = condnames[func-48];
         }
         break;
     case OPC_ADD_D:
@@ -6843,24 +6863,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
     case OPC_CMP_NGE_D:
     case OPC_CMP_LE_D:
     case OPC_CMP_NGT_D:
-        {
-            TCGv_i64 fp0 = tcg_temp_new_i64();
-            TCGv_i64 fp1 = tcg_temp_new_i64();
-
-            gen_load_fpr64(ctx, fp0, fs);
-            gen_load_fpr64(ctx, fp1, ft);
-            if (ctx->opcode & (1 << 6)) {
-                check_cop1x(ctx);
-                check_cp1_registers(ctx, fs | ft);
-                gen_cmpabs_d(func-48, fp0, fp1, cc);
-                opn = condnames_abs[func-48];
-            } else {
-                check_cp1_registers(ctx, fs | ft);
-                gen_cmp_d(func-48, fp0, fp1, cc);
-                opn = condnames[func-48];
-            }
-            tcg_temp_free_i64(fp0);
-            tcg_temp_free_i64(fp1);
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_d(ctx, func-48, ft, fs, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_d(ctx, func-48, ft, fs, cc);
+            opn = condnames[func-48];
         }
         break;
     case OPC_CVT_S_D:
@@ -7280,22 +7288,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
     case OPC_CMP_NGE_PS:
     case OPC_CMP_LE_PS:
     case OPC_CMP_NGT_PS:
-        check_cp1_64bitmode(ctx);
-        {
-            TCGv_i64 fp0 = tcg_temp_new_i64();
-            TCGv_i64 fp1 = tcg_temp_new_i64();
-
-            gen_load_fpr64(ctx, fp0, fs);
-            gen_load_fpr64(ctx, fp1, ft);
-            if (ctx->opcode & (1 << 6)) {
-                gen_cmpabs_ps(func-48, fp0, fp1, cc);
-                opn = condnames_abs[func-48];
-            } else {
-                gen_cmp_ps(func-48, fp0, fp1, cc);
-                opn = condnames[func-48];
-            }
-            tcg_temp_free_i64(fp0);
-            tcg_temp_free_i64(fp1);
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_ps(ctx, func-48, ft, fs, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_ps(ctx, func-48, ft, fs, cc);
+            opn = condnames[func-48];
         }
         break;
     default:
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 3/8] target-mips: mips16 cleanups
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 1/8] target-mips: define constants for magic numbers Nathan Froyd
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 2/8] target-mips: refactor c{, abs}.cond.fmt insns Nathan Froyd
@ 2010-06-08 20:29 ` Nathan Froyd
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 4/8] target-mips: microMIPS ASE support Nathan Froyd
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien

Change code handling mips16-specific branches to use ISA-neutral special
opcodes.  Since there are several places where the delay slot
requirements for microMIPS branches differ from mips16 branches, using
opcodes is easier than checking hflags, then checking mips16
vs. microMIPS.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 target-mips/translate.c |   24 +++++++++++++++++-------
 1 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 8d532d5..2754b2e 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -68,6 +68,7 @@ enum {
     /* Jump and branches */
     OPC_J        = (0x02 << 26),
     OPC_JAL      = (0x03 << 26),
+    OPC_JALS     = OPC_JAL | 0x5,
     OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
     OPC_BEQL     = (0x14 << 26),
     OPC_BNE      = (0x05 << 26),
@@ -77,6 +78,7 @@ enum {
     OPC_BGTZ     = (0x07 << 26),
     OPC_BGTZL    = (0x17 << 26),
     OPC_JALX     = (0x1D << 26),  /* MIPS 16 only */
+    OPC_JALXS    = OPC_JALX | 0x5,
     /* Load and stores */
     OPC_LDL      = (0x1A << 26),
     OPC_LDR      = (0x1B << 26),
@@ -177,6 +179,7 @@ enum {
     OPC_JR       = 0x08 | OPC_SPECIAL, /* Also JR.HB */
     OPC_JALR     = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
     OPC_JALRC    = OPC_JALR | (0x5 << 6),
+    OPC_JALRS    = 0x10 | OPC_SPECIAL | (0x5 << 6),
     /* Traps */
     OPC_TGE      = 0x30 | OPC_SPECIAL,
     OPC_TGEU     = 0x31 | OPC_SPECIAL,
@@ -2466,12 +2469,15 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
     case OPC_J:
     case OPC_JAL:
     case OPC_JALX:
+    case OPC_JALS:
+    case OPC_JALXS:
         /* Jump to immediate */
         btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
         break;
     case OPC_JR:
     case OPC_JALR:
     case OPC_JALRC:
+    case OPC_JALRS:
         /* Jump to register */
         if (offset != 0 && offset != 16) {
             /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
@@ -2534,29 +2540,33 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
             break;
+        case OPC_JALXS:           
         case OPC_JALX:
             ctx->hflags |= MIPS_HFLAG_BX;
             /* Fallthrough */
+        case OPC_JALS:
         case OPC_JAL:
             blink = 31;
             ctx->hflags |= MIPS_HFLAG_B;
-            ctx->hflags |= (ctx->hflags & MIPS_HFLAG_M16
+            ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS)
                             ? MIPS_HFLAG_BDS16
                             : MIPS_HFLAG_BDS32);
             MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
             break;
         case OPC_JR:
             ctx->hflags |= MIPS_HFLAG_BR;
-            if (ctx->hflags & MIPS_HFLAG_M16)
-                ctx->hflags |= MIPS_HFLAG_BDS16;
+            if (insn_bytes == 4)
+                ctx->hflags |= MIPS_HFLAG_BDS32;
             MIPS_DEBUG("jr %s", regnames[rs]);
             break;
+        case OPC_JALRS:
         case OPC_JALR:
         case OPC_JALRC:
             blink = rt;
             ctx->hflags |= MIPS_HFLAG_BR;
-            if (ctx->hflags & MIPS_HFLAG_M16)
-                ctx->hflags |= MIPS_HFLAG_BDS16;
+            ctx->hflags |= (opc == OPC_JALRS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
             MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
             break;
         default:
@@ -8487,7 +8497,7 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
         offset = (((ctx->opcode & 0x1f) << 21)
                   | ((ctx->opcode >> 5) & 0x1f) << 16
                   | offset) << 2;
-        op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL;
+        op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS;
         gen_compute_branch(ctx, op, 4, rx, ry, offset);
         n_bytes = 4;
         *is_branch = 1;
@@ -8726,7 +8736,7 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
                 int ra = (ctx->opcode >> 5) & 0x1;
 
                 if (link) {
-                    op = nd ? OPC_JALRC : OPC_JALR;
+                    op = nd ? OPC_JALRC : OPC_JALRS;
                 } else {
                     op = OPC_JR;
                 }
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 4/8] target-mips: microMIPS ASE support
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
                   ` (2 preceding siblings ...)
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 3/8] target-mips: mips16 cleanups Nathan Froyd
@ 2010-06-08 20:29 ` Nathan Froyd
  2010-06-09 14:08   ` Aurelien Jarno
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 5/8] target-mips: add microMIPS CPUs Nathan Froyd
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien

Add instruction decoding for the microMIPS ASE.  All we do is decode and
then forward to the existing gen_* routines.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 target-mips/helper.h    |    9 +
 target-mips/mips-defs.h |    1 +
 target-mips/op_helper.c |  136 +++
 target-mips/translate.c | 2390 ++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 2531 insertions(+), 5 deletions(-)

diff --git a/target-mips/helper.h b/target-mips/helper.h
index ab47b1a..a6ba75d 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -160,6 +160,15 @@ DEF_HELPER_1(emt, tl, tl)
 DEF_HELPER_1(dvpe, tl, tl)
 DEF_HELPER_1(evpe, tl, tl)
 #endif /* !CONFIG_USER_ONLY */
+
+/* microMIPS functions */
+DEF_HELPER_3(lwm, void, tl, tl, i32);
+DEF_HELPER_3(swm, void, tl, tl, i32);
+#ifdef TARGET_MIPS64
+DEF_HELPER_3(ldm, void, tl, tl, i32);
+DEF_HELPER_3(sdm, void, tl, tl, i32);
+#endif
+
 DEF_HELPER_2(fork, void, tl, tl)
 DEF_HELPER_1(yield, tl, tl)
 
diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
index c57de02..a7f4697 100644
--- a/target-mips/mips-defs.h
+++ b/target-mips/mips-defs.h
@@ -38,6 +38,7 @@
 #define		ASE_DSPR2	0x00010000
 #define		ASE_MT		0x00020000
 #define		ASE_SMARTMIPS	0x00040000
+#define 	ASE_MICROMIPS	0x00080000
 
 /* Chip specific instructions. */
 #define		INSN_VR54XX	0x80000000
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 2bfdd50..56c5e59 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -565,6 +565,142 @@ void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
 }
 #endif /* TARGET_MIPS64 */
 
+static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
+
+void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldl_raw
+#else
+    uint32_t (*ldfun)(target_ulong);
+
+    switch (mem_idx)
+    {
+    case 0: ldfun = ldl_kernel; break;
+    case 1: ldfun = ldl_super; break;
+    default:
+    case 2: ldfun = ldl_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
+            addr += 4;
+        }
+    }
+
+    if (do_r31) {
+        env->active_tc.gpr[31] = (target_long) ldfun(addr);
+    }
+}
+
+void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun 
+#define stfun stl_raw
+#else
+    void (*stfun)(target_ulong, uint32_t);
+
+    switch (mem_idx)
+    {
+    case 0: stfun = stl_kernel; break;
+    case 1: stfun = stl_super; break;
+     default:
+    case 2: stfun = stl_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+            addr += 4;
+        }
+    }
+
+    if (do_r31) {
+        stfun(addr, env->active_tc.gpr[31]);
+    }
+}
+
+#if defined(TARGET_MIPS64)
+void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldq_raw
+#else
+    uint64_t (*ldfun)(target_ulong);
+
+    switch (mem_idx)
+    {
+    case 0: ldfun = ldq_kernel; break;
+    case 1: ldfun = ldq_super; break;
+    default:
+    case 2: ldfun = ldq_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
+            addr += 8;
+        }
+    }
+
+    if (do_r31) {
+        env->active_tc.gpr[31] = ldfun(addr);
+    }
+}
+
+void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stq_raw
+#else
+    void (*stfun)(target_ulong, uint64_t);
+
+    switch (mem_idx)
+    {
+    case 0: stfun = stq_kernel; break;
+    case 1: stfun = stq_super; break;
+     default:
+    case 2: stfun = stq_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+            addr += 8;
+        }
+    }
+
+    if (do_r31) {
+        stfun(addr, env->active_tc.gpr[31]);
+    }
+}
+#endif
+
 #ifndef CONFIG_USER_ONLY
 /* CP0 helpers */
 target_ulong helper_mfc0_mvpcontrol (void)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 2754b2e..51082b8 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -4,7 +4,7 @@
  *  Copyright (c) 2004-2005 Jocelyn Mayer
  *  Copyright (c) 2006 Marius Groeger (FPU operations)
  *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
- *  Copyright (c) 2009 CodeSourcery (MIPS16 support)
+ *  Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -243,8 +243,10 @@ enum {
     OPC_BGEZ     = (0x01 << 16) | OPC_REGIMM,
     OPC_BGEZL    = (0x03 << 16) | OPC_REGIMM,
     OPC_BLTZAL   = (0x10 << 16) | OPC_REGIMM,
+    OPC_BLTZALS  = OPC_BLTZAL | 0x5, /* microMIPS */
     OPC_BLTZALL  = (0x12 << 16) | OPC_REGIMM,
     OPC_BGEZAL   = (0x11 << 16) | OPC_REGIMM,
+    OPC_BGEZALS  = OPC_BGEZAL | 0x5, /* microMIPS */
     OPC_BGEZALL  = (0x13 << 16) | OPC_REGIMM,
     OPC_TGEI     = (0x08 << 16) | OPC_REGIMM,
     OPC_TGEIU    = (0x09 << 16) | OPC_REGIMM,
@@ -2449,6 +2451,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
         break;
     case OPC_BGEZ:
     case OPC_BGEZAL:
+    case OPC_BGEZALS:
     case OPC_BGEZALL:
     case OPC_BGEZL:
     case OPC_BGTZ:
@@ -2457,6 +2460,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
     case OPC_BLEZL:
     case OPC_BLTZ:
     case OPC_BLTZAL:
+    case OPC_BLTZALS:
     case OPC_BLTZALL:
     case OPC_BLTZL:
         /* Compare to zero */
@@ -2506,8 +2510,12 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("balways");
             break;
+        case OPC_BGEZALS:
         case OPC_BGEZAL:  /* 0 >= 0          */
         case OPC_BGEZALL: /* 0 >= 0 likely   */
+            ctx->hflags |= (opc == OPC_BGEZALS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
             /* Always take and link */
             blink = 31;
             ctx->hflags |= MIPS_HFLAG_B;
@@ -2519,10 +2527,18 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             /* Treat as NOP. */
             MIPS_DEBUG("bnever (NOP)");
             goto out;
+        case OPC_BLTZALS:
         case OPC_BLTZAL:  /* 0 < 0           */
-            tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 8);
+            ctx->hflags |= (opc == OPC_BLTZALS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
+            /* Handle as an unconditional branch to get correct delay
+               slot checking.  */
+            blink = 31;
+            btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8);
+            ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("bnever and link");
-            goto out;
+            break;
         case OPC_BLTZALL: /* 0 < 0 likely */
             tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 8);
             /* Skip the instruction in the delay slot */
@@ -2604,7 +2620,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
             MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
             goto likely;
+        case OPC_BGEZALS:
         case OPC_BGEZAL:
+            ctx->hflags |= (opc == OPC_BGEZALS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
             tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
             MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt);
             blink = 31;
@@ -2638,7 +2658,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
             MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btgt);
             goto likely;
+        case OPC_BLTZALS:
         case OPC_BLTZAL:
+            ctx->hflags |= (opc == OPC_BLTZALS
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
             tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
             blink = 31;
             MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt);
@@ -7785,7 +7809,7 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
         case MIPS_HFLAG_BR:
             /* unconditional branch to register */
             MIPS_DEBUG("branch to register");
-            if (env->insn_flags & ASE_MIPS16) {
+            if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
                 TCGv t0 = tcg_temp_new();
                 TCGv_i32 t1 = tcg_temp_new_i32();
 
@@ -8906,6 +8930,2358 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
     return n_bytes;
 }
 
+/* microMIPS extension to MIPS32 */
+
+/* microMIPS32 major opcodes */
+
+enum {
+    POOL32A = 0x00,
+    POOL16A = 0x01,
+    LBU16 = 0x02,
+    MOVE16 = 0x03,
+    ADDI32 = 0x04,
+    LBU32 = 0x05,
+    SB32 = 0x06,
+    LB32 = 0x07,
+
+    POOL32B = 0x08,
+    POOL16B = 0x09,
+    LHU16 = 0x0a,
+    ANDI16 = 0x0b,
+    ADDIU32 = 0x0c,
+    LHU32 = 0x0d,
+    SH32 = 0x0e,
+    LH32 = 0x0f,
+
+    POOL32I = 0x10,
+    POOL16C = 0x11,
+    LWSP16 = 0x12,
+    POOL16D = 0x13,
+    ORI32 = 0x14,
+    POOL32F = 0x15,
+    POOL32S = 0x16,
+    DADDIU32 = 0x17,
+
+    POOL32C = 0x18,
+    LWGP16 = 0x19,
+    LW16 = 0x1a,
+    POOL16E = 0x1b,
+    XORI32 = 0x1c,
+    JALS32 = 0x1d,
+    ADDIUPC = 0x1e,
+    POOL48A = 0x1f,
+
+    /* 0x20 is reserved */
+    RES_20 = 0x20,
+    POOL16F = 0x21,
+    SB16 = 0x22,
+    BEQZ16 = 0x23,
+    SLTI32 = 0x24,
+    BEQ32 = 0x25,
+    SWC132 = 0x26,
+    LWC132 = 0x27,
+
+    /* 0x28 and 0x29 are reserved */
+    RES_28 = 0x28,
+    RES_29 = 0x29,
+    SH16 = 0x2a,
+    BNEZ16 = 0x2b,
+    SLTIU32 = 0x2c,
+    BNE32 = 0x2d,
+    SDC132 = 0x2e,
+    LDC132 = 0x2f,
+
+    /* 0x30 and 0x31 are reserved */
+    RES_30 = 0x30,
+    RES_31 = 0x31,
+    SWSP16 = 0x32,
+    B16 = 0x33,
+    ANDI32 = 0x34,
+    J32 = 0x35,
+    SD32 = 0x36,
+    LD32 = 0x37,
+
+    /* 0x38 and 0x39 are reserved */
+    RES_38 = 0x38,
+    RES_39 = 0x39,
+    SW16 = 0x3a,
+    LI16 = 0x3b,
+    JALX32 = 0x3c,
+    JAL32 = 0x3d,
+    SW32 = 0x3e,
+    LW32 = 0x3f
+};
+
+/* POOL32A encoding of minor opcode field */
+
+enum {
+    /* These opcodes are distinguished only by bits 9..6; those bits are
+     * what are recorded below. */
+    SLL32 = 0x0,
+    SRL32 = 0x1,
+    SRA = 0x2,
+    ROTR = 0x3,
+
+    SLLV = 0x0,
+    SRLV = 0x1,
+    SRAV = 0x2,
+    ROTRV = 0x3,
+    ADD = 0x4,
+    ADDU32 = 0x5,
+    SUB = 0x6,
+    SUBU32 = 0x7,
+    MUL = 0x8,
+    AND = 0x9,
+    OR32 = 0xa,
+    NOR = 0xb,
+    XOR32 = 0xc,
+    SLT = 0xd,
+    SLTU = 0xe,
+
+    MOVN = 0x0,
+    MOVZ = 0x1,
+    LWXS = 0x4,
+
+    /* The following can be distinguished by their lower 6 bits. */
+    INS = 0x0c,
+    EXT = 0x2c,
+    POOL32AXF = 0x3c
+};
+
+/* POOL32AXF encoding of minor opcode field extension */
+
+enum {
+    /* bits 11..6 */
+    TEQ = 0x00,
+    TGE = 0x08,
+    TGEU = 0x10,
+    TLT = 0x20,
+    TLTU = 0x28,
+    TNE = 0x30,
+
+    MFC0 = 0x03,
+    MTC0 = 0x0b,
+
+    /* bits 13..12 for 0x01 */
+    MFHI_ACC = 0x0,
+    MFLO_ACC = 0x1,
+    MTHI_ACC = 0x2,
+    MTLO_ACC = 0x3,
+
+    /* bits 13..12 for 0x2a */
+    MADD_ACC = 0x0,
+    MADDU_ACC = 0x1,
+    MSUB_ACC = 0x2,
+    MSUBU_ACC = 0x3,
+
+    /* bits 13..12 for 0x32 */
+    MULT_ACC = 0x0,
+    MULTU_ACC = 0x0,
+
+    /* bits 15..12 for 0x2c */
+    SEB = 0x2,
+    SEH = 0x3,
+    CLO = 0x4,
+    CLZ = 0x5,
+    RDHWR = 0x6,
+    WSBH = 0x7,
+    MULT = 0x8,
+    MULTU = 0x9,
+    DIV = 0xa,
+    DIVU = 0xb,
+    MADD = 0xc,
+    MADDU = 0xd,
+    MSUB = 0xe,
+    MSUBU = 0xf,
+
+    /* bits 15..12 for 0x34 */
+    MFC2 = 0x4,
+    MTC2 = 0x5,
+    MFHC2 = 0x8,
+    MTHC2 = 0x9,
+    CFC2 = 0xc,
+    CTC2 = 0xd,
+
+    /* bits 15..12 for 0x3c */
+    JALR = 0x0,
+    JR = 0x0,                   /* alias */
+    JALR_HB = 0x1,
+    JALRS = 0x4,
+    JALRS_HB = 0x5,
+
+    /* bits 15..12 for 0x05 */
+    RDPGPR = 0xe,
+    WRPGPR = 0xf,
+
+    /* bits 15..12 for 0x0d */
+    TLBP = 0x0,
+    TLBR = 0x1,
+    TLBWI = 0x2,
+    TLBWR = 0x3,
+    WAIT = 0x9,
+    IRET = 0xd,
+    DERET = 0xe,
+    ERET = 0xf,
+
+    /* bits 15..12 for 0x15 */
+    DMT = 0x0,
+    DVPE = 0x1,
+    EMT = 0x2,
+    EVPE = 0x3,
+
+    /* bits 15..12 for 0x1d */
+    DI = 0x4,
+    EI = 0x5,
+
+    /* bits 15..12 for 0x2d */
+    SYNC = 0x6,
+    SYSCALL = 0x8,
+    SDBBP = 0xd,
+
+    /* bits 15..12 for 0x35 */
+    MFHI32 = 0x0,
+    MFLO32 = 0x1,
+    MTHI32 = 0x2,
+    MTLO32 = 0x3,
+};
+
+/* POOL32B encoding of minor opcode field (bits 15..12) */
+
+enum {
+    LWC2 = 0x0,
+    LWP = 0x1,
+    LDP = 0x4,
+    LWM32 = 0x5,
+    CACHE = 0x6,
+    LDM = 0x7,
+    SWC2 = 0x8,
+    SWP = 0x9,
+    SDP = 0xc,
+    SWM32 = 0xd,
+    SDM = 0xf
+};
+
+/* POOL32C encoding of minor opcode field (bits 15..12) */
+
+enum {
+    LWL = 0x0,
+    SWL = 0x8,
+    LWR = 0x1,
+    SWR = 0x9,
+    PREF = 0x2,
+    /* 0xa is reserved */
+    LL = 0x3,
+    SC = 0xb,
+    LDL = 0x4,
+    SDL = 0xc,
+    LDR = 0x5,
+    SDR = 0xd,
+    /* 0x6 is reserved */
+    LWU = 0xe,
+    LLD = 0x7,
+    SCD = 0xf
+};
+
+/* POOL32F encoding of minor opcode field (bits 5..0) */
+
+enum {
+    /* These are the bit 7..6 values */
+    ADD_FMT = 0x0,
+    MOVN_FMT = 0x0,
+
+    SUB_FMT = 0x1,
+    MOVZ_FMT = 0x1,
+
+    MUL_FMT = 0x2,
+
+    DIV_FMT = 0x3,
+
+    /* These are the bit 8..6 values */
+    RSQRT2_FMT = 0x0,
+    MOVF_FMT = 0x0,
+
+    LWXC1 = 0x1,
+    MOVT_FMT = 0x1,
+
+    PLL_PS = 0x2,
+    SWXC1 = 0x2,
+
+    PLU_PS = 0x3,
+    LDXC1 = 0x3,
+
+    PUL_PS = 0x4,
+    SDXC1 = 0x4,
+    RECIP2_FMT = 0x4,
+
+    PUU_PS = 0x5,
+    LUXC1 = 0x5,
+
+    CVT_PS_S = 0x6,
+    SUXC1 = 0x6,
+    ADDR_PS = 0x6,
+    PREFX = 0x6,
+
+    MULR_PS = 0x7,
+
+    MADD_S = 0x01,
+    MADD_D = 0x09,
+    MADD_PS = 0x11,
+    ALNV_PS = 0x19,
+    MSUB_S = 0x21,
+    MSUB_D = 0x29,
+    MSUB_PS = 0x31,
+
+    NMADD_S = 0x02,
+    NMADD_D = 0x0a,
+    NMADD_PS = 0x12,
+    NMSUB_S = 0x22,
+    NMSUB_D = 0x2a,
+    NMSUB_PS = 0x32,
+
+    POOL32FXF = 0x3b,
+
+    CABS_COND_FMT = 0x1c,              /* MIPS3D */
+    C_COND_FMT = 0x3c
+};
+
+/* POOL32Fxf encoding of minor opcode extension field */
+
+enum {
+    CVT_L = 0x04,
+    RSQRT_FMT = 0x08,
+    FLOOR_L = 0x0c,
+    CVT_PW_PS = 0x1c,
+    CVT_W = 0x24,
+    SQRT_FMT = 0x28,
+    FLOOR_W = 0x2c,
+    CVT_PS_PW = 0x3c,
+    CFC1 = 0x40,
+    RECIP_FMT = 0x48,
+    CEIL_L = 0x4c,
+    CTC1 = 0x60,
+    CEIL_W = 0x6c,
+    MFC1 = 0x80,
+    CVT_S_PL = 0x84,
+    TRUNC_L = 0x8c,
+    MTC1 = 0xa0,
+    CVT_S_PU = 0xa4,
+    TRUNC_W = 0xac,
+    MFHC1 = 0xc0,
+    ROUND_L = 0xcc,
+    MTHC1 = 0xe0,
+    ROUND_W = 0xec,
+
+    MOV_FMT = 0x01,
+    MOVF = 0x05,
+    ABS_FMT = 0x0d,
+    RSQRT1_FMT = 0x1d,
+    MOVT = 0x25,
+    NEG_FMT = 0x2d,
+    CVT_D = 0x4d,
+    RECIP1_FMT = 0x5d,
+    CVT_S = 0x6d
+};
+
+/* POOL32I encoding of minor opcode field (bits 25..21) */
+
+enum {
+    BLTZ = 0x00,
+    BLTZAL = 0x01,
+    BGEZ = 0x02,
+    BGEZAL = 0x03,
+    BLEZ = 0x04,
+    BNEZC = 0x05,
+    BGTZ = 0x06,
+    BEQZC = 0x07,
+    TLTI = 0x08,
+    TGEI = 0x09,
+    TLTIU = 0x0a,
+    TGEIU = 0x0b,
+    TNEI = 0x0c,
+    LUI = 0x0d,
+    TEQI = 0x0e,
+    SYNCI = 0x10,
+    BLTZALS = 0x11,
+    BGEZALS = 0x13,
+    BC2F = 0x14,
+    BC2T = 0x15,
+    BPOSGE64 = 0x1a,
+    BPOSGE32 = 0x1b,
+    /* These overlap and are distinguished by bit16 of the instruction */
+    BC1F = 0x1c,
+    BC1T = 0x1d,
+    BC1ANY2F = 0x1c,
+    BC1ANY2T = 0x1d,
+    BC1ANY4F = 0x1e,
+    BC1ANY4T = 0x1f
+};
+
+/* POOL16A encoding of minor opcode field */
+
+enum {
+    ADDU16 = 0x0,
+    SUBU16 = 0x1
+};
+
+/* POOL16B encoding of minor opcode field */
+
+enum {
+    SLL16 = 0x0,
+    SRL16 = 0x1
+};
+
+/* POOL16C encoding of minor opcode field */
+
+enum {
+    NOT16 = 0x00,
+    XOR16 = 0x04,
+    AND16 = 0x08,
+    OR16 = 0x0c,
+    LWM16 = 0x10,
+    SWM16 = 0x14,
+    JR16 = 0x18,
+    JRC16 = 0x1a,
+    JALR16 = 0x1c,
+    JALR16S = 0x1e,
+    MFHI16 = 0x20,
+    MFLO16 = 0x24,
+    BREAK16 = 0x28,
+    SDBBP16 = 0x2c,
+    JRADDIUSP = 0x30
+};
+
+/* POOL16D encoding of minor opcode field */
+
+enum {
+    ADDIUS5 = 0x0,
+    ADDIUSP = 0x1
+};
+
+/* POOL16E encoding of minor opcode field */
+
+enum {
+    ADDIUR2 = 0x0,
+    ADDIUR1SP = 0x1
+};
+
+static int mmreg (int r)
+{
+    static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
+
+    return map[r];
+}
+
+/* Used for 16-bit store instructions.  */
+static int mmreg2 (int r)
+{
+    static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
+
+    return map[r];
+}
+
+#define uMIPS_RD(op) ((op >> 7) & 0x7)
+#define uMIPS_RS(op) ((op >> 4) & 0x7)
+#define uMIPS_RS2(op) uMIPS_RS(op)
+#define uMIPS_RS1(op) ((op >> 1) & 0x7)
+#define uMIPS_RD5(op) ((op >> 5) & 0x1f)
+#define uMIPS_RS5(op) (op & 0x1f)
+
+/* Signed immediate */
+#define SIMM(op, start, width)                                          \
+    ((int32_t)(((op >> start) & ((~0U) >> (32-width)))                 \
+               << (32-width))                                           \
+     >> (32-width))
+/* Zero-extended immediate */
+#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32-width)))
+
+static void gen_addiur1sp (CPUState *env, DisasContext *ctx)
+{
+    int rd = mmreg(uMIPS_RD(ctx->opcode));
+
+    gen_arith_imm(env, ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2);
+}
+
+static void gen_addiur2 (CPUState *env, DisasContext *ctx)
+{
+    static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 };
+    int rd = mmreg(uMIPS_RD(ctx->opcode));
+    int rs = mmreg(uMIPS_RS(ctx->opcode));
+
+    gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]);
+}
+
+static void gen_addiusp (CPUState *env, DisasContext *ctx)
+{
+    int encoded = ZIMM(ctx->opcode, 1, 9);
+    int decoded;
+
+    if (encoded <= 1) {
+        decoded = 256 + encoded;
+    } else if (encoded <= 255) {
+        decoded = encoded;
+    } else if (encoded <= 509) {
+        decoded = encoded - 512;
+    } else {
+        decoded = encoded - 768;
+    }
+
+    gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, decoded << 2);
+}
+
+static void gen_addius5 (CPUState *env, DisasContext *ctx)
+{
+    int imm = SIMM(ctx->opcode, 1, 4);
+    int rd = (ctx->opcode >> 5) & 0x1f;
+
+    gen_arith_imm(env, ctx, OPC_ADDIU, rd, rd, imm);
+}
+
+static void gen_andi16 (CPUState *env, DisasContext *ctx)
+{
+    static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16,
+                                 31, 32, 63, 64, 255, 32768, 65535 };
+    int rd = mmreg(uMIPS_RD(ctx->opcode));
+    int rs = mmreg(uMIPS_RS(ctx->opcode));
+    int encoded = ZIMM(ctx->opcode, 0, 4);
+
+    gen_logic_imm(env, OPC_ANDI, rd, rs, decoded_imm[encoded]);
+}
+
+static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist,
+                               int base, int16_t offset)
+{
+    TCGv t0, t1;
+    TCGv_i32 t2;
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, base, offset);
+
+    t1 = tcg_const_tl(reglist);
+    t2 = tcg_const_i32(ctx->mem_idx);
+
+    save_cpu_state(ctx, 1);
+    switch (opc) {
+    case LWM32:
+        gen_helper_lwm(t0, t1, t2);
+        break;
+    case SWM32:
+        gen_helper_swm(t0, t1, t2);
+        break;
+#ifdef TARGET_MIPS64
+    case LDM:
+        gen_helper_ldm(t0, t1, t2);
+        break;
+    case SDM:
+        gen_helper_sdm(t0, t1, t2);
+        break;
+#endif
+    }
+    MIPS_DEBUG("%s, %x, %d(%s)", opn, reglist, offset, regnames[base]);
+    tcg_temp_free(t0);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+}
+
+
+static void gen_pool16c_insn (CPUState *env, DisasContext *ctx, int *is_branch)
+{
+    int rd = mmreg((ctx->opcode >> 3) & 0x7);
+    int rs = mmreg(ctx->opcode & 0x7);
+    int opc;
+
+    switch (((ctx->opcode) >> 4) & 0x3f) {
+    case NOT16 + 0:
+    case NOT16 + 1:
+    case NOT16 + 2:
+    case NOT16 + 3:
+        gen_logic(env, OPC_NOR, rd, rs, 0);
+        break;
+    case XOR16 + 0:
+    case XOR16 + 1:
+    case XOR16 + 2:
+    case XOR16 + 3:
+        gen_logic(env, OPC_XOR, rd, rd, rs);
+        break;
+    case AND16 + 0:
+    case AND16 + 1:
+    case AND16 + 2:
+    case AND16 + 3:
+        gen_logic(env, OPC_AND, rd, rd, rs);
+        break;
+    case OR16 + 0:
+    case OR16 + 1:
+    case OR16 + 2:
+    case OR16 + 3:
+        gen_logic(env, OPC_OR, rd, rd, rs);
+        break;
+    case LWM16 + 0:
+    case LWM16 + 1:
+    case LWM16 + 2:
+    case LWM16 + 3:
+        {
+            static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 };
+            int offset = ZIMM(ctx->opcode, 0, 4);
+
+            gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3],
+                              29, offset << 2);
+        }
+        break;
+    case SWM16 + 0:
+    case SWM16 + 1:
+    case SWM16 + 2:
+    case SWM16 + 3:
+        {
+            static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 };
+            int offset = ZIMM(ctx->opcode, 0, 4);
+
+            gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3],
+                              29, offset << 2);
+        }
+        break;
+    case JR16 + 0:
+    case JR16 + 1:
+        {
+            int reg = ctx->opcode & 0x1f;
+
+            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
+        }
+        *is_branch = 1;
+        break;
+    case JRC16 + 0:
+    case JRC16 + 1:
+        {
+            int reg = ctx->opcode & 0x1f;
+
+            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
+            /* Let normal delay slot handling in our caller take us
+               to the branch target.  */
+        }
+        break;
+    case JALR16 + 0:
+    case JALR16 + 1:
+        opc = OPC_JALR;
+        goto do_jalr;
+    case JALR16S + 0:
+    case JALR16S + 1:
+        opc = OPC_JALRS;
+    do_jalr:
+        {
+            int reg = ctx->opcode & 0x1f;
+
+            gen_compute_branch(ctx, opc, 2, reg, 31, 0);
+        }
+        *is_branch = 1;
+        break;
+    case MFHI16 + 0:
+    case MFHI16 + 1:
+        gen_HILO(ctx, OPC_MFHI, uMIPS_RS5(ctx->opcode));
+        break;
+    case MFLO16 + 0:
+    case MFLO16 + 1:
+        gen_HILO(ctx, OPC_MFLO, uMIPS_RS5(ctx->opcode));
+        break;
+    case BREAK16:
+        generate_exception(ctx, EXCP_BREAK);
+        break;
+    case SDBBP16:
+        /* XXX: not clear which exception should be raised
+         *      when in debug mode...
+         */
+        check_insn(env, ctx, ISA_MIPS32);
+        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+            generate_exception(ctx, EXCP_DBp);
+        } else {
+            generate_exception(ctx, EXCP_DBp);
+        }
+        break;
+    case JRADDIUSP + 0:
+    case JRADDIUSP + 1:
+        {
+            int imm = ZIMM(ctx->opcode, 0, 5);
+
+            gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0);
+            gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm << 2);
+            /* Let normal delay slot handling in our caller take us
+               to the branch target.  */
+        }
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static void gen_ldxs (DisasContext *ctx, int base, int index, int rd)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    gen_load_gpr(t0, base);
+
+    if (index != 0) {
+        gen_load_gpr(t1, index);
+        tcg_gen_shli_tl(t1, t1, 2);
+        gen_op_addr_add(ctx, t0, t1, t0);
+    }
+
+    save_cpu_state(ctx, 0);
+    op_ldst_lw(t1, t0, ctx);
+    gen_store_gpr(t1, rd);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
+                           int base, int16_t offset)
+{
+    const char *opn = "ldst_pair";
+    TCGv t0, t1;
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31 || rd == base) {
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, base, offset);
+
+    switch (opc) {
+    case LWP:
+        save_cpu_state(ctx, 0);
+        op_ldst_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);
+        gen_store_gpr(t1, rd+1);
+        opn = "lwp";
+        break;
+    case SWP:
+        save_cpu_state(ctx, 1);
+        gen_load_gpr(t1, rd);
+        op_ldst_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);
+        opn = "swp";
+        break;
+#ifdef TARGET_MIPS64
+    case LDP:
+        save_cpu_state(ctx, 0);
+        op_ldst_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);
+        gen_store_gpr(t1, rd+1);
+        opn = "ldp";
+        break;
+    case SDP:
+        save_cpu_state(ctx, 1);
+        gen_load_gpr(t1, rd);
+        op_ldst_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);
+        opn = "sdp";
+        break;
+#endif
+    }
+    MIPS_DEBUG("%s, %s, %d(%s)", opn, regnames[rd], offset, regnames[base]);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_pool32axf (CPUState *env, DisasContext *ctx, int rt, int rs,
+                           int *is_branch)
+{
+    int extension = (ctx->opcode >> 6) & 0x3f;
+    int minor = (ctx->opcode >> 12) & 0xf;
+    uint32_t mips32_op;
+
+    switch (extension) {
+    case TEQ:
+        mips32_op = OPC_TEQ;
+        goto do_trap;
+    case TGE:
+        mips32_op = OPC_TGE;
+        goto do_trap;
+    case TGEU:
+        mips32_op = OPC_TGEU;
+        goto do_trap;
+    case TLT:
+        mips32_op = OPC_TLT;
+        goto do_trap;
+    case TLTU:
+        mips32_op = OPC_TLTU;
+        goto do_trap;
+    case TNE:
+        mips32_op = OPC_TNE;
+    do_trap:
+        gen_trap(ctx, mips32_op, rs, rt, -1);
+        break;
+#ifndef CONFIG_USER_ONLY
+    case MFC0:
+    case MFC0 + 32:
+        if (rt == 0) {
+            /* Treat as NOP. */
+            break;
+        }
+        gen_mfc0(env, ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7);
+        break;
+    case MTC0:
+    case MTC0 + 32:
+        {
+            TCGv t0 = tcg_temp_new();
+
+            gen_load_gpr(t0, rt);
+            gen_mtc0(env, ctx, t0, rs, (ctx->opcode >> 11) & 0x7);
+            tcg_temp_free(t0);
+        }
+        break;
+#endif
+    case 0x2c:
+        switch (minor) {
+        case SEB:
+            gen_bshfl(ctx, OPC_SEB, rs, rt);
+            break;
+        case SEH:
+            gen_bshfl(ctx, OPC_SEH, rs, rt);
+            break;
+        case CLO:
+            mips32_op = OPC_CLO;
+            goto do_cl;
+        case CLZ:
+            mips32_op = OPC_CLZ;
+        do_cl:
+            check_insn(env, ctx, ISA_MIPS32);
+            gen_cl(ctx, mips32_op, rt, rs);
+            break;
+        case RDHWR:
+            gen_rdhwr(env, ctx, rt, rs);
+            break;
+        case WSBH:
+            gen_bshfl(ctx, OPC_WSBH, rs, rt);
+            break;
+        case MULT:
+            mips32_op = OPC_MULT;
+            goto do_muldiv;
+        case MULTU:
+            mips32_op = OPC_MULTU;
+            goto do_muldiv;
+        case DIV:
+            mips32_op = OPC_DIV;
+            goto do_muldiv;
+        case DIVU:
+            mips32_op = OPC_DIVU;
+            goto do_muldiv;
+        case MADD:
+            mips32_op = OPC_MADD;
+            goto do_muldiv;
+        case MADDU:
+            mips32_op = OPC_MADDU;
+            goto do_muldiv;
+        case MSUB:
+            mips32_op = OPC_MSUB;
+            goto do_muldiv;
+        case MSUBU:
+            mips32_op = OPC_MSUBU;
+        do_muldiv:
+            check_insn(env, ctx, ISA_MIPS32);
+            gen_muldiv(ctx, mips32_op, rs, rt);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x34:
+        switch (minor) {
+        case MFC2:
+        case MTC2:
+        case MFHC2:
+        case MTHC2:
+        case CFC2:
+        case CTC2:
+            generate_exception_err(ctx, EXCP_CpU, 2);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x3c:
+        switch (minor) {
+        case JALR:
+        case JALR_HB:
+            gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0);
+            *is_branch = 1;
+            break;
+        case JALRS:
+        case JALRS_HB:
+            gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0);
+            *is_branch = 1;
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x05:
+        switch (minor) {
+        case RDPGPR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_load_srsgpr(rt, rs);
+            break;
+        case WRPGPR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_store_srsgpr(rt, rs);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+#ifndef CONFIG_USER_ONLY
+    case 0x0d:
+        switch (minor) {
+        case TLBP:
+            mips32_op = OPC_TLBP;
+            goto do_cp0;
+        case TLBR:
+            mips32_op = OPC_TLBR;
+            goto do_cp0;
+        case TLBWI:
+            mips32_op = OPC_TLBWI;
+            goto do_cp0;
+        case TLBWR:
+            mips32_op = OPC_TLBWR;
+            goto do_cp0;
+        case WAIT:
+            mips32_op = OPC_WAIT;
+            goto do_cp0;
+        case DERET:
+            mips32_op = OPC_DERET;
+            goto do_cp0;
+        case ERET:
+            mips32_op = OPC_ERET;
+        do_cp0:
+            gen_cp0(env, ctx, mips32_op, rt, rs);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x1d:
+        switch (minor) {
+        case DI:
+            {
+                TCGv t0 = tcg_temp_new();
+
+                save_cpu_state(ctx, 1);
+                gen_helper_di(t0);
+                gen_store_gpr(t0, rs);
+                /* Stop translation as we may have switched the execution mode */
+                ctx->bstate = BS_STOP;
+                tcg_temp_free(t0);
+            }
+            break;
+        case EI:
+            {
+                TCGv t0 = tcg_temp_new();
+
+                save_cpu_state(ctx, 1);
+                gen_helper_ei(t0);
+                gen_store_gpr(t0, rs);
+                /* Stop translation as we may have switched the execution mode */
+                ctx->bstate = BS_STOP;
+                tcg_temp_free(t0);
+            }
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+#endif
+    case 0x2d:
+        switch (minor) {
+        case SYNC:
+            /* NOP */
+            break;
+        case SYSCALL:
+            generate_exception(ctx, EXCP_SYSCALL);
+            ctx->bstate = BS_STOP;
+            break;
+        case SDBBP:
+            check_insn(env, ctx, ISA_MIPS32);
+            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+                generate_exception(ctx, EXCP_DBp);
+            } else {
+                generate_exception(ctx, EXCP_DBp);
+            }
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    case 0x35:
+        switch (minor) {
+        case MFHI32:
+            gen_HILO(ctx, OPC_MFHI, rs);
+            break;
+        case MFLO32:
+            gen_HILO(ctx, OPC_MFLO, rs);
+            break;
+        case MTHI32:
+            gen_HILO(ctx, OPC_MTHI, rs);
+            break;
+        case MTLO32:
+            gen_HILO(ctx, OPC_MTLO, rs);
+            break;
+        default:
+            goto pool32axf_invalid;
+        }
+        break;
+    default:
+    pool32axf_invalid:
+        MIPS_INVAL("pool32axf");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+/* Values for microMIPS fmt field.  Variable-width, depending on which
+   formats the instruction supports.  */
+
+enum {
+    FMT_SD_S = 0,
+    FMT_SD_D = 1,
+
+    FMT_SDPS_S = 0,
+    FMT_SDPS_D = 1,
+    FMT_SDPS_PS = 2,
+
+    FMT_SWL_S = 0,
+    FMT_SWL_W = 1,
+    FMT_SWL_L = 2,
+
+    FMT_DWL_D = 0,
+    FMT_DWL_W = 1,
+    FMT_DWL_L = 2
+};
+
+static void gen_pool32fxf (CPUState *env, DisasContext *ctx, int rt, int rs)
+{
+    int extension = (ctx->opcode >> 6) & 0x3ff;
+    uint32_t mips32_op;
+
+#define FLOAT_1BIT_FMT(opc, fmt) (fmt << 8) | opc
+#define FLOAT_2BIT_FMT(opc, fmt) (fmt << 7) | opc
+#define COND_FLOAT_MOV(opc, cond) (cond << 7) | opc
+
+    switch (extension) {
+    case FLOAT_1BIT_FMT(CFC1, 0):
+        mips32_op = OPC_CFC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(CTC1, 0):
+        mips32_op = OPC_CTC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(MFC1, 0):
+        mips32_op = OPC_MFC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(MTC1, 0):
+        mips32_op = OPC_MTC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(MFHC1, 0):
+        mips32_op = OPC_MFHC1;
+        goto do_cp1;
+    case FLOAT_1BIT_FMT(MTHC1, 0):
+        mips32_op = OPC_MTHC1;
+    do_cp1:
+        gen_cp1(ctx, mips32_op, rt, rs);
+        break;
+
+        /* Reciprocal square root */
+    case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S):
+        mips32_op = OPC_RSQRT_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D):
+        mips32_op = OPC_RSQRT_D;
+        goto do_unaryfp;
+
+        /* Square root */
+    case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S):
+        mips32_op = OPC_SQRT_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D):
+        mips32_op = OPC_SQRT_D;
+        goto do_unaryfp;
+
+        /* Reciprocal */
+    case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S):
+        mips32_op = OPC_RECIP_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D):
+        mips32_op = OPC_RECIP_D;
+        goto do_unaryfp;
+
+        /* Floor */
+    case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S):
+        mips32_op = OPC_FLOOR_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D):
+        mips32_op = OPC_FLOOR_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S):
+        mips32_op = OPC_FLOOR_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D):
+        mips32_op = OPC_FLOOR_W_D;
+        goto do_unaryfp;
+
+        /* Ceiling */
+    case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S):
+        mips32_op = OPC_CEIL_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D):
+        mips32_op = OPC_CEIL_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S):
+        mips32_op = OPC_CEIL_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D):
+        mips32_op = OPC_CEIL_W_D;
+        goto do_unaryfp;
+
+        /* Truncation */
+    case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S):
+        mips32_op = OPC_TRUNC_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D):
+        mips32_op = OPC_TRUNC_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S):
+        mips32_op = OPC_TRUNC_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D):
+        mips32_op = OPC_TRUNC_W_D;
+        goto do_unaryfp;
+
+        /* Round */
+    case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S):
+        mips32_op = OPC_ROUND_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D):
+        mips32_op = OPC_ROUND_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S):
+        mips32_op = OPC_ROUND_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D):
+        mips32_op = OPC_ROUND_W_D;
+        goto do_unaryfp;
+
+        /* Integer to floating-point conversion */
+    case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S):
+        mips32_op = OPC_CVT_L_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D):
+        mips32_op = OPC_CVT_L_D;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S):
+        mips32_op = OPC_CVT_W_S;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D):
+        mips32_op = OPC_CVT_W_D;
+        goto do_unaryfp;
+
+        /* Paired-foo conversions */
+    case FLOAT_1BIT_FMT(CVT_S_PL, 0):
+        mips32_op = OPC_CVT_S_PL;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_S_PU, 0):
+        mips32_op = OPC_CVT_S_PU;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_PW_PS, 0):
+        mips32_op = OPC_CVT_PW_PS;
+        goto do_unaryfp;
+    case FLOAT_1BIT_FMT(CVT_PS_PW, 0):
+        mips32_op = OPC_CVT_PS_PW;
+        goto do_unaryfp;
+
+        /* Floating-point moves */
+    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S):
+        mips32_op = OPC_MOV_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D):
+        mips32_op = OPC_MOV_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_MOV_PS;
+        goto do_unaryfp;
+
+        /* Absolute value */
+    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S):
+        mips32_op = OPC_ABS_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D):
+        mips32_op = OPC_ABS_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_ABS_PS;
+        goto do_unaryfp;
+
+        /* Negation */
+    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S):
+        mips32_op = OPC_NEG_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D):
+        mips32_op = OPC_NEG_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_NEG_PS;
+        goto do_unaryfp;
+
+        /* Reciprocal square root step */
+    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S):
+        mips32_op = OPC_RSQRT1_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D):
+        mips32_op = OPC_RSQRT1_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_RSQRT1_PS;
+        goto do_unaryfp;
+
+        /* Reciprocal step */
+    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S):
+        mips32_op = OPC_RECIP1_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D):
+        mips32_op = OPC_RECIP1_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS):
+        mips32_op = OPC_RECIP1_PS;
+        goto do_unaryfp;
+
+        /* Conversions from double */
+    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S):
+        mips32_op = OPC_CVT_D_S;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W):
+        mips32_op = OPC_CVT_D_W;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L):
+        mips32_op = OPC_CVT_D_L;
+        goto do_unaryfp;
+
+        /* Conversions from single */
+    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D):
+        mips32_op = OPC_CVT_S_D;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W):
+        mips32_op = OPC_CVT_S_W;
+        goto do_unaryfp;
+    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L):
+        mips32_op = OPC_CVT_S_L;
+    do_unaryfp:
+        gen_farith(ctx, mips32_op, -1, rs, rt, 0);
+        break;
+
+        /* Conditional moves on floating-point codes */
+    case COND_FLOAT_MOV(MOVT, 0):
+    case COND_FLOAT_MOV(MOVT, 1):
+    case COND_FLOAT_MOV(MOVT, 2):
+    case COND_FLOAT_MOV(MOVT, 3):
+    case COND_FLOAT_MOV(MOVT, 4):
+    case COND_FLOAT_MOV(MOVT, 5):
+    case COND_FLOAT_MOV(MOVT, 6):
+    case COND_FLOAT_MOV(MOVT, 7):
+        gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1);
+        break;
+    case COND_FLOAT_MOV(MOVF, 0):
+    case COND_FLOAT_MOV(MOVF, 1):
+    case COND_FLOAT_MOV(MOVF, 2):
+    case COND_FLOAT_MOV(MOVF, 3):
+    case COND_FLOAT_MOV(MOVF, 4):
+    case COND_FLOAT_MOV(MOVF, 5):
+    case COND_FLOAT_MOV(MOVF, 6):
+    case COND_FLOAT_MOV(MOVF, 7):
+        gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0);
+        break;
+    default:
+        MIPS_INVAL("pool32fxf");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static void decode_micromips32_opc (CPUState *env, DisasContext *ctx,
+                                    uint16_t insn_hw1, int *is_branch)
+{
+    int32_t offset;
+    uint16_t insn;
+    int rt, rs, rd, rr;
+    int16_t imm;
+    uint32_t op, minor, mips32_op;
+    uint32_t cond, fmt, cc;
+
+    insn = lduw_code(ctx->pc + 2);
+    ctx->opcode = (ctx->opcode << 16) | insn;
+
+    rt = (ctx->opcode >> 21) & 0x1f;
+    rs = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+    rr = (ctx->opcode >> 6) & 0x1f;
+    imm = (int16_t) ctx->opcode;
+
+    op = (ctx->opcode >> 26) & 0x3f;
+    switch (op) {
+    case POOL32A:
+        minor = ctx->opcode & 0x3f;
+        switch (minor) {
+        case 0x00:
+            minor = (ctx->opcode >> 6) & 0xf;
+            switch (minor) {
+            case SLL32:
+                mips32_op = OPC_SLL;
+                goto do_shifti;
+            case SRA:
+                mips32_op = OPC_SRA;
+                goto do_shifti;
+            case SRL32:
+                mips32_op = OPC_SRL;
+                goto do_shifti;
+            case ROTR:
+                mips32_op = OPC_ROTR;
+            do_shifti:
+                gen_shift_imm(env, ctx, mips32_op, rt, rs, rd);
+                break;
+            default:
+                goto pool32a_invalid;
+            }
+            break;
+        case 0x10:
+            minor = (ctx->opcode >> 6) & 0xf;
+            switch (minor) {
+                /* Arithmetic */
+            case ADD:
+                mips32_op = OPC_ADD;
+                goto do_arith;
+            case ADDU32:
+                mips32_op = OPC_ADDU;
+                goto do_arith;
+            case SUB:
+                mips32_op = OPC_SUB;
+                goto do_arith;
+            case SUBU32:
+                mips32_op = OPC_SUBU;
+                goto do_arith;
+            case MUL:
+                mips32_op = OPC_MUL;
+            do_arith:
+                gen_arith(env, ctx, mips32_op, rd, rs, rt);
+                break;
+                /* Shifts */
+            case SLLV:
+                mips32_op = OPC_SLLV;
+                goto do_shift;
+            case SRLV:
+                mips32_op = OPC_SRLV;
+                goto do_shift;
+            case SRAV:
+                mips32_op = OPC_SRAV;
+                goto do_shift;
+            case ROTRV:
+                mips32_op = OPC_ROTRV;
+            do_shift:
+                gen_shift(env, ctx, mips32_op, rd, rs, rt);
+                break;
+                /* Logical operations */
+            case AND:
+                mips32_op = OPC_AND;
+                goto do_logic;
+            case OR32:
+                mips32_op = OPC_OR;
+                goto do_logic;
+            case NOR:
+                mips32_op = OPC_NOR;
+                goto do_logic;
+            case XOR32:
+                mips32_op = OPC_XOR;
+            do_logic:
+                gen_logic(env, mips32_op, rd, rs, rt);
+                break;
+                /* Set less than */
+            case SLT:
+                mips32_op = OPC_SLT;
+                goto do_slt;
+            case SLTU:
+                mips32_op = OPC_SLTU;
+            do_slt:
+                gen_slt(env, mips32_op, rd, rs, rt);
+                break;
+            default:
+                goto pool32a_invalid;
+            }
+            break;
+        case 0x18:
+            minor = (ctx->opcode >> 6) & 0xf;
+            switch (minor) {
+                /* Conditional moves */
+            case MOVN:
+                mips32_op = OPC_MOVN;
+                goto do_cmov;
+            case MOVZ:
+                mips32_op = OPC_MOVZ;
+            do_cmov:
+                gen_cond_move(env, mips32_op, rd, rs, rt);
+                break;
+            case LWXS:
+                gen_ldxs(ctx, rs, rt, rd);
+                break;
+            default:
+                goto pool32a_invalid;
+            }
+            break;
+        case INS:
+            gen_bitops(ctx, OPC_INS, rt, rs, rr, rd);
+            return;
+        case EXT:
+            gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd);
+            return;
+        case POOL32AXF:
+            gen_pool32axf(env, ctx, rt, rs, is_branch);
+            break;
+        case 0x07:
+            generate_exception(ctx, EXCP_BREAK);
+            break;
+        default:
+        pool32a_invalid:
+                MIPS_INVAL("pool32a");
+                generate_exception(ctx, EXCP_RI);
+                break;
+        }
+        break;
+    case POOL32B:
+        minor = (ctx->opcode >> 12) & 0xf;
+        switch (minor) {
+        case CACHE:
+            /* Treat as no-op. */
+            break;
+        case LWC2:
+        case SWC2:
+            /* COP2: Not implemented. */
+            generate_exception_err(ctx, EXCP_CpU, 2);
+            break;
+        case LWP:
+        case SWP:
+#ifdef TARGET_MIPS64
+        case LDP:
+        case SDP:
+#endif
+            gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+        case LWM32:
+        case SWM32:
+#ifdef TARGET_MIPS64
+        case LDM:
+        case SDM:
+#endif
+            gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+        default:
+            MIPS_INVAL("pool32b");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case POOL32F:
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            minor = ctx->opcode & 0x3f;
+            check_cp1_enabled(ctx);
+            switch (minor) {
+            case ALNV_PS:
+                mips32_op = OPC_ALNV_PS;
+                goto do_madd;
+            case MADD_S:
+                mips32_op = OPC_MADD_S;
+                goto do_madd;
+            case MADD_D:
+                mips32_op = OPC_MADD_D;
+                goto do_madd;
+            case MADD_PS:
+                mips32_op = OPC_MADD_PS;
+                goto do_madd;
+            case MSUB_S:
+                mips32_op = OPC_MSUB_S;
+                goto do_madd;
+            case MSUB_D:
+                mips32_op = OPC_MSUB_D;
+                goto do_madd;
+            case MSUB_PS:
+                mips32_op = OPC_MSUB_PS;
+                goto do_madd;
+            case NMADD_S:
+                mips32_op = OPC_NMADD_S;
+                goto do_madd;
+            case NMADD_D:
+                mips32_op = OPC_NMADD_D;
+                goto do_madd;
+            case NMADD_PS:
+                mips32_op = OPC_NMADD_PS;
+                goto do_madd;
+            case NMSUB_S:
+                mips32_op = OPC_NMSUB_S;
+                goto do_madd;
+            case NMSUB_D:
+                mips32_op = OPC_NMSUB_D;
+                goto do_madd;
+            case NMSUB_PS:
+                mips32_op = OPC_NMSUB_PS;
+            do_madd:
+                gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt);
+                break;
+            case CABS_COND_FMT:
+                cond = (ctx->opcode >> 6) & 0xf;
+                cc = (ctx->opcode >> 13) & 0x7;
+                fmt = (ctx->opcode >> 10) & 0x3;
+                switch (fmt) {
+                case 0x0:
+                    gen_cmpabs_s(ctx, cond, rt, rs, cc);
+                    break;
+                case 0x1:
+                    gen_cmpabs_d(ctx, cond, rt, rs, cc);
+                    break;
+                case 0x2:
+                    gen_cmpabs_ps(ctx, cond, rt, rs, cc);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case C_COND_FMT:
+                cond = (ctx->opcode >> 6) & 0xf;
+                cc = (ctx->opcode >> 13) & 0x7;
+                fmt = (ctx->opcode >> 10) & 0x3;
+                switch (fmt) {
+                case 0x0:
+                    gen_cmp_s(ctx, cond, rt, rs, cc);
+                    break;
+                case 0x1:
+                    gen_cmp_d(ctx, cond, rt, rs, cc);
+                    break;
+                case 0x2:
+                    gen_cmp_ps(ctx, cond, rt, rs, cc);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case POOL32FXF:
+                gen_pool32fxf(env, ctx, rt, rs);
+                break;
+            case 0x00:
+                /* PLL foo */
+                switch ((ctx->opcode >> 6) & 0x7) {
+                case PLL_PS:
+                    mips32_op = OPC_PLL_PS;
+                    goto do_ps;
+                case PLU_PS:
+                    mips32_op = OPC_PLU_PS;
+                    goto do_ps;
+                case PUL_PS:
+                    mips32_op = OPC_PUL_PS;
+                    goto do_ps;
+                case PUU_PS:
+                    mips32_op = OPC_PUU_PS;
+                    goto do_ps;
+                case CVT_PS_S:
+                    mips32_op = OPC_CVT_PS_S;
+                do_ps:
+                    gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case 0x08:
+                /* [LS][WDU]XC1 */
+                switch ((ctx->opcode >> 6) & 0x7) {
+                case LWXC1:
+                    mips32_op = OPC_LWXC1;
+                    goto do_ldst_cp1;
+                case SWXC1:
+                    mips32_op = OPC_SWXC1;
+                    goto do_ldst_cp1;
+                case LDXC1:
+                    mips32_op = OPC_LDXC1;
+                    goto do_ldst_cp1;
+                case SDXC1:
+                    mips32_op = OPC_SDXC1;
+                    goto do_ldst_cp1;
+                case LUXC1:
+                    mips32_op = OPC_LUXC1;
+                    goto do_ldst_cp1;
+                case SUXC1:
+                    mips32_op = OPC_SUXC1;
+                do_ldst_cp1:
+                    gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case 0x18:
+                /* 3D insns */
+                fmt = (ctx->opcode >> 9) & 0x3;
+                switch ((ctx->opcode >> 6) & 0x7) {
+                case RSQRT2_FMT:
+                    switch (fmt) {
+                    case FMT_SDPS_S:
+                        mips32_op = OPC_RSQRT2_S;
+                        goto do_3d;
+                    case FMT_SDPS_D:
+                        mips32_op = OPC_RSQRT2_D;
+                        goto do_3d;
+                    case FMT_SDPS_PS:
+                        mips32_op = OPC_RSQRT2_PS;
+                        goto do_3d;
+                    default:
+                        goto pool32f_invalid;
+                    }
+                    break;
+                case RECIP2_FMT:
+                    switch (fmt) {
+                    case FMT_SDPS_S:
+                        mips32_op = OPC_RECIP2_S;
+                        goto do_3d;
+                    case FMT_SDPS_D:
+                        mips32_op = OPC_RECIP2_D;
+                        goto do_3d;
+                    case FMT_SDPS_PS:
+                        mips32_op = OPC_RECIP2_PS;
+                        goto do_3d;
+                    default:
+                        goto pool32f_invalid;
+                    }
+                    break;
+                case ADDR_PS:
+                    mips32_op = OPC_ADDR_PS;
+                    goto do_3d;
+                case MULR_PS:
+                    mips32_op = OPC_MULR_PS;
+                do_3d:
+                    gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case 0x20:
+                /* MOV[FT].fmt and PREFX */
+                cc = (ctx->opcode >> 13) & 0x7;
+                fmt = (ctx->opcode >> 9) & 0x3;
+                switch ((ctx->opcode >> 6) & 0x7) {
+                case MOVF_FMT:
+                    switch (fmt) {
+                    case FMT_SDPS_S:
+                        gen_movcf_s(rs, rt, cc, 0);
+                        break;
+                    case FMT_SDPS_D:
+                        gen_movcf_d(ctx, rs, rt, cc, 0);
+                        break;
+                    case FMT_SDPS_PS:
+                        gen_movcf_ps(rs, rt, cc, 0);
+                        break;
+                    default:
+                        goto pool32f_invalid;
+                    }
+                    break;
+                case MOVT_FMT:
+                    switch (fmt) {
+                    case FMT_SDPS_S:
+                        gen_movcf_s(rs, rt, cc, 1);
+                        break;
+                    case FMT_SDPS_D:
+                        gen_movcf_d(ctx, rs, rt, cc, 1);
+                        break;
+                    case FMT_SDPS_PS:
+                        gen_movcf_ps(rs, rt, cc, 1);
+                        break;
+                    default:
+                        goto pool32f_invalid;
+                    }
+                    break;
+                case PREFX:
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+#define FINSN_3ARG_SDPS(prfx)                           \
+                switch ((ctx->opcode >> 8) & 0x3) {     \
+                case FMT_SDPS_S:                        \
+                    mips32_op = OPC_##prfx##_S;         \
+                    goto do_fpop;                       \
+                case FMT_SDPS_D:                        \
+                    mips32_op = OPC_##prfx##_D;         \
+                    goto do_fpop;                       \
+                case FMT_SDPS_PS:                       \
+                    mips32_op = OPC_##prfx##_PS;        \
+                    goto do_fpop;                       \
+                default:                                \
+                    goto pool32f_invalid;               \
+                }
+            case 0x30:
+                /* regular FP ops */
+                switch ((ctx->opcode >> 6) & 0x3) {
+                case ADD_FMT:
+                    FINSN_3ARG_SDPS(ADD);
+                    break;
+                case SUB_FMT:
+                    FINSN_3ARG_SDPS(SUB);
+                    break;
+                case MUL_FMT:
+                    FINSN_3ARG_SDPS(MUL);
+                    break;
+                case DIV_FMT:
+                    fmt = (ctx->opcode >> 8) & 0x3;
+                    if (fmt == 1) {
+                        mips32_op = OPC_DIV_D;
+                    } else if (fmt == 0) {
+                        mips32_op = OPC_DIV_S;
+                    } else {
+                        goto pool32f_invalid;
+                    }
+                    goto do_fpop;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            case 0x38:
+                /* cmovs */
+                switch ((ctx->opcode >> 6) & 0x3) {
+                case MOVN_FMT:
+                    FINSN_3ARG_SDPS(MOVN);
+                    break;
+                case MOVZ_FMT:
+                    FINSN_3ARG_SDPS(MOVZ);
+                    break;
+                default:
+                    goto pool32f_invalid;
+                }
+                break;
+            do_fpop:
+                gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+                break;
+            default:
+            pool32f_invalid:
+                MIPS_INVAL("pool32f");
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
+        }
+        break;
+    case POOL32I:
+        minor = (ctx->opcode >> 21) & 0x1f;
+        switch (minor) {
+        case BLTZ:
+            mips32_op = OPC_BLTZ;
+            goto do_branch;
+        case BLTZAL:
+            mips32_op = OPC_BLTZAL;
+            goto do_branch;
+        case BLTZALS:
+            mips32_op = OPC_BLTZALS;
+            goto do_branch;
+        case BGEZ:
+            mips32_op = OPC_BGEZ;
+            goto do_branch;
+        case BGEZAL:
+            mips32_op = OPC_BGEZAL;
+            goto do_branch;
+        case BGEZALS:
+            mips32_op = OPC_BGEZALS;
+            goto do_branch;
+        case BLEZ:
+            mips32_op = OPC_BLEZ;
+            goto do_branch;
+        case BGTZ:
+            mips32_op = OPC_BGTZ;
+        do_branch:
+            gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1);
+            *is_branch = 1;
+            break;
+
+            /* Traps */
+        case TLTI:
+            mips32_op = OPC_TLTI;
+            goto do_trapi;
+        case TGEI:
+            mips32_op = OPC_TGEI;
+            goto do_trapi;
+        case TLTIU:
+            mips32_op = OPC_TLTIU;
+            goto do_trapi;
+        case TGEIU:
+            mips32_op = OPC_TGEIU;
+            goto do_trapi;
+        case TNEI:
+            mips32_op = OPC_TNEI;
+            goto do_trapi;
+        case TEQI:
+            mips32_op = OPC_TEQI;
+        do_trapi:
+            gen_trap(ctx, mips32_op, rs, -1, imm);
+            break;
+
+        case BNEZC:
+        case BEQZC:
+            gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ,
+                               4, rs, 0, imm << 1);
+            /* Compact branches don't have a delay slot, so just let
+               the normal delay slot handling take us to the branch
+               target. */
+            break;
+        case LUI:
+            gen_logic_imm(env, OPC_LUI, rs, -1, imm);
+            break;
+        case SYNCI:
+            break;
+        case BC2F:
+        case BC2T:
+            /* COP2: Not implemented. */
+            generate_exception_err(ctx, EXCP_CpU, 2);
+            break;
+        case BC1F:
+            mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F;
+            goto do_cp1branch;
+        case BC1T:
+            mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T;
+            goto do_cp1branch;
+        case BC1ANY4F:
+            mips32_op = OPC_BC1FANY4;
+            goto do_cp1mips3d;
+        case BC1ANY4T:
+            mips32_op = OPC_BC1TANY4;
+        do_cp1mips3d:
+            check_cop1x(ctx);
+            check_insn(env, ctx, ASE_MIPS3D);
+            /* Fall through */
+        do_cp1branch:
+            gen_compute_branch1(env, ctx, mips32_op,
+                                (ctx->opcode >> 18) & 0x7, imm << 1);
+            *is_branch = 1;
+            break;
+        case BPOSGE64:
+        case BPOSGE32:
+            /* MIPS DSP: not implemented */
+            /* Fall through */
+        default:
+            MIPS_INVAL("pool32i");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case POOL32C:
+        minor = (ctx->opcode >> 12) & 0xf;
+        switch (minor) {
+        case LWL:
+            mips32_op = OPC_LWL;
+            goto do_ldst_lr;
+        case SWL:
+            mips32_op = OPC_SWL;
+            goto do_ldst_lr;
+        case LWR:
+            mips32_op = OPC_LWR;
+            goto do_ldst_lr;
+        case SWR:
+            mips32_op = OPC_SWR;
+            goto do_ldst_lr;
+#if defined(TARGET_MIPS64)
+        case LDL:
+            mips32_op = OPC_LDL;
+            goto do_ldst_lr;
+        case SDL:
+            mips32_op = OPC_SDL;
+            goto do_ldst_lr;
+        case LDR:
+            mips32_op = OPC_LDR;
+            goto do_ldst_lr;
+        case SDR:
+            mips32_op = OPC_SDR;
+            goto do_ldst_lr;
+        case LWU:
+            mips32_op = OPC_LWU;
+            goto do_ldst_lr;
+        case LLD:
+            mips32_op = OPC_LLD;
+            goto do_ldst_lr;
+#endif
+        case LL:
+            mips32_op = OPC_LL;
+        do_ldst_lr:
+            gen_ldst(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));
+            break;
+#if defined(TARGET_MIPS64)
+        case SCD:
+            gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12));
+            break;
+#endif
+        case PREF:
+            /* Treat as no-op */
+            break;
+        default:
+            MIPS_INVAL("pool32c");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case ADDI32:
+        mips32_op = OPC_ADDI;
+        goto do_addi;
+    case ADDIU32:
+        mips32_op = OPC_ADDIU;
+    do_addi:
+        gen_arith_imm(env, ctx, mips32_op, rt, rs, imm);
+        break;
+
+        /* Logical operations */
+    case ORI32:
+        mips32_op = OPC_ORI;
+        goto do_logici;
+    case XORI32:
+        mips32_op = OPC_XORI;
+        goto do_logici;
+    case ANDI32:
+        mips32_op = OPC_ANDI;
+    do_logici:
+        gen_logic_imm(env, mips32_op, rt, rs, imm);
+        break;
+
+        /* Set less than immediate */
+    case SLTI32:
+        mips32_op = OPC_SLTI;
+        goto do_slti;
+    case SLTIU32:
+        mips32_op = OPC_SLTIU;
+    do_slti:
+        gen_slt_imm(env, mips32_op, rt, rs, imm);
+        break;
+    case JALX32:
+        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+        gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset);
+        *is_branch = 1;
+        break;
+    case JALS32:
+        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1;
+        gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset);
+        *is_branch = 1;
+        break;
+    case BEQ32:
+        gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1);
+        *is_branch = 1;
+        break;
+    case BNE32:
+        gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1);
+        *is_branch = 1;
+        break;
+    case J32:
+        gen_compute_branch(ctx, OPC_J, 4, rt, rs,
+                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
+        *is_branch = 1;
+        break;
+    case JAL32:
+        gen_compute_branch(ctx, OPC_JAL, 4, rt, rs,
+                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
+        *is_branch = 1;
+        break;
+        /* Floating point (COP1) */
+    case LWC132:
+        mips32_op = OPC_LWC1;
+        goto do_cop1;
+    case LDC132:
+        mips32_op = OPC_LDC1;
+        goto do_cop1;
+    case SWC132:
+        mips32_op = OPC_SWC1;
+        goto do_cop1;
+    case SDC132:
+        mips32_op = OPC_SDC1;
+    do_cop1:
+        gen_cop1_ldst(env, ctx, mips32_op, rt, rs, imm);
+        break;
+    case ADDIUPC:
+        {
+            int reg = mmreg(ZIMM(ctx->opcode, 23, 3));
+            int offset = SIMM(ctx->opcode, 0, 23) << 2;
+
+            gen_addiupc(ctx, reg, offset, 0, 0);
+        }
+        break;
+        /* Loads and stores */
+    case LB32:
+        mips32_op = OPC_LB;
+        goto do_ldst;
+    case LBU32:
+        mips32_op = OPC_LBU;
+        goto do_ldst;
+    case LH32:
+        mips32_op = OPC_LH;
+        goto do_ldst;
+    case LHU32:
+        mips32_op = OPC_LHU;
+        goto do_ldst;
+    case LW32:
+        mips32_op = OPC_LW;
+        goto do_ldst;
+#ifdef TARGET_MIPS64
+    case LD32:
+        mips32_op = OPC_LD;
+        goto do_ldst;
+    case SD32:
+        mips32_op = OPC_SD;
+        goto do_ldst;
+#endif
+    case SB32:
+        mips32_op = OPC_SB;
+        goto do_ldst;
+    case SH32:
+        mips32_op = OPC_SH;
+        goto do_ldst;
+    case SW32:
+        mips32_op = OPC_SW;
+    do_ldst:
+        gen_ldst(ctx, mips32_op, rt, rs, imm);
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branch)
+{
+    uint32_t op;
+
+    /* make sure instructions are on a halfword boundary */
+    if (ctx->pc & 0x1) {
+        env->CP0_BadVAddr = ctx->pc;
+        generate_exception(ctx, EXCP_AdEL);
+        ctx->bstate = BS_STOP;
+        return 2;
+    }
+
+    op = (ctx->opcode >> 10) & 0x3f;
+    /* Enforce properly-sized instructions in a delay slot */
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+        int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT;
+
+        switch (op) {
+        case POOL32A:
+        case POOL32B:
+        case POOL32I:
+        case POOL32C:
+        case ADDI32:
+        case ADDIU32:
+        case ORI32:
+        case XORI32:
+        case SLTI32:
+        case SLTIU32:
+        case ANDI32:
+        case JALX32:
+        case LBU32:
+        case LHU32:
+        case POOL32F:
+        case JALS32:
+        case BEQ32:
+        case BNE32:
+        case J32:
+        case JAL32:
+        case SB32:
+        case SH32:
+        case POOL32S:
+        case ADDIUPC:
+        case SWC132:
+        case SDC132:
+        case SD32:
+        case SW32:
+        case LB32:
+        case LH32:
+        case DADDIU32:
+        case POOL48A:           /* ??? */
+        case LWC132:
+        case LDC132:
+        case LD32:
+        case LW32:
+            if (bits & MIPS_HFLAG_BDS16) {
+                generate_exception(ctx, EXCP_RI);
+                /* Just stop translation; the user is confused.  */
+                ctx->bstate = BS_STOP;
+                return 2;
+            }
+            break;
+        case POOL16A:
+        case POOL16B:
+        case POOL16C:
+        case LWGP16:
+        case POOL16F:
+        case LBU16:
+        case LHU16:
+        case LWSP16:
+        case LW16:
+        case SB16:
+        case SH16:
+        case SWSP16:
+        case SW16:
+        case MOVE16:
+        case ANDI16:
+        case POOL16D:
+        case POOL16E:
+        case BEQZ16:
+        case BNEZ16:
+        case B16:
+        case LI16:
+            if (bits & MIPS_HFLAG_BDS32) {
+                generate_exception(ctx, EXCP_RI);
+                /* Just stop translation; the user is confused.  */
+                ctx->bstate = BS_STOP;
+                return 2;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    switch (op) {
+    case POOL16A:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rs1 = mmreg(uMIPS_RS1(ctx->opcode));
+            int rs2 = mmreg(uMIPS_RS2(ctx->opcode));
+            uint32_t opc = 0;
+
+            switch (ctx->opcode & 0x1) {
+            case ADDU16:
+                opc = OPC_ADDU;
+                break;
+            case SUBU16:
+                opc = OPC_SUBU;
+                break;
+            }
+
+            gen_arith(env, ctx, opc, rd, rs1, rs2);
+        }
+        break;
+    case POOL16B:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rs = mmreg(uMIPS_RS(ctx->opcode));
+            int amount = (ctx->opcode >> 1) & 0x7;
+            uint32_t opc = 0;
+            amount = amount == 0 ? 8 : amount;
+
+            switch (ctx->opcode & 0x1) {
+            case SLL16:
+                opc = OPC_SLL;
+                break;
+            case SRL16:
+                opc = OPC_SRL;
+                break;
+            }
+
+            gen_shift_imm(env, ctx, opc, rd, rs, amount);
+        }
+        break;
+    case POOL16C:
+        gen_pool16c_insn(env, ctx, is_branch);
+        break;
+    case LWGP16:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rb = 28;            /* GP */
+            int16_t offset = SIMM(ctx->opcode, 0, 7) << 2;
+
+            gen_ldst(ctx, OPC_LW, rd, rb, offset);
+        }
+        break;
+    case POOL16F:
+        if (ctx->opcode & 1) {
+            generate_exception(ctx, EXCP_RI);
+        } else {
+            /* MOVEP */
+            int enc_dest = uMIPS_RD(ctx->opcode);
+            int enc_rt = uMIPS_RS2(ctx->opcode);
+            int enc_rs = uMIPS_RS1(ctx->opcode);
+            int rd, rs, re, rt;
+            static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 };
+            static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 };
+            static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 };
+
+            rd = rd_enc[enc_dest];
+            re = re_enc[enc_dest];
+            rs = rs_rt_enc[enc_rs];
+            rt = rs_rt_enc[enc_rt];
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0);
+            gen_arith_imm(env, ctx, OPC_ADDIU, re, rt, 0);
+        }
+        break;
+    case LBU16:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4);
+            offset = (offset == 0xf ? -1 : offset);
+
+            gen_ldst(ctx, OPC_LBU, rd, rb, offset);
+        }
+        break;
+    case LHU16:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;
+
+            gen_ldst(ctx, OPC_LHU, rd, rb, offset);
+        }
+        break;
+    case LWSP16:
+        {
+            int rd = (ctx->opcode >> 5) & 0x1f;
+            int rb = 29;            /* SP */
+            int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;
+
+            gen_ldst(ctx, OPC_LW, rd, rb, offset);
+        }
+        break;
+    case LW16:
+        {
+            int rd = mmreg(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;
+
+            gen_ldst(ctx, OPC_LW, rd, rb, offset);
+        }
+        break;
+    case SB16:
+        {
+            int rd = mmreg2(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4);
+
+            gen_ldst(ctx, OPC_SB, rd, rb, offset);
+        }
+        break;
+    case SH16:
+        {
+            int rd = mmreg2(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;
+
+            gen_ldst(ctx, OPC_SH, rd, rb, offset);
+        }
+        break;
+    case SWSP16:
+        {
+            int rd = (ctx->opcode >> 5) & 0x1f;
+            int rb = 29;            /* SP */
+            int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;
+
+            gen_ldst(ctx, OPC_SW, rd, rb, offset);
+        }
+        break;
+    case SW16:
+        {
+            int rd = mmreg2(uMIPS_RD(ctx->opcode));
+            int rb = mmreg(uMIPS_RS(ctx->opcode));
+            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;
+
+            gen_ldst(ctx, OPC_SW, rd, rb, offset);
+        }
+        break;
+    case MOVE16:
+        {
+            int rd = uMIPS_RD5(ctx->opcode);
+            int rs = uMIPS_RS5(ctx->opcode);
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0);
+        }
+        break;
+    case ANDI16:
+        gen_andi16(env, ctx);
+        break;
+    case POOL16D:
+        switch (ctx->opcode & 0x1) {
+        case ADDIUS5:
+            gen_addius5(env, ctx);
+            break;
+        case ADDIUSP:
+            gen_addiusp(env, ctx);
+            break;
+        }
+        break;
+    case POOL16E:
+        switch (ctx->opcode & 0x1) {
+        case ADDIUR2:
+            gen_addiur2(env, ctx);
+            break;
+        case ADDIUR1SP:
+            gen_addiur1sp(env, ctx);
+            break;
+        }
+        break;
+    case B16:
+        gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0,
+                           SIMM(ctx->opcode, 0, 10) << 1);
+        *is_branch = 1;
+        break;
+    case BNEZ16:
+    case BEQZ16:
+        gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2,
+                           mmreg(uMIPS_RD(ctx->opcode)),
+                           0, SIMM(ctx->opcode, 0, 7) << 1);
+        *is_branch = 1;
+        break;
+    case LI16:
+        {
+            int reg = mmreg(uMIPS_RD(ctx->opcode));
+            int imm = ZIMM(ctx->opcode, 0, 7);
+
+            imm = (imm == 0x7f ? -1 : imm);
+            tcg_gen_movi_tl(cpu_gpr[reg], imm);
+        }
+        break;
+    case RES_20:
+    case RES_28:
+    case RES_29:
+    case RES_30:
+    case RES_31:
+    case RES_38:
+    case RES_39:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    default:
+        decode_micromips32_opc (env, ctx, op, is_branch);
+        return 4;
+    }
+
+    return 2;
+}
+
 /* SmartMIPS extension to MIPS32 */
 
 #if defined(TARGET_MIPS64)
@@ -9548,7 +11924,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
         break;
 #endif
     case OPC_JALX:
-        check_insn(env, ctx, ASE_MIPS16);
+        check_insn(env, ctx, ASE_MIPS16 | ASE_MICROMIPS);
         offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
         gen_compute_branch(ctx, op, 4, rs, rt, offset);
         *is_branch = 1;
@@ -9636,11 +12012,15 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
             ctx.opcode = ldl_code(ctx.pc);
             insn_bytes = 4;
             decode_opc(env, &ctx, &is_branch);
+        } else if (env->insn_flags & ASE_MICROMIPS) {
+            ctx.opcode = lduw_code(ctx.pc);
+            insn_bytes = decode_micromips_opc(env, &ctx, &is_branch);
         } else if (env->insn_flags & ASE_MIPS16) {
             ctx.opcode = lduw_code(ctx.pc);
             insn_bytes = decode_mips16_opc(env, &ctx, &is_branch);
         } else {
             generate_exception(&ctx, EXCP_RI);
+            ctx.bstate = BS_STOP;
             break;
         }
         if (!is_branch) {
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 5/8] target-mips: add microMIPS CPUs
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
                   ` (3 preceding siblings ...)
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 4/8] target-mips: microMIPS ASE support Nathan Froyd
@ 2010-06-08 20:30 ` Nathan Froyd
  2010-06-09 14:02   ` Aurelien Jarno
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 6/8] target-mips: add microMIPS exception handler support Nathan Froyd
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien


Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 target-mips/translate_init.c |   61 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index b79ed56..8e17f4b 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -141,6 +141,25 @@ static const mips_def_t mips_defs[] =
         .mmu_type = MMU_TYPE_FMT,
     },
     {
+        .name = "4Km-micromips",
+        .CP0_PRid = 0x00018300,
+        /* Config1 implemented, fixed mapping MMU,
+           no virtual icache, uncached coherency. */
+        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_FMT << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1258FF17,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS,
+        .mmu_type = MMU_TYPE_FMT,
+    },
+    {
         .name = "4KEcR1",
         .CP0_PRid = 0x00018400,
         .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_R4000 << CP0C0_MT),
@@ -245,6 +264,25 @@ static const mips_def_t mips_defs[] =
         .mmu_type = MMU_TYPE_R4000,
     },
     {
+        .name = "24Kc-micromips",
+        .CP0_PRid = 0x00019300,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x1278FF1F,
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
         .name = "24Kf",
         .CP0_PRid = 0x00019300,
         .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
@@ -269,6 +307,29 @@ static const mips_def_t mips_defs[] =
         .mmu_type = MMU_TYPE_R4000,
     },
     {
+        .name = "24Kf-micromips",
+        .CP0_PRid = 0x00019300,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
+                    (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
+                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 4,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x3678FF1F,
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+        .SEGBITS = 32,
+        .PABITS = 32,
+        .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
         .name = "34Kf",
         .CP0_PRid = 0x00019500,
         .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 6/8] target-mips: add microMIPS exception handler support
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
                   ` (4 preceding siblings ...)
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 5/8] target-mips: add microMIPS CPUs Nathan Froyd
@ 2010-06-08 20:30 ` Nathan Froyd
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 7/8] linux-user: honor low bit of entry PC for MIPS Nathan Froyd
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien

Unlike MIPS16, microMIPS lets you choose the ISA mode for your exception
handlers.  The ISA mode is selectable via a user-writable CP0.Config3
flag.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 target-mips/cpu.h    |    1 +
 target-mips/helper.c |   21 +++++++++++++++------
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 7285636..c21b8e4 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -363,6 +363,7 @@ struct CPUMIPSState {
 #define CP0C2_SA   0
     int32_t CP0_Config3;
 #define CP0C3_M    31
+#define CP0C3_ISA_ON_EXC 16
 #define CP0C3_DSPP 10
 #define CP0C3_LPA  7
 #define CP0C3_VEIC 6
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 8102f03..ea221ab 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -385,6 +385,18 @@ static target_ulong exception_resume_pc (CPUState *env)
 
     return bad_pc;
 }
+
+static void set_hflags_for_handler (CPUState *env)
+{
+    /* Exception handlers are entered in 32-bit mode.  */
+    env->hflags &= ~(MIPS_HFLAG_M16);
+    /* ...except that microMIPS lets you choose.  */
+    if (env->insn_flags & ASE_MICROMIPS) {
+        env->hflags |= (!!(env->CP0_Config3
+                           & (1 << CP0C3_ISA_ON_EXC))
+                        << MIPS_HFLAG_M16_SHIFT);
+    }
+}
 #endif
 
 void do_interrupt (CPUState *env)
@@ -440,8 +452,7 @@ void do_interrupt (CPUState *env)
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
         env->active_tc.PC = (int32_t)0xBFC00480;
-        /* Exception handlers are entered in 32-bit mode.  */
-        env->hflags &= ~(MIPS_HFLAG_M16);
+        set_hflags_for_handler(env);
         break;
     case EXCP_RESET:
         cpu_reset(env);
@@ -461,8 +472,7 @@ void do_interrupt (CPUState *env)
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
         env->active_tc.PC = (int32_t)0xBFC00000;
-        /* Exception handlers are entered in 32-bit mode.  */
-        env->hflags &= ~(MIPS_HFLAG_M16);
+        set_hflags_for_handler(env);
         break;
     case EXCP_EXT_INTERRUPT:
         cause = 0;
@@ -581,8 +591,7 @@ void do_interrupt (CPUState *env)
             env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
         }
         env->active_tc.PC += offset;
-        /* Exception handlers are entered in 32-bit mode.  */
-        env->hflags &= ~(MIPS_HFLAG_M16);
+        set_hflags_for_handler(env);
         env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
         break;
     default:
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 7/8] linux-user: honor low bit of entry PC for MIPS
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
                   ` (5 preceding siblings ...)
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 6/8] target-mips: add microMIPS exception handler support Nathan Froyd
@ 2010-06-08 20:30 ` Nathan Froyd
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 8/8] hw: honor low bit in mipssim machine Nathan Froyd
  2010-06-09 14:10 ` [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Aurelien Jarno
  8 siblings, 0 replies; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien


Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 linux-user/main.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index 0f23fc9..ad292f1 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3271,7 +3271,10 @@ int main(int argc, char **argv, char **envp)
         for(i = 0; i < 32; i++) {
             env->active_tc.gpr[i] = regs->regs[i];
         }
-        env->active_tc.PC = regs->cp0_epc;
+        env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+        if (regs->cp0_epc & 1) {
+            env->hflags |= MIPS_HFLAG_M16;
+        }
     }
 #elif defined(TARGET_SH4)
     {
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 8/8] hw: honor low bit in mipssim machine
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
                   ` (6 preceding siblings ...)
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 7/8] linux-user: honor low bit of entry PC for MIPS Nathan Froyd
@ 2010-06-08 20:30 ` Nathan Froyd
  2010-06-09 14:10 ` [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Aurelien Jarno
  8 siblings, 0 replies; 13+ messages in thread
From: Nathan Froyd @ 2010-06-08 20:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien


Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 hw/mips_mipssim.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index a747de5..293d99e 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -106,7 +106,10 @@ static void main_cpu_reset(void *opaque)
     CPUState *env = s->env;
 
     cpu_reset(env);
-    env->active_tc.PC = s->vector;
+    env->active_tc.PC = s->vector & ~(target_ulong)1;
+    if (s->vector & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
 }
 
 static void
-- 
1.6.3.2

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

* Re: [Qemu-devel] [PATCH 5/8] target-mips: add microMIPS CPUs
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 5/8] target-mips: add microMIPS CPUs Nathan Froyd
@ 2010-06-09 14:02   ` Aurelien Jarno
  0 siblings, 0 replies; 13+ messages in thread
From: Aurelien Jarno @ 2010-06-09 14:02 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Tue, Jun 08, 2010 at 01:30:00PM -0700, Nathan Froyd wrote:
> 
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
>  target-mips/translate_init.c |   61 ++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 61 insertions(+), 0 deletions(-)
> 
> diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
> index b79ed56..8e17f4b 100644
> --- a/target-mips/translate_init.c
> +++ b/target-mips/translate_init.c
> @@ -141,6 +141,25 @@ static const mips_def_t mips_defs[] =
>          .mmu_type = MMU_TYPE_FMT,
>      },
>      {
> +        .name = "4Km-micromips",
> +        .CP0_PRid = 0x00018300,
> +        /* Config1 implemented, fixed mapping MMU,
> +           no virtual icache, uncached coherency. */
> +        .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_FMT << CP0C0_MT),
> +        .CP0_Config1 = MIPS_CONFIG1 |
> +		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
> +		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
> +        .CP0_Config2 = MIPS_CONFIG2,
> +        .CP0_Config3 = MIPS_CONFIG3,
> +        .SYNCI_Step = 32,
> +        .CCRes = 2,
> +        .CP0_Status_rw_bitmask = 0x1258FF17,
> +        .SEGBITS = 32,
> +        .PABITS = 32,
> +        .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS,
> +        .mmu_type = MMU_TYPE_FMT,
> +    },
> +    {
>          .name = "4KEcR1",
>          .CP0_PRid = 0x00018400,
>          .CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_R4000 << CP0C0_MT),
> @@ -245,6 +264,25 @@ static const mips_def_t mips_defs[] =
>          .mmu_type = MMU_TYPE_R4000,
>      },
>      {
> +        .name = "24Kc-micromips",
> +        .CP0_PRid = 0x00019300,
> +        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
> +                    (MMU_TYPE_R4000 << CP0C0_MT),
> +        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
> +		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
> +		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
> +        .CP0_Config2 = MIPS_CONFIG2,
> +        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
> +        .SYNCI_Step = 32,
> +        .CCRes = 2,
> +        /* No DSP implemented. */
> +        .CP0_Status_rw_bitmask = 0x1278FF1F,
> +        .SEGBITS = 32,
> +        .PABITS = 32,
> +        .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS,
> +        .mmu_type = MMU_TYPE_R4000,
> +    },
> +    {
>          .name = "24Kf",
>          .CP0_PRid = 0x00019300,
>          .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
> @@ -269,6 +307,29 @@ static const mips_def_t mips_defs[] =
>          .mmu_type = MMU_TYPE_R4000,
>      },
>      {
> +        .name = "24Kf-micromips",
> +        .CP0_PRid = 0x00019300,
> +        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
> +                    (MMU_TYPE_R4000 << CP0C0_MT),
> +        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
> +                       (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
> +                       (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
> +        .CP0_Config2 = MIPS_CONFIG2,
> +        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
> +        .CP0_LLAddr_rw_bitmask = 0,
> +        .CP0_LLAddr_shift = 4,
> +        .SYNCI_Step = 32,
> +        .CCRes = 2,
> +        /* No DSP implemented. */
> +        .CP0_Status_rw_bitmask = 0x3678FF1F,
> +        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
> +                    (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
> +        .SEGBITS = 32,
> +        .PABITS = 32,
> +        .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS,
> +        .mmu_type = MMU_TYPE_R4000,
> +    },
> +    {
>          .name = "34Kf",
>          .CP0_PRid = 0x00019500,
>          .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |

None of those CPU seems to be real CPU. According to the MIPS website
(which BTW has very few details about microMIPS), the microMIPS ASE is
implemented in the M14K core, which seems to be a 4K core with R2 and
microMIPS support. Wouldn't it be better to add this one instead?

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH 4/8] target-mips: microMIPS ASE support
  2010-06-08 20:29 ` [Qemu-devel] [PATCH 4/8] target-mips: microMIPS ASE support Nathan Froyd
@ 2010-06-09 14:08   ` Aurelien Jarno
  0 siblings, 0 replies; 13+ messages in thread
From: Aurelien Jarno @ 2010-06-09 14:08 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Tue, Jun 08, 2010 at 01:29:59PM -0700, Nathan Froyd wrote:
> Add instruction decoding for the microMIPS ASE.  All we do is decode and
> then forward to the existing gen_* routines.
> 
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
>  target-mips/helper.h    |    9 +
>  target-mips/mips-defs.h |    1 +
>  target-mips/op_helper.c |  136 +++
>  target-mips/translate.c | 2390 ++++++++++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 2531 insertions(+), 5 deletions(-)
> 
> diff --git a/target-mips/helper.h b/target-mips/helper.h
> index ab47b1a..a6ba75d 100644
> --- a/target-mips/helper.h
> +++ b/target-mips/helper.h
> @@ -160,6 +160,15 @@ DEF_HELPER_1(emt, tl, tl)
>  DEF_HELPER_1(dvpe, tl, tl)
>  DEF_HELPER_1(evpe, tl, tl)
>  #endif /* !CONFIG_USER_ONLY */
> +
> +/* microMIPS functions */
> +DEF_HELPER_3(lwm, void, tl, tl, i32);
> +DEF_HELPER_3(swm, void, tl, tl, i32);
> +#ifdef TARGET_MIPS64
> +DEF_HELPER_3(ldm, void, tl, tl, i32);
> +DEF_HELPER_3(sdm, void, tl, tl, i32);
> +#endif
> +
>  DEF_HELPER_2(fork, void, tl, tl)
>  DEF_HELPER_1(yield, tl, tl)
>  
> diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
> index c57de02..a7f4697 100644
> --- a/target-mips/mips-defs.h
> +++ b/target-mips/mips-defs.h
> @@ -38,6 +38,7 @@
>  #define		ASE_DSPR2	0x00010000
>  #define		ASE_MT		0x00020000
>  #define		ASE_SMARTMIPS	0x00040000
> +#define 	ASE_MICROMIPS	0x00080000
>  
>  /* Chip specific instructions. */
>  #define		INSN_VR54XX	0x80000000
> diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
> index 2bfdd50..56c5e59 100644
> --- a/target-mips/op_helper.c
> +++ b/target-mips/op_helper.c
> @@ -565,6 +565,142 @@ void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
>  }
>  #endif /* TARGET_MIPS64 */
>  
> +static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
> +
> +void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
> +{
> +    target_ulong base_reglist = reglist & 0xf;
> +    target_ulong do_r31 = reglist & 0x10;
> +#ifdef CONFIG_USER_ONLY
> +#undef ldfun
> +#define ldfun ldl_raw
> +#else
> +    uint32_t (*ldfun)(target_ulong);
> +
> +    switch (mem_idx)
> +    {
> +    case 0: ldfun = ldl_kernel; break;
> +    case 1: ldfun = ldl_super; break;
> +    default:
> +    case 2: ldfun = ldl_user; break;
> +    }
> +#endif
> +
> +    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> +        target_ulong i;
> +
> +        for (i = 0; i < base_reglist; i++) {
> +            env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
> +            addr += 4;
> +        }
> +    }
> +
> +    if (do_r31) {
> +        env->active_tc.gpr[31] = (target_long) ldfun(addr);
> +    }
> +}
> +
> +void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
> +{
> +    target_ulong base_reglist = reglist & 0xf;
> +    target_ulong do_r31 = reglist & 0x10;
> +#ifdef CONFIG_USER_ONLY
> +#undef stfun 
> +#define stfun stl_raw
> +#else
> +    void (*stfun)(target_ulong, uint32_t);
> +
> +    switch (mem_idx)
> +    {
> +    case 0: stfun = stl_kernel; break;
> +    case 1: stfun = stl_super; break;
> +     default:
> +    case 2: stfun = stl_user; break;
> +    }
> +#endif
> +
> +    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> +        target_ulong i;
> +
> +        for (i = 0; i < base_reglist; i++) {
> +            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
> +            addr += 4;
> +        }
> +    }
> +
> +    if (do_r31) {
> +        stfun(addr, env->active_tc.gpr[31]);
> +    }
> +}
> +
> +#if defined(TARGET_MIPS64)
> +void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
> +{
> +    target_ulong base_reglist = reglist & 0xf;
> +    target_ulong do_r31 = reglist & 0x10;
> +#ifdef CONFIG_USER_ONLY
> +#undef ldfun
> +#define ldfun ldq_raw
> +#else
> +    uint64_t (*ldfun)(target_ulong);
> +
> +    switch (mem_idx)
> +    {
> +    case 0: ldfun = ldq_kernel; break;
> +    case 1: ldfun = ldq_super; break;
> +    default:
> +    case 2: ldfun = ldq_user; break;
> +    }
> +#endif
> +
> +    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> +        target_ulong i;
> +
> +        for (i = 0; i < base_reglist; i++) {
> +            env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
> +            addr += 8;
> +        }
> +    }
> +
> +    if (do_r31) {
> +        env->active_tc.gpr[31] = ldfun(addr);
> +    }
> +}
> +
> +void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
> +{
> +    target_ulong base_reglist = reglist & 0xf;
> +    target_ulong do_r31 = reglist & 0x10;
> +#ifdef CONFIG_USER_ONLY
> +#undef stfun
> +#define stfun stq_raw
> +#else
> +    void (*stfun)(target_ulong, uint64_t);
> +
> +    switch (mem_idx)
> +    {
> +    case 0: stfun = stq_kernel; break;
> +    case 1: stfun = stq_super; break;
> +     default:
> +    case 2: stfun = stq_user; break;
> +    }
> +#endif
> +
> +    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
> +        target_ulong i;
> +
> +        for (i = 0; i < base_reglist; i++) {
> +            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
> +            addr += 8;
> +        }
> +    }
> +
> +    if (do_r31) {
> +        stfun(addr, env->active_tc.gpr[31]);
> +    }
> +}
> +#endif
> +
>  #ifndef CONFIG_USER_ONLY
>  /* CP0 helpers */
>  target_ulong helper_mfc0_mvpcontrol (void)

As the list of registers is included in the opcode, I do wonder if it
wouldn't be better to do this directly in translate.c as TCG code.


-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3
  2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
                   ` (7 preceding siblings ...)
  2010-06-08 20:30 ` [Qemu-devel] [PATCH 8/8] hw: honor low bit in mipssim machine Nathan Froyd
@ 2010-06-09 14:10 ` Aurelien Jarno
  2010-06-09 15:39   ` Nathan Froyd
  8 siblings, 1 reply; 13+ messages in thread
From: Aurelien Jarno @ 2010-06-09 14:10 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Tue, Jun 08, 2010 at 01:29:55PM -0700, Nathan Froyd wrote:
> This patch series adds support for the microMIPS ASE.  microMIPS is a
> new ASE similar to MIPS16, but re-encodes the entire instruction set
> into 16-bit and 32-bit instructions--in contrast to MIPS16, which
> re-encodes only integer instructions.  The mechanisms for going in and
> out of microMIPS mode are identical to those for MIPS16; a given chip
> cannot support both ASEs simultaneously.
> 
> changes from v2:
>   give actual name to FOP constants; assign names to FOPs for c{,abs}
>   fix up coding style violations
>   fix helpers for recent ldl_*/stl_* prototype changes
>   split out mips16-related changes into separate patch
>   group patches more logically
> 
> changes from v1:
>   fix re-introduction of previously deleted code noted by rth
> 
> Nathan Froyd (8):
>   target-mips: define constants for magic numbers
>   target-mips: refactor c{,abs}.cond.fmt insns
>   target-mips: mips16 cleanups
>   target-mips: microMIPS ASE support
>   target-mips: add microMIPS CPUs
>   target-mips: add microMIPS exception handler support
>   linux-user: honor low bit of entry PC for MIPS
>   hw: honor low bit in mipssim machine
> 
>  hw/mips_mipssim.c            |    5 +-
>  linux-user/main.c            |    5 +-
>  target-mips/cpu.h            |    1 +
>  target-mips/helper.c         |   21 +-
>  target-mips/helper.h         |    9 +
>  target-mips/mips-defs.h      |    1 +
>  target-mips/op_helper.c      |  136 ++
>  target-mips/translate.c      | 3015 ++++++++++++++++++++++++++++++++++++++----
>  target-mips/translate_init.c |   61 +
>  9 files changed, 3009 insertions(+), 245 deletions(-)
> 

I have applied all patches except the 5th one, see my comments about it.

I also have applied a complementary patch to the first one, that moves
FP FMT comments to a more appropriate place. It doesn't change any code.

Finally, I have made some comments about the 4th patch, that may be a
basis for future improvements.

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3
  2010-06-09 14:10 ` [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Aurelien Jarno
@ 2010-06-09 15:39   ` Nathan Froyd
  0 siblings, 0 replies; 13+ messages in thread
From: Nathan Froyd @ 2010-06-09 15:39 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: qemu-devel

On Wed, Jun 09, 2010 at 04:10:25PM +0200, Aurelien Jarno wrote:
> On Tue, Jun 08, 2010 at 01:29:55PM -0700, Nathan Froyd wrote:
> > This patch series adds support for the microMIPS ASE.  microMIPS is a
> > new ASE similar to MIPS16, but re-encodes the entire instruction set
> > into 16-bit and 32-bit instructions--in contrast to MIPS16, which
> > re-encodes only integer instructions.  The mechanisms for going in and
> > out of microMIPS mode are identical to those for MIPS16; a given chip
> > cannot support both ASEs simultaneously.
> 
> I have applied all patches except the 5th one, see my comments about
> it.

Thanks for applying these.  I agree with you about the 5th one and will
submit a M14K patch in the next week.

> Finally, I have made some comments about the 4th patch, that may be a
> basis for future improvements.

Indeed.  I will work on that one.

-Nathan

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

end of thread, other threads:[~2010-06-09 15:39 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-08 20:29 [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Nathan Froyd
2010-06-08 20:29 ` [Qemu-devel] [PATCH 1/8] target-mips: define constants for magic numbers Nathan Froyd
2010-06-08 20:29 ` [Qemu-devel] [PATCH 2/8] target-mips: refactor c{, abs}.cond.fmt insns Nathan Froyd
2010-06-08 20:29 ` [Qemu-devel] [PATCH 3/8] target-mips: mips16 cleanups Nathan Froyd
2010-06-08 20:29 ` [Qemu-devel] [PATCH 4/8] target-mips: microMIPS ASE support Nathan Froyd
2010-06-09 14:08   ` Aurelien Jarno
2010-06-08 20:30 ` [Qemu-devel] [PATCH 5/8] target-mips: add microMIPS CPUs Nathan Froyd
2010-06-09 14:02   ` Aurelien Jarno
2010-06-08 20:30 ` [Qemu-devel] [PATCH 6/8] target-mips: add microMIPS exception handler support Nathan Froyd
2010-06-08 20:30 ` [Qemu-devel] [PATCH 7/8] linux-user: honor low bit of entry PC for MIPS Nathan Froyd
2010-06-08 20:30 ` [Qemu-devel] [PATCH 8/8] hw: honor low bit in mipssim machine Nathan Froyd
2010-06-09 14:10 ` [Qemu-devel] [PATCH 0/8] target-mips: add microMIPS ASE support, v3 Aurelien Jarno
2010-06-09 15:39   ` Nathan Froyd

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.