qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support
@ 2009-11-23 20:49 Nathan Froyd
  2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
                   ` (11 more replies)
  0 siblings, 12 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:49 UTC (permalink / raw)
  To: qemu-devel

This patchset adds MIPS16 support to the MIPS backend.  MIPS16 is a
compact encoding of a subset of the MIPS integer instructions, similar
to ARM's Thumb mode.  The processor enters MIPS16 mode by executing a
special jump instruction; execution continus at the jump target in
MIPS16 mode until the processor returns to MIPS32/64 mode by executing a
special jump instruction.

The patches have been tested with GCC's testsuite and GDB's testsuite.

-Nathan

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

* [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
@ 2009-11-23 20:49 ` Nathan Froyd
  2009-11-28 10:17   ` Aurelien Jarno
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 02/11] target-mips: add new HFLAGs for JALX and 16/32-bit delay slots Nathan Froyd
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:49 UTC (permalink / raw)
  To: qemu-devel


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

diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 82f9a38..e8febe6 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -167,6 +167,7 @@ struct TCState {
     target_ulong CP0_TCContext;
     target_ulong CP0_TCSchedule;
     target_ulong CP0_TCScheFBack;
+    uint32_t ISAMode; /* MIPS32 or MIPS16 mode */
     int32_t CP0_Debug_tcstatus;
 };
 
diff --git a/target-mips/translate.c b/target-mips/translate.c
index e9d9224..b0a1b29 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -463,6 +463,7 @@ typedef struct DisasContext {
     struct TranslationBlock *tb;
     target_ulong pc, saved_pc;
     uint32_t opcode;
+    int isa_mode;
     int singlestep_enabled;
     /* Routine used to access memory */
     int mem_idx;
@@ -8306,6 +8307,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     ctx.pc = pc_start;
     ctx.saved_pc = -1;
     ctx.singlestep_enabled = env->singlestep_enabled;
+    ctx.isa_mode = env->active_tc.ISAMode;
     ctx.tb = tb;
     ctx.bstate = BS_NONE;
     /* Restore delay slot state from the tb context.  */
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 02/11] target-mips: add new HFLAGs for JALX and 16/32-bit delay slots
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
  2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware Nathan Froyd
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel

We create separate masks for the "basic" branch hflags and the
"extended" branch hflags and define MIPS_HFLAG_BMASK as the logical or
of those two.  This is done to avoid churning the codebase in lots of
different places.

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

diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index e8febe6..9413be0 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -441,11 +441,17 @@ struct CPUMIPSState {
      * the delay slot, record what type of branch it is so that we can
      * resume translation properly.  It might be possible to reduce
      * this from three bits to two.  */
-#define MIPS_HFLAG_BMASK  0x1C00
+#define MIPS_HFLAG_BMASK_BASE  0x1C00
 #define MIPS_HFLAG_B      0x0400 /* Unconditional branch               */
 #define MIPS_HFLAG_BC     0x0800 /* Conditional branch                 */
 #define MIPS_HFLAG_BL     0x0C00 /* Likely branch                      */
 #define MIPS_HFLAG_BR     0x1000 /* branch to register (can't link TB) */
+    /* Extra flags about the current pending branch.  */
+#define MIPS_HFLAG_BMASK_EXT 0xE000
+#define MIPS_HFLAG_BDS16  0x2000 /* branch requires 16-bit delay slot  */
+#define MIPS_HFLAG_BDS32  0x4000 /* branch requires 32-bit delay slot  */
+#define MIPS_HFLAG_BX     0x8000 /* branch exchange execution mode     */
+#define MIPS_HFLAG_BMASK  (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT)
     target_ulong btarget;        /* Jump / branch target               */
     target_ulong bcond;          /* Branch condition (if needed)       */
 
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
  2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 02/11] target-mips: add new HFLAGs for JALX and 16/32-bit delay slots Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-28 10:17   ` Aurelien Jarno
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 04/11] target-mips: move ROTR and ROTRV inside gen_shift_{imm, } Nathan Froyd
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel


Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 target-mips/helper.c    |   47 ++++++++++++++++++++++++++---------------------
 target-mips/op_helper.c |   10 +++++++---
 2 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/target-mips/helper.c b/target-mips/helper.c
index 4a37277..e54a31a 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -339,6 +339,20 @@ static const char * const excp_names[EXCP_LAST + 1] = {
     [EXCP_CACHE] = "cache error",
 };
 
+static target_ulong exception_resume_pc (CPUState *env)
+{
+    target_ulong bad_pc;
+
+    bad_pc = env->active_tc.PC | env->active_tc.ISAMode;
+    if (env->hflags & MIPS_HFLAG_BMASK) {
+        /* If the exception was raised from a delay slot, come back to
+           the jump.  */
+        bad_pc -= (env->hflags & MIPS_HFLAG_BDS16 ? 2 : 4);
+    }
+
+    return bad_pc;
+}
+
 void do_interrupt (CPUState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
@@ -366,7 +380,7 @@ void do_interrupt (CPUState *env)
            resume will always occur on the next instruction
            (but we assume the pc has always been updated during
            code translation). */
-        env->CP0_DEPC = env->active_tc.PC;
+        env->CP0_DEPC = env->active_tc.PC | env->active_tc.ISAMode;
         goto enter_debug_mode;
     case EXCP_DINT:
         env->CP0_Debug |= 1 << CP0DB_DINT;
@@ -383,14 +397,8 @@ void do_interrupt (CPUState *env)
     case EXCP_DDBL:
         env->CP0_Debug |= 1 << CP0DB_DDBL;
     set_DEPC:
-        if (env->hflags & MIPS_HFLAG_BMASK) {
-            /* If the exception was raised from a delay slot,
-               come back to the jump.  */
-            env->CP0_DEPC = env->active_tc.PC - 4;
-            env->hflags &= ~MIPS_HFLAG_BMASK;
-        } else {
-            env->CP0_DEPC = env->active_tc.PC;
-        }
+        env->CP0_DEPC = exception_resume_pc(env);
+        env->hflags &= ~MIPS_HFLAG_BMASK;
  enter_debug_mode:
         env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
         env->hflags &= ~(MIPS_HFLAG_KSU);
@@ -398,6 +406,8 @@ 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->active_tc.ISAMode = 0;
         break;
     case EXCP_RESET:
         cpu_reset(env);
@@ -409,20 +419,16 @@ void do_interrupt (CPUState *env)
     case EXCP_NMI:
         env->CP0_Status |= (1 << CP0St_NMI);
  set_error_EPC:
-        if (env->hflags & MIPS_HFLAG_BMASK) {
-            /* If the exception was raised from a delay slot,
-               come back to the jump.  */
-            env->CP0_ErrorEPC = env->active_tc.PC - 4;
-            env->hflags &= ~MIPS_HFLAG_BMASK;
-        } else {
-            env->CP0_ErrorEPC = env->active_tc.PC;
-        }
+        env->CP0_ErrorEPC = exception_resume_pc(env);
+        env->hflags &= ~MIPS_HFLAG_BMASK;
         env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
         env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
         env->hflags &= ~(MIPS_HFLAG_KSU);
         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->active_tc.ISAMode = 0;
         break;
     case EXCP_EXT_INTERRUPT:
         cause = 0;
@@ -524,13 +530,10 @@ void do_interrupt (CPUState *env)
         }
  set_EPC:
         if (!(env->CP0_Status & (1 << CP0St_EXL))) {
+            env->CP0_EPC = exception_resume_pc(env);
             if (env->hflags & MIPS_HFLAG_BMASK) {
-                /* If the exception was raised from a delay slot,
-                   come back to the jump.  */
-                env->CP0_EPC = env->active_tc.PC - 4;
                 env->CP0_Cause |= (1 << CP0Ca_BD);
             } else {
-                env->CP0_EPC = env->active_tc.PC;
                 env->CP0_Cause &= ~(1 << CP0Ca_BD);
             }
             env->CP0_Status |= (1 << CP0St_EXL);
@@ -544,6 +547,8 @@ 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->active_tc.ISAMode = 0;
         env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
         break;
     default:
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 52d687d..d585d65 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1701,10 +1701,12 @@ void helper_eret (void)
 {
     debug_pre_eret();
     if (env->CP0_Status & (1 << CP0St_ERL)) {
-        env->active_tc.PC = env->CP0_ErrorEPC;
+        env->active_tc.PC = env->CP0_ErrorEPC & ~(target_ulong)1;
+        env->active_tc.ISAMode = env->CP0_ErrorEPC & 1;
         env->CP0_Status &= ~(1 << CP0St_ERL);
     } else {
-        env->active_tc.PC = env->CP0_EPC;
+        env->active_tc.PC = env->CP0_EPC & ~(target_ulong)1;
+        env->active_tc.ISAMode = env->CP0_EPC & 1;
         env->CP0_Status &= ~(1 << CP0St_EXL);
     }
     compute_hflags(env);
@@ -1715,7 +1717,9 @@ void helper_eret (void)
 void helper_deret (void)
 {
     debug_pre_eret();
-    env->active_tc.PC = env->CP0_DEPC;
+    env->active_tc.PC = env->CP0_DEPC & ~(target_ulong)1;
+    env->active_tc.ISAMode = env->CP0_DEPC & 1;
+
     env->hflags &= MIPS_HFLAG_DM;
     compute_hflags(env);
     debug_post_eret();
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 04/11] target-mips: move ROTR and ROTRV inside gen_shift_{imm, }
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (2 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 05/11] target-mips: make gen_compute_branch 16/32-bit-aware Nathan Froyd
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel

It's easier to implement mips16 shift instructions if we're not
examining the opcode inside gen_shift_{imm,}.  So move ROTR and ROTRV
and do the special-case handling of SRL and SRLV inside decode_opc.
Likewise for their 64-bit counterparts.

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

diff --git a/target-mips/translate.c b/target-mips/translate.c
index b0a1b29..c03d1bf 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -128,18 +128,23 @@ enum {
     /* SSNOP is SLL r0, r0, 1 */
     /* EHB is SLL r0, r0, 3 */
     OPC_SRL      = 0x02 | OPC_SPECIAL, /* also ROTR */
+    OPC_ROTR     = OPC_SRL | (1 << 21),
     OPC_SRA      = 0x03 | OPC_SPECIAL,
     OPC_SLLV     = 0x04 | OPC_SPECIAL,
     OPC_SRLV     = 0x06 | OPC_SPECIAL, /* also ROTRV */
+    OPC_ROTRV    = OPC_SRLV | (1 << 6),
     OPC_SRAV     = 0x07 | OPC_SPECIAL,
     OPC_DSLLV    = 0x14 | OPC_SPECIAL,
     OPC_DSRLV    = 0x16 | OPC_SPECIAL, /* also DROTRV */
+    OPC_DROTRV   = OPC_DSRLV | (1 << 6),
     OPC_DSRAV    = 0x17 | OPC_SPECIAL,
     OPC_DSLL     = 0x38 | OPC_SPECIAL,
     OPC_DSRL     = 0x3A | OPC_SPECIAL, /* also DROTR */
+    OPC_DROTR    = OPC_DSRL | (1 << 21),
     OPC_DSRA     = 0x3B | OPC_SPECIAL,
     OPC_DSLL32   = 0x3C | OPC_SPECIAL,
     OPC_DSRL32   = 0x3E | OPC_SPECIAL, /* also DROTR32 */
+    OPC_DROTR32  = OPC_DSRL32 | (1 << 21),
     OPC_DSRA32   = 0x3F | OPC_SPECIAL,
     /* Multiplication / division */
     OPC_MULT     = 0x18 | OPC_SPECIAL,
@@ -1447,43 +1452,24 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
         opn = "sra";
         break;
     case OPC_SRL:
-        switch ((ctx->opcode >> 21) & 0x1f) {
-        case 0:
-            if (uimm != 0) {
-                tcg_gen_ext32u_tl(t0, t0);
-                tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
-            } else {
-                tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
-            }
-            opn = "srl";
-            break;
-        case 1:
-            /* rotr is decoded as srl on non-R2 CPUs */
-            if (env->insn_flags & ISA_MIPS32R2) {
-                if (uimm != 0) {
-                    TCGv_i32 t1 = tcg_temp_new_i32();
-
-                    tcg_gen_trunc_tl_i32(t1, t0);
-                    tcg_gen_rotri_i32(t1, t1, uimm);
-                    tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
-                    tcg_temp_free_i32(t1);
-                }
-                opn = "rotr";
-            } else {
-                if (uimm != 0) {
-                    tcg_gen_ext32u_tl(t0, t0);
-                    tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
-                } else {
-                    tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
-                }
-                opn = "srl";
-            }
-            break;
-        default:
-            MIPS_INVAL("invalid srl flag");
-            generate_exception(ctx, EXCP_RI);
-            break;
+        if (uimm != 0) {
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
+        } else {
+            tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
         }
+        opn = "srl";
+        break;
+    case OPC_ROTR:
+        if (uimm != 0) {
+            TCGv_i32 t1 = tcg_temp_new_i32();
+
+            tcg_gen_trunc_tl_i32(t1, t0);
+            tcg_gen_rotri_i32(t1, t1, uimm);
+            tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
+            tcg_temp_free_i32(t1);
+        }
+        opn = "rotr";
         break;
 #if defined(TARGET_MIPS64)
     case OPC_DSLL:
@@ -1495,28 +1481,14 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
         opn = "dsra";
         break;
     case OPC_DSRL:
-        switch ((ctx->opcode >> 21) & 0x1f) {
-        case 0:
-            tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
-            opn = "dsrl";
-            break;
-        case 1:
-            /* drotr is decoded as dsrl on non-R2 CPUs */
-            if (env->insn_flags & ISA_MIPS32R2) {
-                if (uimm != 0) {
-                    tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
-                }
-                opn = "drotr";
-            } else {
-                tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
-                opn = "dsrl";
-            }
-            break;
-        default:
-            MIPS_INVAL("invalid dsrl flag");
-            generate_exception(ctx, EXCP_RI);
-            break;
+        tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
+        opn = "dsrl";
+        break;
+    case OPC_DROTR:
+        if (uimm != 0) {
+            tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
         }
+        opn = "drotr";
         break;
     case OPC_DSLL32:
         tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm + 32);
@@ -1527,26 +1499,12 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
         opn = "dsra32";
         break;
     case OPC_DSRL32:
-        switch ((ctx->opcode >> 21) & 0x1f) {
-        case 0:
-            tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
-            opn = "dsrl32";
-            break;
-        case 1:
-            /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
-            if (env->insn_flags & ISA_MIPS32R2) {
-                tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32);
-                opn = "drotr32";
-            } else {
-                tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
-                opn = "dsrl32";
-            }
-            break;
-        default:
-            MIPS_INVAL("invalid dsrl32 flag");
-            generate_exception(ctx, EXCP_RI);
-            break;
-        }
+        tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
+        opn = "dsrl32";
+        break;
+    case OPC_DROTR32:
+        tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32);
+        opn = "drotr32";
         break;
 #endif
     }
@@ -1895,40 +1853,25 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
         opn = "srav";
         break;
     case OPC_SRLV:
-        switch ((ctx->opcode >> 6) & 0x1f) {
-        case 0:
-            tcg_gen_ext32u_tl(t1, t1);
-            tcg_gen_andi_tl(t0, t0, 0x1f);
-            tcg_gen_shr_tl(t0, t1, t0);
-            tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
-            opn = "srlv";
-            break;
-        case 1:
-            /* rotrv is decoded as srlv on non-R2 CPUs */
-            if (env->insn_flags & ISA_MIPS32R2) {
-                TCGv_i32 t2 = tcg_temp_new_i32();
-                TCGv_i32 t3 = tcg_temp_new_i32();
-
-                tcg_gen_trunc_tl_i32(t2, t0);
-                tcg_gen_trunc_tl_i32(t3, t1);
-                tcg_gen_andi_i32(t2, t2, 0x1f);
-                tcg_gen_rotr_i32(t2, t3, t2);
-                tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
-                tcg_temp_free_i32(t2);
-                tcg_temp_free_i32(t3);
-                opn = "rotrv";
-            } else {
-                tcg_gen_ext32u_tl(t1, t1);
-                tcg_gen_andi_tl(t0, t0, 0x1f);
-                tcg_gen_shr_tl(t0, t1, t0);
-                tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
-                opn = "srlv";
-            }
-            break;
-        default:
-            MIPS_INVAL("invalid srlv flag");
-            generate_exception(ctx, EXCP_RI);
-            break;
+        tcg_gen_ext32u_tl(t1, t1);
+        tcg_gen_andi_tl(t0, t0, 0x1f);
+        tcg_gen_shr_tl(t0, t1, t0);
+        tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
+        opn = "srlv";
+        break;
+    case OPC_ROTRV:
+        {
+            TCGv_i32 t2 = tcg_temp_new_i32();
+            TCGv_i32 t3 = tcg_temp_new_i32();
+
+            tcg_gen_trunc_tl_i32(t2, t0);
+            tcg_gen_trunc_tl_i32(t3, t1);
+            tcg_gen_andi_i32(t2, t2, 0x1f);
+            tcg_gen_rotr_i32(t2, t3, t2);
+            tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
+            tcg_temp_free_i32(t2);
+            tcg_temp_free_i32(t3);
+            opn = "rotrv";
         }
         break;
 #if defined(TARGET_MIPS64)
@@ -1943,29 +1886,14 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
         opn = "dsrav";
         break;
     case OPC_DSRLV:
-        switch ((ctx->opcode >> 6) & 0x1f) {
-        case 0:
-            tcg_gen_andi_tl(t0, t0, 0x3f);
-            tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
-            opn = "dsrlv";
-            break;
-        case 1:
-            /* drotrv is decoded as dsrlv on non-R2 CPUs */
-            if (env->insn_flags & ISA_MIPS32R2) {
-                tcg_gen_andi_tl(t0, t0, 0x3f);
-                tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
-                opn = "drotrv";
-            } else {
-                tcg_gen_andi_tl(t0, t0, 0x3f);
-                tcg_gen_shr_tl(t0, t1, t0);
-                opn = "dsrlv";
-            }
-            break;
-        default:
-            MIPS_INVAL("invalid dsrlv flag");
-            generate_exception(ctx, EXCP_RI);
-            break;
-        }
+        tcg_gen_andi_tl(t0, t0, 0x3f);
+        tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
+        opn = "dsrlv";
+        break;
+    case OPC_DROTRV:
+        tcg_gen_andi_tl(t0, t0, 0x3f);
+        tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
+        opn = "drotrv";
         break;
 #endif
     }
@@ -7677,9 +7605,24 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         switch (op1) {
         case OPC_SLL:          /* Shift with immediate */
         case OPC_SRA:
-        case OPC_SRL:
             gen_shift_imm(env, ctx, op1, rd, rt, sa);
             break;
+        case OPC_SRL:
+            switch ((ctx->opcode >> 21) & 0x1f) {
+            case 1:
+                /* rotr is decoded as srl on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_ROTR;
+                }
+                /* Fallthrough */
+            case 0:
+                gen_shift_imm(env, ctx, op1, rd, rt, sa);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
         case OPC_MOVN:         /* Conditional move */
         case OPC_MOVZ:
             check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
@@ -7689,10 +7632,25 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             gen_arith(env, ctx, op1, rd, rs, rt);
             break;
         case OPC_SLLV:         /* Shifts */
-        case OPC_SRLV:
         case OPC_SRAV:
             gen_shift(env, ctx, op1, rd, rs, rt);
             break;
+        case OPC_SRLV:
+            switch ((ctx->opcode >> 6) & 0x1f) {
+            case 1:
+                /* rotrv is decoded as srlv on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_ROTRV;
+                }
+                /* Fallthrough */
+            case 0:
+                gen_shift(env, ctx, op1, rd, rs, rt);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
         case OPC_SLT:          /* Set on less than */
         case OPC_SLTU:
             gen_slt(env, op1, rd, rs, rt);
@@ -7770,14 +7728,48 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
        /* MIPS64 specific opcodes */
         case OPC_DSLL:
         case OPC_DSRA:
-        case OPC_DSRL:
         case OPC_DSLL32:
         case OPC_DSRA32:
-        case OPC_DSRL32:
             check_insn(env, ctx, ISA_MIPS3);
             check_mips_64(ctx);
             gen_shift_imm(env, ctx, op1, rd, rt, sa);
             break;
+        case OPC_DSRL:
+            switch ((ctx->opcode >> 21) & 0x1f) {
+            case 1:
+                /* drotr is decoded as dsrl on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_DROTR;
+                }
+                /* Fallthrough */
+            case 0:
+                check_insn(env, ctx, ISA_MIPS3);
+                check_mips_64(ctx);
+                gen_shift_imm(env, ctx, op1, rd, rt, sa);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        case OPC_DSRL32:
+            switch ((ctx->opcode >> 21) & 0x1f) {
+            case 1:
+                /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_DROTR32;
+                }
+                /* Fallthrough */
+            case 0:
+                check_insn(env, ctx, ISA_MIPS3);
+                check_mips_64(ctx);
+                gen_shift_imm(env, ctx, op1, rd, rt, sa);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
         case OPC_DADD ... OPC_DSUBU:
             check_insn(env, ctx, ISA_MIPS3);
             check_mips_64(ctx);
@@ -7785,11 +7777,28 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             break;
         case OPC_DSLLV:
         case OPC_DSRAV:
-        case OPC_DSRLV:
             check_insn(env, ctx, ISA_MIPS3);
             check_mips_64(ctx);
             gen_shift(env, ctx, op1, rd, rs, rt);
             break;
+        case OPC_DSRLV:
+            switch ((ctx->opcode >> 6) & 0x1f) {
+            case 1:
+                /* drotrv is decoded as dsrlv on non-R2 CPUs */
+                if (env->insn_flags & ISA_MIPS32R2) {
+                    op1 = OPC_DROTRV;
+                }
+                /* Fallthrough */
+            case 0:
+                check_insn(env, ctx, ISA_MIPS3);
+                check_mips_64(ctx);
+                gen_shift(env, ctx, op1, rd, rs, rt);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
         case OPC_DMULT ... OPC_DDIVU:
             check_insn(env, ctx, ISA_MIPS3);
             check_mips_64(ctx);
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 05/11] target-mips: make gen_compute_branch 16/32-bit-aware
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (3 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 04/11] target-mips: move ROTR and ROTRV inside gen_shift_{imm, } Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr Nathan Froyd
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel


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

diff --git a/target-mips/translate.c b/target-mips/translate.c
index c03d1bf..1157e97 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -2406,6 +2406,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
 
 /* Branches (before delay slot) */
 static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
+                                int insn_bytes,
                                 int rs, int rt, int32_t offset)
 {
     target_ulong btgt = -1;
@@ -2434,7 +2435,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             gen_load_gpr(t1, rt);
             bcond_compute = 1;
         }
-        btgt = ctx->pc + 4 + offset;
+        btgt = ctx->pc + insn_bytes + offset;
         break;
     case OPC_BGEZ:
     case OPC_BGEZAL:
@@ -2453,12 +2454,12 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             gen_load_gpr(t0, rs);
             bcond_compute = 1;
         }
-        btgt = ctx->pc + 4 + offset;
+        btgt = ctx->pc + insn_bytes + offset;
         break;
     case OPC_J:
     case OPC_JAL:
         /* Jump to immediate */
-        btgt = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset;
+        btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
         break;
     case OPC_JR:
     case OPC_JALR:
@@ -7670,7 +7671,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
                 gen_muldiv(ctx, op1, rs, rt);
             break;
         case OPC_JR ... OPC_JALR:
-            gen_compute_branch(ctx, op1, rs, rd, sa);
+            gen_compute_branch(ctx, op1, 4, rs, rd, sa);
             return;
         case OPC_TGE ... OPC_TEQ: /* Traps */
         case OPC_TNE:
@@ -7959,7 +7960,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         switch (op1) {
         case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
         case OPC_BLTZAL ... OPC_BGEZALL:
-            gen_compute_branch(ctx, op1, rs, -1, imm << 2);
+            gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
             return;
         case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
         case OPC_TNEI:
@@ -8078,11 +8079,11 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
          break;
     case OPC_J ... OPC_JAL: /* Jump */
          offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
-         gen_compute_branch(ctx, op, rs, rt, offset);
+         gen_compute_branch(ctx, op, 4, rs, rt, offset);
          return;
     case OPC_BEQ ... OPC_BGTZ: /* Branch */
     case OPC_BEQL ... OPC_BGTZL:
-         gen_compute_branch(ctx, op, rs, rt, imm << 2);
+         gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
          return;
     case OPC_LB ... OPC_LWR: /* Load and stores */
     case OPC_SB ... OPC_SW:
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (4 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 05/11] target-mips: make gen_compute_branch 16/32-bit-aware Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-28 10:17   ` Aurelien Jarno
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 07/11] target-mips: split out delay slot handling Nathan Froyd
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel

This is a common pattern in existing code.  We'll also use it to
implement the mips16 SAVE/RESTORE instructions.

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

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 1157e97..fece3c1 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -997,6 +997,19 @@ OP_ST_ATOMIC(scd,st64,ld64,0x7);
 #endif
 #undef OP_ST_ATOMIC
 
+static void gen_base_offset_addr (DisasContext *ctx, TCGv addr,
+                                  int base, int16_t offset)
+{
+    if (base == 0) {
+        tcg_gen_movi_tl(addr, offset);
+    } else if (offset == 0) {
+        gen_load_gpr(addr, base);
+    } else {
+        tcg_gen_movi_tl(addr, offset);
+        gen_op_addr_add(ctx, addr, addr, cpu_gpr[base]);
+    }
+}
+
 /* Load and store */
 static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
                       int base, int16_t offset)
@@ -1005,14 +1018,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
     TCGv t0 = tcg_temp_new();
     TCGv t1 = tcg_temp_new();
 
-    if (base == 0) {
-        tcg_gen_movi_tl(t0, offset);
-    } else if (offset == 0) {
-        gen_load_gpr(t0, base);
-    } else {
-        tcg_gen_movi_tl(t0, offset);
-        gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
-    }
+    gen_base_offset_addr(ctx, t0, base, offset);
     /* Don't do NOP if destination is zero: we must perform the actual
        memory access. */
     switch (opc) {
@@ -1163,14 +1169,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
 
     t0 = tcg_temp_local_new();
 
-    if (base == 0) {
-        tcg_gen_movi_tl(t0, offset);
-    } else if (offset == 0) {
-        gen_load_gpr(t0, base);
-    } else {
-        tcg_gen_movi_tl(t0, offset);
-        gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
-    }
+    gen_base_offset_addr(ctx, t0, base, offset);
     /* Don't do NOP if destination is zero: we must perform the actual
        memory access. */
 
@@ -1202,14 +1201,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
     const char *opn = "flt_ldst";
     TCGv t0 = tcg_temp_new();
 
-    if (base == 0) {
-        tcg_gen_movi_tl(t0, offset);
-    } else if (offset == 0) {
-        gen_load_gpr(t0, base);
-    } else {
-        tcg_gen_movi_tl(t0, offset);
-        gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
-    }
+    gen_base_offset_addr(ctx, t0, base, offset);
     /* Don't do NOP if destination is zero: we must perform the actual
        memory access. */
     switch (opc) {
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 07/11] target-mips: split out delay slot handling
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (5 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 08/11] target-mips: add enums for MIPS16 opcodes Nathan Froyd
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel

Move delay slot handling to common code whose invocation can be
controlled from gen_intermediate_code_internal.

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

diff --git a/target-mips/translate.c b/target-mips/translate.c
index fece3c1..e7aee33 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -7548,6 +7548,56 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
                fregnames[fs], fregnames[ft]);
 }
 
+static void handle_delay_slot (CPUState *env, DisasContext *ctx,
+                               int insn_bytes)
+{
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+        int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
+        /* Branches completion */
+        ctx->hflags &= ~MIPS_HFLAG_BMASK;
+        ctx->bstate = BS_BRANCH;
+        save_cpu_state(ctx, 0);
+        /* FIXME: Need to clear can_do_io.  */
+        switch (hflags) {
+        case MIPS_HFLAG_B:
+            /* unconditional branch */
+            MIPS_DEBUG("unconditional branch");
+            gen_goto_tb(ctx, 0, ctx->btarget);
+            break;
+        case MIPS_HFLAG_BL:
+            /* blikely taken case */
+            MIPS_DEBUG("blikely branch taken");
+            gen_goto_tb(ctx, 0, ctx->btarget);
+            break;
+        case MIPS_HFLAG_BC:
+            /* Conditional branch */
+            MIPS_DEBUG("conditional branch");
+            {
+                int l1 = gen_new_label();
+
+                tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
+                gen_goto_tb(ctx, 1, ctx->pc + insn_bytes);
+                gen_set_label(l1);
+                gen_goto_tb(ctx, 0, ctx->btarget);
+            }
+            break;
+        case MIPS_HFLAG_BR:
+            /* unconditional branch to register */
+            MIPS_DEBUG("branch to register");
+            tcg_gen_mov_tl(cpu_PC, btarget);
+            if (ctx->singlestep_enabled) {
+                save_cpu_state(ctx, 0);
+                gen_helper_0i(raise_exception, EXCP_DEBUG);
+            }
+            tcg_gen_exit_tb(0);
+            break;
+        default:
+            MIPS_DEBUG("unknown branch");
+            break;
+        }
+    }
+}
+
 /* ISA extensions (ASEs) */
 /* MIPS16 extension to MIPS32 */
 /* SmartMIPS extension to MIPS32 */
@@ -7558,7 +7608,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
 
 #endif
 
-static void decode_opc (CPUState *env, DisasContext *ctx)
+static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
 {
     int32_t offset;
     int rs, rt, rd, sa;
@@ -7573,7 +7623,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
     }
 
     /* Handle blikely not taken case */
-    if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
+    if ((ctx->hflags & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BL) {
         int l1 = gen_new_label();
 
         MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
@@ -7664,7 +7714,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             break;
         case OPC_JR ... OPC_JALR:
             gen_compute_branch(ctx, op1, 4, rs, rd, sa);
-            return;
+            *is_branch = 1;
+            break;
         case OPC_TGE ... OPC_TEQ: /* Traps */
         case OPC_TNE:
             gen_trap(ctx, op1, rs, rt, -1);
@@ -7953,7 +8004,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
         case OPC_BLTZAL ... OPC_BGEZALL:
             gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
-            return;
+            *is_branch = 1;
+            break;
         case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
         case OPC_TNEI:
             gen_trap(ctx, op1, rs, -1, imm);
@@ -8072,11 +8124,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
     case OPC_J ... OPC_JAL: /* Jump */
          offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
          gen_compute_branch(ctx, op, 4, rs, rt, offset);
-         return;
+         *is_branch = 1;
+         break;
     case OPC_BEQ ... OPC_BGTZ: /* Branch */
     case OPC_BEQL ... OPC_BGTZL:
          gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
-         return;
+         *is_branch = 1;
+         break;
     case OPC_LB ... OPC_LWR: /* Load and stores */
     case OPC_SB ... OPC_SW:
     case OPC_SWR:
@@ -8137,7 +8191,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             case OPC_BC1:
                 gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
                                     (rt >> 2) & 0x7, imm << 2);
-                return;
+                *is_branch = 1;
+                break;
             case OPC_S_FMT:
             case OPC_D_FMT:
             case OPC_W_FMT:
@@ -8242,51 +8297,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         generate_exception(ctx, EXCP_RI);
         break;
     }
-    if (ctx->hflags & MIPS_HFLAG_BMASK) {
-        int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
-        /* Branches completion */
-        ctx->hflags &= ~MIPS_HFLAG_BMASK;
-        ctx->bstate = BS_BRANCH;
-        save_cpu_state(ctx, 0);
-        /* FIXME: Need to clear can_do_io.  */
-        switch (hflags) {
-        case MIPS_HFLAG_B:
-            /* unconditional branch */
-            MIPS_DEBUG("unconditional branch");
-            gen_goto_tb(ctx, 0, ctx->btarget);
-            break;
-        case MIPS_HFLAG_BL:
-            /* blikely taken case */
-            MIPS_DEBUG("blikely branch taken");
-            gen_goto_tb(ctx, 0, ctx->btarget);
-            break;
-        case MIPS_HFLAG_BC:
-            /* Conditional branch */
-            MIPS_DEBUG("conditional branch");
-            {
-                int l1 = gen_new_label();
-
-                tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
-                gen_goto_tb(ctx, 1, ctx->pc + 4);
-                gen_set_label(l1);
-                gen_goto_tb(ctx, 0, ctx->btarget);
-            }
-            break;
-        case MIPS_HFLAG_BR:
-            /* unconditional branch to register */
-            MIPS_DEBUG("branch to register");
-            tcg_gen_mov_tl(cpu_PC, btarget);
-            if (ctx->singlestep_enabled) {
-                save_cpu_state(ctx, 0);
-                gen_helper_0i(raise_exception, EXCP_DEBUG);
-            }
-            tcg_gen_exit_tb(0);
-            break;
-        default:
-            MIPS_DEBUG("unknown branch");
-            break;
-        }
-    }
 }
 
 static inline void
@@ -8300,6 +8310,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     int j, lj = -1;
     int num_insns;
     int max_insns;
+    int insn_bytes;
+    int is_branch;
 
     if (search_pc)
         qemu_log("search pc %d\n", search_pc);
@@ -8360,9 +8372,21 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
         }
         if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
             gen_io_start();
-        ctx.opcode = ldl_code(ctx.pc);
-        decode_opc(env, &ctx);
-        ctx.pc += 4;
+
+        is_branch = 0;
+        if (ctx.isa_mode == 0) {
+            ctx.opcode = ldl_code(ctx.pc);
+            insn_bytes = 4;
+            decode_opc(env, &ctx, &is_branch);
+        } else {
+            generate_exception(&ctx, EXCP_RI);
+            break;
+        }
+        if (!is_branch) {
+            handle_delay_slot(env, &ctx, insn_bytes);
+        }
+        ctx.pc += insn_bytes;
+
         num_insns++;
 
         /* Execute a branch and its delay slot as a single instruction.
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 08/11] target-mips: add enums for MIPS16 opcodes
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (6 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 07/11] target-mips: split out delay slot handling Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding Nathan Froyd
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel


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

diff --git a/target-mips/translate.c b/target-mips/translate.c
index e7aee33..611774b 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -7600,6 +7600,118 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
 
 /* ISA extensions (ASEs) */
 /* MIPS16 extension to MIPS32 */
+
+/* MIPS16 major opcodes */
+enum {
+  M16_OPC_ADDIUSP = 0x00,
+  M16_OPC_ADDIUPC = 0x01,
+  M16_OPC_B = 0x02,
+  M16_OPC_JAL = 0x03,
+  M16_OPC_BEQZ = 0x04,
+  M16_OPC_BNEQZ = 0x05,
+  M16_OPC_SHIFT = 0x06,
+  M16_OPC_LD = 0x07,
+  M16_OPC_RRIA = 0x08,
+  M16_OPC_ADDIU8 = 0x09,
+  M16_OPC_SLTI = 0x0a,
+  M16_OPC_SLTIU = 0x0b,
+  M16_OPC_I8 = 0x0c,
+  M16_OPC_LI = 0x0d,
+  M16_OPC_CMPI = 0x0e,
+  M16_OPC_SD = 0x0f,
+  M16_OPC_LB = 0x10,
+  M16_OPC_LH = 0x11,
+  M16_OPC_LWSP = 0x12,
+  M16_OPC_LW = 0x13,
+  M16_OPC_LBU = 0x14,
+  M16_OPC_LHU = 0x15,
+  M16_OPC_LWPC = 0x16,
+  M16_OPC_LWU = 0x17,
+  M16_OPC_SB = 0x18,
+  M16_OPC_SH = 0x19,
+  M16_OPC_SWSP = 0x1a,
+  M16_OPC_SW = 0x1b,
+  M16_OPC_RRR = 0x1c,
+  M16_OPC_RR = 0x1d,
+  M16_OPC_EXTEND = 0x1e,
+  M16_OPC_I64 = 0x1f
+};
+
+/* I8 funct field */
+enum {
+  I8_BTEQZ = 0x0,
+  I8_BTNEZ = 0x1,
+  I8_SWRASP = 0x2,
+  I8_ADJSP = 0x3,
+  I8_SVRS = 0x4,
+  I8_MOV32R = 0x5,
+  I8_MOVR32 = 0x7
+};
+
+/* RRR f field */
+enum {
+  RRR_DADDU = 0x0,
+  RRR_ADDU = 0x1,
+  RRR_DSUBU = 0x2,
+  RRR_SUBU = 0x3
+};
+
+/* RR funct field */
+enum {
+  RR_JR = 0x00,
+  RR_SDBBP = 0x01,
+  RR_SLT = 0x02,
+  RR_SLTU = 0x03,
+  RR_SLLV = 0x04,
+  RR_BREAK = 0x05,
+  RR_SRLV = 0x06,
+  RR_SRAV = 0x07,
+  RR_DSRL = 0x08,
+  RR_CMP = 0x0a,
+  RR_NEG = 0x0b,
+  RR_AND = 0x0c,
+  RR_OR = 0x0d,
+  RR_XOR = 0x0e,
+  RR_NOT = 0x0f,
+  RR_MFHI = 0x10,
+  RR_CNVT = 0x11,
+  RR_MFLO = 0x12,
+  RR_DSRA = 0x13,
+  RR_DSLLV = 0x14,
+  RR_DSRLV = 0x16,
+  RR_DSRAV = 0x17,
+  RR_MULT = 0x18,
+  RR_MULTU = 0x19,
+  RR_DIV = 0x1a,
+  RR_DIVU = 0x1b,
+  RR_DMULT = 0x1c,
+  RR_DMULTU = 0x1d,
+  RR_DDIV = 0x1e,
+  RR_DDIVU = 0x1f
+};
+
+/* I64 funct field */
+enum {
+  I64_LDSP = 0x0,
+  I64_SDSP = 0x1,
+  I64_SDRASP = 0x2,
+  I64_DADJSP = 0x3,
+  I64_LDPC = 0x4,
+  I64_DADDIU = 0x5,
+  I64_DADDIUPC = 0x6,
+  I64_DADDIUSP = 0x7
+};
+
+/* RR ry field for CNVT */
+enum {
+  RR_RY_CNVT_ZEB = 0x0,
+  RR_RY_CNVT_ZEH = 0x1,
+  RR_RY_CNVT_ZEW = 0x2,
+  RR_RY_CNVT_SEB = 0x4,
+  RR_RY_CNVT_SEH = 0x5,
+  RR_RY_CNVT_SEW = 0x6,
+};
+
 /* SmartMIPS extension to MIPS32 */
 
 #if defined(TARGET_MIPS64)
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (7 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 08/11] target-mips: add enums for MIPS16 opcodes Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-28 10:17   ` Aurelien Jarno
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 10/11] gdbstub: add MIPS16 support Nathan Froyd
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel

There's no good way to add this incrementally, so we do it all at once.
The only changes to shared code are in handle_delay_slot.  We need to
flip ISAMode when doing a jump-and-exchange.  We also need to set
ISAMode the low bit of the target address for jump-to-register.

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

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 611774b..49d2264 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -83,6 +83,7 @@ enum {
     OPC_LH       = (0x21 << 26),
     OPC_LWL      = (0x22 << 26),
     OPC_LW       = (0x23 << 26),
+    OPC_LWPC     = OPC_LW | 0x5,
     OPC_LBU      = (0x24 << 26),
     OPC_LHU      = (0x25 << 26),
     OPC_LWR      = (0x26 << 26),
@@ -173,6 +174,7 @@ enum {
     /* Jumps */
     OPC_JR       = 0x08 | OPC_SPECIAL, /* Also JR.HB */
     OPC_JALR     = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
+    OPC_JALRC    = OPC_JALR | (0x5 << 6),
     /* Traps */
     OPC_TGE      = 0x30 | OPC_SPECIAL,
     OPC_TGEU     = 0x31 | OPC_SPECIAL,
@@ -1074,6 +1076,19 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
         opn = "sdr";
         break;
 #endif
+    case OPC_LWPC:
+        save_cpu_state(ctx, 1);
+        if (ctx->hflags & MIPS_HFLAG_BMASK) {
+            int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4;
+
+            tcg_gen_movi_tl(t1, (ctx->pc - branch_bytes) & ~(target_ulong)3);
+        } else {
+            tcg_gen_movi_tl(t1, ctx->pc & ~(target_ulong)3);
+        }
+        gen_op_addr_add(ctx, t0, t0, t1);
+        op_ldst_lw(t0, t0, ctx);
+        gen_store_gpr(t0, rt);
+        break;
     case OPC_LW:
         save_cpu_state(ctx, 0);
         op_ldst_lw(t0, t0, ctx);
@@ -2450,11 +2465,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
         break;
     case OPC_J:
     case OPC_JAL:
+    case OPC_JALX:
         /* Jump to immediate */
         btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
         break;
     case OPC_JR:
     case OPC_JALR:
+    case OPC_JALRC:
         /* Jump to register */
         if (offset != 0 && offset != 16) {
             /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
@@ -2517,18 +2534,29 @@ 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_JALX:
+            ctx->hflags |= MIPS_HFLAG_BX;
+            /* Fallthrough */
         case OPC_JAL:
             blink = 31;
             ctx->hflags |= MIPS_HFLAG_B;
+            ctx->hflags |= (ctx->isa_mode
+                            ? MIPS_HFLAG_BDS16
+                            : MIPS_HFLAG_BDS32);
             MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
             break;
         case OPC_JR:
             ctx->hflags |= MIPS_HFLAG_BR;
+            if (ctx->isa_mode)
+                ctx->hflags |= MIPS_HFLAG_BDS16;
             MIPS_DEBUG("jr %s", regnames[rs]);
             break;
         case OPC_JALR:
+        case OPC_JALRC:
             blink = rt;
             ctx->hflags |= MIPS_HFLAG_BR;
+            if (ctx->isa_mode)
+                ctx->hflags |= MIPS_HFLAG_BDS16;
             MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
             break;
         default:
@@ -2625,7 +2653,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
 
     ctx->btarget = btgt;
     if (blink > 0) {
-        tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + 8);
+        int post_delay = insn_bytes;
+        int lowbit = ctx->isa_mode;
+
+        if (opc != OPC_JALRC)
+            post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4);
+
+        tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit);
     }
 
  out:
@@ -7558,10 +7592,17 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
         ctx->bstate = BS_BRANCH;
         save_cpu_state(ctx, 0);
         /* FIXME: Need to clear can_do_io.  */
-        switch (hflags) {
+        switch (hflags & MIPS_HFLAG_BMASK_BASE) {
         case MIPS_HFLAG_B:
             /* unconditional branch */
             MIPS_DEBUG("unconditional branch");
+            if (hflags & MIPS_HFLAG_BX) {
+                TCGv_i32 t0 = tcg_temp_new_i32();
+
+                tcg_gen_movi_i32(t0, 1 - ctx->isa_mode);
+                tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, active_tc.ISAMode));
+                tcg_temp_free_i32(t0);
+            }
             gen_goto_tb(ctx, 0, ctx->btarget);
             break;
         case MIPS_HFLAG_BL:
@@ -7584,7 +7625,20 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
         case MIPS_HFLAG_BR:
             /* unconditional branch to register */
             MIPS_DEBUG("branch to register");
-            tcg_gen_mov_tl(cpu_PC, btarget);
+            if (env->insn_flags & ASE_MIPS16) {
+                TCGv t0 = tcg_temp_new();
+                TCGv_i32 t1 = tcg_temp_new_i32();
+
+                tcg_gen_andi_tl(t0, btarget, 0x1);
+                tcg_gen_trunc_tl_i32(t1, t0);
+                tcg_temp_free(t0);
+                tcg_gen_st_i32(t1, cpu_env, offsetof(CPUState, active_tc.ISAMode));
+                tcg_temp_free_i32(t1);
+
+                tcg_gen_andi_tl(cpu_PC, btarget, ~(target_ulong)0x1);
+            } else {
+                tcg_gen_mov_tl(cpu_PC, btarget);
+            }
             if (ctx->singlestep_enabled) {
                 save_cpu_state(ctx, 0);
                 gen_helper_0i(raise_exception, EXCP_DEBUG);
@@ -7712,6 +7766,918 @@ enum {
   RR_RY_CNVT_SEW = 0x6,
 };
 
+static int xlat (int r)
+{
+  static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
+
+  return map[r];
+}
+
+static void gen_mips16_save (DisasContext *ctx,
+                             int xsregs, int aregs,
+                             int do_ra, int do_s0, int do_s1,
+                             int framesize)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    int args, astatic;
+
+    switch (aregs) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 11:
+        args = 0;
+        break;
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+        args = 1;
+        break;
+    case 8:
+    case 9:
+    case 10:
+        args = 2;
+        break;
+    case 12:
+    case 13:
+        args = 3;
+        break;
+    case 14:
+        args = 4;
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    switch (args) {
+    case 4:
+        gen_base_offset_addr(ctx, t0, 29, 12);
+        gen_load_gpr(t1, 7);
+        op_ldst_sw(t1, t0, ctx);
+        /* Fall through */
+    case 3:
+        gen_base_offset_addr(ctx, t0, 29, 8);
+        gen_load_gpr(t1, 6);
+        op_ldst_sw(t1, t0, ctx);
+        /* Fall through */
+    case 2:
+        gen_base_offset_addr(ctx, t0, 29, 4);
+        gen_load_gpr(t1, 5);
+        op_ldst_sw(t1, t0, ctx);
+        /* Fall through */
+    case 1:
+        gen_base_offset_addr(ctx, t0, 29, 0);
+        gen_load_gpr(t1, 4);
+        op_ldst_sw(t1, t0, ctx);
+    }
+
+    gen_load_gpr(t0, 29);
+
+#define DECR_AND_STORE(reg) do {                \
+        tcg_gen_subi_tl(t0, t0, 4);             \
+        gen_load_gpr(t1, reg);                  \
+        op_ldst_sw(t1, t0, ctx);                \
+    } while (0)
+
+    if (do_ra) {
+        DECR_AND_STORE(31);
+    }
+
+    switch (xsregs) {
+    case 7:
+        DECR_AND_STORE(30);
+        /* Fall through */
+    case 6:
+        DECR_AND_STORE(23);
+        /* Fall through */
+    case 5:
+        DECR_AND_STORE(22);
+        /* Fall through */
+    case 4:
+        DECR_AND_STORE(21);
+        /* Fall through */
+    case 3:
+        DECR_AND_STORE(20);
+        /* Fall through */
+    case 2:
+        DECR_AND_STORE(19);
+        /* Fall through */
+    case 1:
+        DECR_AND_STORE(18);
+    }
+
+    if (do_s1) {
+        DECR_AND_STORE(17);
+    }
+    if (do_s0) {
+        DECR_AND_STORE(16);
+    }
+
+    switch (aregs) {
+    case 0:
+    case 4:
+    case 8:
+    case 12:
+    case 14:
+        astatic = 0;
+        break;
+    case 1:
+    case 5:
+    case 9:
+    case 13:
+        astatic = 1;
+        break;
+    case 2:
+    case 6:
+    case 10:
+        astatic = 2;
+        break;
+    case 3:
+    case 7:
+        astatic = 3;
+        break;
+    case 11:
+        astatic = 4;
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    if (astatic > 0) {
+        DECR_AND_STORE(7);
+        if (astatic > 1) {
+            DECR_AND_STORE(6);
+            if (astatic > 2) {
+                DECR_AND_STORE(5);
+                if (astatic > 3) {
+                    DECR_AND_STORE(4);
+                }
+            }
+        }
+    }
+#undef DECR_AND_STORE
+
+    tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_mips16_restore (DisasContext *ctx,
+                                int xsregs, int aregs,
+                                int do_ra, int do_s0, int do_s1,
+                                int framesize)
+{
+    int astatic;
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    tcg_gen_addi_tl(t0, cpu_gpr[29], framesize);
+
+#define DECR_AND_LOAD(reg) do {                 \
+        tcg_gen_subi_tl(t0, t0, 4);             \
+        op_ldst_lw(t1, t0, ctx);                \
+        gen_store_gpr(t1, reg);                 \
+    } while (0)
+
+    if (do_ra) {
+        DECR_AND_LOAD(31);
+    }
+
+    switch (xsregs) {
+    case 7:
+        DECR_AND_LOAD(30);
+        /* Fall through */
+    case 6:
+        DECR_AND_LOAD(23);
+        /* Fall through */
+    case 5:
+        DECR_AND_LOAD(22);
+        /* Fall through */
+    case 4:
+        DECR_AND_LOAD(21);
+        /* Fall through */
+    case 3:
+        DECR_AND_LOAD(20);
+        /* Fall through */
+    case 2:
+        DECR_AND_LOAD(19);
+        /* Fall through */
+    case 1:
+        DECR_AND_LOAD(18);
+    }
+
+    if (do_s1) {
+        DECR_AND_LOAD(17);
+    }
+    if (do_s0) {
+        DECR_AND_LOAD(16);
+    }
+
+    switch (aregs) {
+    case 0:
+    case 4:
+    case 8:
+    case 12:
+    case 14:
+        astatic = 0;
+        break;
+    case 1:
+    case 5:
+    case 9:
+    case 13:
+        astatic = 1;
+        break;
+    case 2:
+    case 6:
+    case 10:
+        astatic = 2;
+        break;
+    case 3:
+    case 7:
+        astatic = 3;
+        break;
+    case 11:
+        astatic = 4;
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    if (astatic > 0) {
+        DECR_AND_LOAD(7);
+        if (astatic > 1) {
+            DECR_AND_LOAD(6);
+            if (astatic > 2) {
+                DECR_AND_LOAD(5);
+                if (astatic > 3) {
+                    DECR_AND_LOAD(4);
+                }
+            }
+        }
+    }
+#undef DECR_AND_LOAD
+
+    tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_addiupc (DisasContext *ctx, int rx, int imm)
+{
+    TCGv t0 = tcg_temp_new();
+
+    tcg_gen_movi_tl(t0, ctx->pc & ~(target_ulong)3);
+    tcg_gen_addi_tl(cpu_gpr[rx], t0, imm);
+
+    tcg_temp_free(t0);
+}
+
+static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx,
+                                       int *is_branch)
+{
+    int extend = lduw_code(ctx->pc + 2);
+    int op, rx, ry, funct, sa;
+    int16_t imm, offset;
+
+    ctx->opcode = (ctx->opcode << 16) | extend;
+    op = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 22) & 0x1f;
+    funct = (ctx->opcode >> 8) & 0x7;
+    rx = xlat((ctx->opcode >> 8) & 0x7);
+    ry = xlat((ctx->opcode >> 5) & 0x7);
+    offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11
+                              | ((ctx->opcode >> 21) & 0x3f) << 5
+                              | (ctx->opcode & 0x1f));
+
+    /* The extended opcodes cleverly reuse the opcodes from their 16-bit
+       counterparts.  */
+    switch (op) {
+    case M16_OPC_ADDIUSP:
+        gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
+        break;
+    case M16_OPC_ADDIUPC:
+        gen_addiupc(ctx, rx, imm);
+        break;
+    case M16_OPC_B:
+        gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_BEQZ:
+        gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_BNEQZ:
+        gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_SHIFT:
+        switch (ctx->opcode & 0x3) {
+        case 0x0:
+            gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
+            break;
+        case 0x1:
+#if defined(TARGET_MIPS64)
+            gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
+#else
+            generate_exception(ctx, EXCP_RI);
+#endif
+            break;
+        case 0x2:
+            gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
+            break;
+        case 0x3:
+            gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
+            break;
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_LD:
+        gen_ldst(ctx, OPC_LD, ry, rx, offset);
+        break;
+#endif
+    case M16_OPC_RRIA:
+        imm = ctx->opcode & 0xf;
+        imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4;
+        imm = imm | ((ctx->opcode >> 16) & 0xf) << 11;
+        imm = (int16_t) (imm << 1) >> 1;
+        if ((ctx->opcode >> 4) & 0x1) {
+#if defined(TARGET_MIPS64)
+            gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
+#else
+            generate_exception(ctx, EXCP_RI);
+#endif
+        } else {
+            gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
+        }
+        break;
+    case M16_OPC_ADDIU8:
+        gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
+        break;
+    case M16_OPC_SLTI:
+        gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
+        break;
+    case M16_OPC_SLTIU:
+        gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
+        break;
+    case M16_OPC_I8:
+        switch (funct) {
+        case I8_BTEQZ:
+            gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1);
+            break;
+        case I8_BTNEZ:
+            gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1);
+            break;
+        case I8_SWRASP:
+            gen_ldst(ctx, OPC_SW, 31, 29, imm);
+            break;
+        case I8_ADJSP:
+            gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm);
+            break;
+        case I8_SVRS:
+            {
+                int xsregs = (ctx->opcode >> 24) & 0x7;
+                int aregs = (ctx->opcode >> 16) & 0xf;
+                int do_ra = (ctx->opcode >> 6) & 0x1;
+                int do_s0 = (ctx->opcode >> 5) & 0x1;
+                int do_s1 = (ctx->opcode >> 4) & 0x1;
+                int framesize = (((ctx->opcode >> 20) & 0xf) << 4
+                                 | (ctx->opcode & 0xf)) << 3;
+
+                if (ctx->opcode & (1 << 7)) {
+                    gen_mips16_save(ctx, xsregs, aregs,
+                                    do_ra, do_s0, do_s1,
+                                    framesize);
+                } else {
+                    gen_mips16_restore(ctx, xsregs, aregs,
+                                       do_ra, do_s0, do_s1,
+                                       framesize);
+                }
+            }
+            break;
+        default:
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case M16_OPC_LI:
+        tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm);
+        break;
+    case M16_OPC_CMPI:
+        tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm);
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_SD:
+        gen_ldst(ctx, OPC_SD, ry, rx, offset);
+        break;
+#endif
+    case M16_OPC_LB:
+        gen_ldst(ctx, OPC_LB, ry, rx, offset);
+        break;
+    case M16_OPC_LH:
+        gen_ldst(ctx, OPC_LH, ry, rx, offset);
+        break;
+    case M16_OPC_LWSP:
+        gen_ldst(ctx, OPC_LW, rx, 29, offset);
+        break;
+    case M16_OPC_LW:
+        gen_ldst(ctx, OPC_LW, ry, rx, offset);
+        break;
+    case M16_OPC_LBU:
+        gen_ldst(ctx, OPC_LBU, ry, rx, offset);
+        break;
+    case M16_OPC_LHU:
+        gen_ldst(ctx, OPC_LHU, ry, rx, offset);
+        break;
+    case M16_OPC_LWPC:
+        gen_ldst(ctx, OPC_LWPC, rx, 0, offset);
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_LWU:
+        gen_ldst(ctx, OPC_LWU, ry, rx, offset);
+        break;
+#endif
+    case M16_OPC_SB:
+        gen_ldst(ctx, OPC_SB, ry, rx, offset);
+        break;
+    case M16_OPC_SH:
+        gen_ldst(ctx, OPC_SH, ry, rx, offset);
+        break;
+    case M16_OPC_SWSP:
+        gen_ldst(ctx, OPC_SW, rx, 29, offset);
+        break;
+    case M16_OPC_SW:
+        gen_ldst(ctx, OPC_SW, ry, rx, offset);
+        break;
+    default:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+
+    return 4;
+}
+
+static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
+                              int *is_branch)
+{
+    int rx, ry;
+    int sa;
+    int op, cnvt_op, op1, offset;
+    int funct;
+    int n_bytes;
+
+    op = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 2) & 0x7;
+    sa = sa == 0 ? 8 : sa;
+    rx = xlat((ctx->opcode >> 8) & 0x7);
+    cnvt_op = (ctx->opcode >> 5) & 0x7;
+    ry = xlat((ctx->opcode >> 5) & 0x7);
+    op1 = offset = ctx->opcode & 0x1f;
+
+    n_bytes = 2;
+
+    switch (op) {
+    case M16_OPC_ADDIUSP:
+        {
+            int16_t imm = ((uint8_t) ctx->opcode) << 2;
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
+        }
+        break;
+    case M16_OPC_ADDIUPC:
+        gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2);
+        break;
+    case M16_OPC_B:
+        offset = (ctx->opcode & 0x7ff) << 1;
+        offset = (int16_t)(offset << 4) >> 4;
+        gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_JAL:
+        offset = lduw_code(ctx->pc + 2);
+        offset = (((ctx->opcode & 0x1f) << 21)
+                  | ((ctx->opcode >> 5) & 0x1f) << 16
+                  | offset) << 2;
+        op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL;
+        gen_compute_branch(ctx, op, 4, rx, ry, offset);
+        n_bytes = 4;
+        *is_branch = 1;
+        break;
+    case M16_OPC_BEQZ:
+        gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_BNEQZ:
+        gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
+        /* No delay slot, so just process as a normal instruction */
+        break;
+    case M16_OPC_SHIFT:
+        switch (ctx->opcode & 0x3) {
+        case 0x0:
+            gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
+            break;
+        case 0x1:
+#if defined(TARGET_MIPS64)
+            gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
+#else
+            generate_exception(ctx, EXCP_RI);
+#endif
+            break;
+        case 0x2:
+            gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
+            break;
+        case 0x3:
+            gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
+            break;
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_LD:
+        gen_ldst(ctx, OPC_LD, ry, rx, offset << 3);
+        break;
+#endif
+    case M16_OPC_RRIA:
+        {
+            int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4;
+
+            if ((ctx->opcode >> 4) & 1) {
+#if defined(TARGET_MIPS64)
+                gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
+#else
+                generate_exception(ctx, EXCP_RI);
+#endif
+            } else {
+                gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
+            }
+        }
+        break;
+    case M16_OPC_ADDIU8:
+        {
+            int16_t imm = (int8_t) ctx->opcode;
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
+        }
+        break;
+    case M16_OPC_SLTI:
+        {
+            int16_t imm = (uint8_t) ctx->opcode;
+
+            gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
+        }
+        break;
+    case M16_OPC_SLTIU:
+        {
+            int16_t imm = (uint8_t) ctx->opcode;
+
+            gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
+        }
+        break;
+    case M16_OPC_I8:
+        {
+            int reg32;
+
+            funct = (ctx->opcode >> 8) & 0x7;
+            switch (funct) {
+            case I8_BTEQZ:
+                gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0,
+                                   ((int8_t)ctx->opcode) << 1);
+                break;
+            case I8_BTNEZ:
+                gen_compute_branch(ctx, OPC_BNE, 2, 24, 0,
+                                   ((int8_t)ctx->opcode) << 1);
+                break;
+            case I8_SWRASP:
+                gen_ldst(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
+                break;
+            case I8_ADJSP:
+                gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29,
+                              ((int8_t)ctx->opcode) << 3);
+                break;
+            case I8_SVRS:
+                {
+                    int do_ra = ctx->opcode & (1 << 6);
+                    int do_s0 = ctx->opcode & (1 << 5);
+                    int do_s1 = ctx->opcode & (1 << 4);
+                    int framesize = ctx->opcode & 0xf;
+
+                    if (framesize == 0) {
+                        framesize = 128;
+                    } else {
+                        framesize = framesize << 3;
+                    }
+
+                    if (ctx->opcode & (1 << 7)) {
+                        gen_mips16_save(ctx, 0, 0,
+                                        do_ra, do_s0, do_s1, framesize);
+                    } else {
+                        gen_mips16_restore(ctx, 0, 0,
+                                           do_ra, do_s0, do_s1, framesize);
+                    }
+                }
+                break;
+            case I8_MOV32R:
+                {
+                    int rz = xlat(ctx->opcode & 0x7);
+
+                    reg32 = (((ctx->opcode >> 3) & 0x3) << 3) |
+                        ((ctx->opcode >> 5) & 0x7);
+                    gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0);
+                }
+                break;
+            case I8_MOVR32:
+                reg32 = ctx->opcode & 0x1f;
+                gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0);
+                break;
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+        }
+        break;
+    case M16_OPC_LI:
+        {
+            int16_t imm = (uint8_t) ctx->opcode;
+
+            gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm);
+        }
+        break;
+    case M16_OPC_CMPI:
+        {
+            int16_t imm = (uint8_t) ctx->opcode;
+
+            gen_logic_imm(env, OPC_XORI, 24, rx, imm);
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_SD:
+        gen_ldst(ctx, OPC_SD, ry, rx, offset << 3);
+        break;
+#endif
+    case M16_OPC_LB:
+        gen_ldst(ctx, OPC_LB, ry, rx, offset);
+        break;
+    case M16_OPC_LH:
+        gen_ldst(ctx, OPC_LH, ry, rx, offset << 1);
+        break;
+    case M16_OPC_LWSP:
+        gen_ldst(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2);
+        break;
+    case M16_OPC_LW:
+        gen_ldst(ctx, OPC_LW, ry, rx, offset << 2);
+        break;
+    case M16_OPC_LBU:
+        gen_ldst(ctx, OPC_LBU, ry, rx, offset);
+        break;
+    case M16_OPC_LHU:
+        gen_ldst(ctx, OPC_LHU, ry, rx, offset << 1);
+        break;
+    case M16_OPC_LWPC:
+        gen_ldst(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2);
+        break;
+#if defined (TARGET_MIPS64)
+    case M16_OPC_LWU:
+        gen_ldst(ctx, OPC_LWU, ry, rx, offset << 2);
+        break;
+#endif
+    case M16_OPC_SB:
+        gen_ldst(ctx, OPC_SB, ry, rx, offset);
+        break;
+    case M16_OPC_SH:
+        gen_ldst(ctx, OPC_SH, ry, rx, offset << 1);
+        break;
+    case M16_OPC_SWSP:
+        gen_ldst(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2);
+        break;
+    case M16_OPC_SW:
+        gen_ldst(ctx, OPC_SW, ry, rx, offset << 2);
+        break;
+    case M16_OPC_RRR:
+        {
+            int rz = xlat((ctx->opcode >> 2) & 0x7);
+            int mips32_op;
+
+            switch (ctx->opcode & 0x3) {
+            case RRR_ADDU:
+                mips32_op = OPC_ADDU;
+                break;
+            case RRR_SUBU:
+                mips32_op = OPC_SUBU;
+                break;
+#if defined(TARGET_MIPS64)
+            case RRR_DADDU:
+                mips32_op = OPC_DADDU;
+                break;
+            case RRR_DSUBU:
+                mips32_op = OPC_DSUBU;
+                break;
+#endif
+            default:
+                generate_exception(ctx, EXCP_RI);
+                goto done;
+            }
+
+            gen_arith(env, ctx, mips32_op, rz, rx, ry);
+        done:
+            ;
+        }
+        break;
+    case M16_OPC_RR:
+        switch (op1) {
+        case RR_JR:
+            {
+                int nd = (ctx->opcode >> 7) & 0x1;
+                int link = (ctx->opcode >> 6) & 0x1;
+                int ra = (ctx->opcode >> 5) & 0x1;
+
+                if (link) {
+                    op = nd ? OPC_JALRC : OPC_JALR;
+                } else {
+                    op = OPC_JR;
+                }
+
+                gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0);
+                if (!nd) {
+                    *is_branch = 1;
+                }
+            }
+            break;
+        case RR_SDBBP:
+            /* 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 RR_SLT:
+            gen_slt(env, OPC_SLT, 24, rx, ry);
+            break;
+        case RR_SLTU:
+            gen_slt(env, OPC_SLTU, 24, rx, ry);
+            break;
+        case RR_BREAK:
+            generate_exception(ctx, EXCP_BREAK);
+            break;
+        case RR_SLLV:
+            gen_shift(env, ctx, OPC_SLLV, ry, rx, ry);
+            break;
+        case RR_SRLV:
+            gen_shift(env, ctx, OPC_SRLV, ry, rx, ry);
+            break;
+        case RR_SRAV:
+            gen_shift(env, ctx, OPC_SRAV, ry, rx, ry);
+            break;
+#if defined (TARGET_MIPS64)
+        case RR_DSRL:
+            gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa);
+            break;
+#endif
+        case RR_CMP:
+            gen_logic(env, OPC_XOR, 24, rx, ry);
+            break;
+        case RR_NEG:
+            gen_arith(env, ctx, OPC_SUBU, rx, 0, ry);
+            break;
+        case RR_AND:
+            gen_logic(env, OPC_AND, rx, rx, ry);
+            break;
+        case RR_OR:
+            gen_logic(env, OPC_OR, rx, rx, ry);
+            break;
+        case RR_XOR:
+            gen_logic(env, OPC_XOR, rx, rx, ry);
+            break;
+        case RR_NOT:
+            gen_logic(env, OPC_NOR, rx, ry, 0);
+            break;
+        case RR_MFHI:
+            gen_HILO(ctx, OPC_MFHI, rx);
+            break;
+        case RR_CNVT:
+            switch (cnvt_op) {
+            case RR_RY_CNVT_ZEB:
+                tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+            case RR_RY_CNVT_ZEH:
+                tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+            case RR_RY_CNVT_SEB:
+                tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+            case RR_RY_CNVT_SEH:
+                tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+#if defined (TARGET_MIPS64)
+            case RR_RY_CNVT_ZEW:
+                tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+            case RR_RY_CNVT_SEW:
+                tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+                break;
+#endif
+            default:
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            break;
+        case RR_MFLO:
+            gen_HILO(ctx, OPC_MFLO, rx);
+            break;
+#if defined (TARGET_MIPS64)
+        case RR_DSRA:
+            gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa);
+            break;
+        case RR_DSLLV:
+            gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry);
+        case RR_DSRLV:
+            gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry);
+            break;
+        case RR_DSRAV:
+            gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry);
+            break;
+#endif
+        case RR_MULT:
+            gen_muldiv(ctx, OPC_MULT, rx, ry);
+            break;
+        case RR_MULTU:
+            gen_muldiv(ctx, OPC_MULTU, rx, ry);
+            break;
+        case RR_DIV:
+            gen_muldiv(ctx, OPC_DIV, rx, ry);
+            break;
+        case RR_DIVU:
+            gen_muldiv(ctx, OPC_DIVU, rx, ry);
+            break;
+#if defined (TARGET_MIPS64)
+        case RR_DMULT:
+            gen_muldiv(ctx, OPC_DMULT, rx, ry);
+            break;
+        case RR_DMULTU:
+            gen_muldiv(ctx, OPC_DMULTU, rx, ry);
+            break;
+        case RR_DDIV:
+            gen_muldiv(ctx, OPC_DDIV, rx, ry);
+            break;
+        case RR_DDIVU:
+            gen_muldiv(ctx, OPC_DDIVU, rx, ry);
+            break;
+#endif
+        default:
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case M16_OPC_EXTEND:
+        decode_extended_mips16_opc(env, ctx, is_branch);
+        n_bytes = 4;
+        break;
+#if defined(TARGET_MIPS64)
+    case M16_OPC_I64:
+        funct = (ctx->opcode >> 8) & 0x7;
+        switch (funct) {
+        case I64_LDSP:
+            gen_ldst(ctx, OPC_LD, ry, 29, offset << 3);
+            break;
+        case I64_SDSP:
+            gen_ldst(ctx, OPC_SD, ry, 29, offset << 3);
+            break;
+        case I64_SDRASP:
+            gen_ldst(ctx, OPC_SD, 31, 29, (ctx->opcode & 0xff) << 3);
+            break;
+        case I64_DADJSP:
+            gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29,
+                          ((int8_t)ctx->opcode) << 3);
+            break;
+        case I64_LDPC:
+            break;
+        case I64_DADDIU:
+            gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry,
+                          ((int8_t)(offset << 3)) >> 3);
+            break;
+        case I64_DADDIUPC:
+            break;
+        case I64_DADDIUSP:
+            gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29,
+                          ((int8_t)(offset << 3)) >> 1);
+            break;
+        }
+#endif
+    default:
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+
+    return n_bytes;
+}
+
 /* SmartMIPS extension to MIPS32 */
 
 #if defined(TARGET_MIPS64)
@@ -8400,7 +9366,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
 #endif
     case OPC_JALX:
         check_insn(env, ctx, ASE_MIPS16);
-        /* MIPS16: Not implemented. */
+        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+        gen_compute_branch(ctx, op, 4, rs, rt, offset);
+        *is_branch = 1;
+        break;
     case OPC_MDMX:
         check_insn(env, ctx, ASE_MDMX);
         /* MDMX: Not implemented. */
@@ -8490,6 +9459,9 @@ 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_MIPS16) {
+            ctx.opcode = lduw_code(ctx.pc);
+            insn_bytes = decode_mips16_opc(env, &ctx, &is_branch);
         } else {
             generate_exception(&ctx, EXCP_RI);
             break;
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 10/11] gdbstub: add MIPS16 support
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (8 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 11/11] target-mips: add copyright notice for mips16 work Nathan Froyd
  2009-11-28 10:17 ` [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Aurelien Jarno
  11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel

The only thing to do here is to expose ISAMode to GDB and to set ISAMode
properly when we change the PC.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 gdbstub.c |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 055093f..58a701b 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1053,7 +1053,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
     case 34: GET_REGL(env->active_tc.HI[0]);
     case 35: GET_REGL(env->CP0_BadVAddr);
     case 36: GET_REGL((int32_t)env->CP0_Cause);
-    case 37: GET_REGL(env->active_tc.PC);
+    case 37: GET_REGL(env->active_tc.PC | env->active_tc.ISAMode);
     case 72: GET_REGL(0); /* fp */
     case 89: GET_REGL((int32_t)env->CP0_PRid);
     }
@@ -1114,7 +1114,10 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
     case 34: env->active_tc.HI[0] = tmp; break;
     case 35: env->CP0_BadVAddr = tmp; break;
     case 36: env->CP0_Cause = tmp; break;
-    case 37: env->active_tc.PC = tmp; break;
+    case 37:
+        env->active_tc.PC = tmp & ~(target_ulong)1;
+        env->active_tc.ISAMode = tmp & 1;
+        break;
     case 72: /* fp, ignored */ break;
     default: 
 	if (n > 89)
@@ -1609,7 +1612,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 #elif defined (TARGET_SH4)
     s->c_cpu->pc = pc;
 #elif defined (TARGET_MIPS)
-    s->c_cpu->active_tc.PC = pc;
+    s->c_cpu->active_tc.PC = pc & ~(target_ulong)1;
+    s->c_cpu->active_tc.ISAMode = pc & 1;
 #elif defined (TARGET_MICROBLAZE)
     s->c_cpu->sregs[SR_PC] = pc;
 #elif defined (TARGET_CRIS)
-- 
1.6.3.2

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

* [Qemu-devel] [PATCH 11/11] target-mips: add copyright notice for mips16 work
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (9 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 10/11] gdbstub: add MIPS16 support Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
  2009-11-28 10:17 ` [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Aurelien Jarno
  11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
  To: qemu-devel


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

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 49d2264..ef5e726 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -4,6 +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)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
-- 
1.6.3.2

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

* Re: [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware Nathan Froyd
@ 2009-11-28 10:17   ` Aurelien Jarno
  0 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Mon, Nov 23, 2009 at 12:50:01PM -0800, Nathan Froyd wrote:
> 
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
>  target-mips/helper.c    |   47 ++++++++++++++++++++++++++---------------------
>  target-mips/op_helper.c |   10 +++++++---
>  2 files changed, 33 insertions(+), 24 deletions(-)
> 
> diff --git a/target-mips/helper.c b/target-mips/helper.c
> index 4a37277..e54a31a 100644
> --- a/target-mips/helper.c
> +++ b/target-mips/helper.c
> @@ -339,6 +339,20 @@ static const char * const excp_names[EXCP_LAST + 1] = {
>      [EXCP_CACHE] = "cache error",
>  };
>  
> +static target_ulong exception_resume_pc (CPUState *env)
> +{
> +    target_ulong bad_pc;
> +
> +    bad_pc = env->active_tc.PC | env->active_tc.ISAMode;
> +    if (env->hflags & MIPS_HFLAG_BMASK) {
> +        /* If the exception was raised from a delay slot, come back to
> +           the jump.  */
> +        bad_pc -= (env->hflags & MIPS_HFLAG_BDS16 ? 2 : 4);
> +    }
> +
> +    return bad_pc;
> +}

This function is only used on softmmu target. This breaks compilation of
linux-user targets, it should be protected with:
  #if !defined(CONFIG_USER_ONLY)
  #endif

>  void do_interrupt (CPUState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> @@ -366,7 +380,7 @@ void do_interrupt (CPUState *env)
>             resume will always occur on the next instruction
>             (but we assume the pc has always been updated during
>             code translation). */
> -        env->CP0_DEPC = env->active_tc.PC;
> +        env->CP0_DEPC = env->active_tc.PC | env->active_tc.ISAMode;
>          goto enter_debug_mode;
>      case EXCP_DINT:
>          env->CP0_Debug |= 1 << CP0DB_DINT;
> @@ -383,14 +397,8 @@ void do_interrupt (CPUState *env)
>      case EXCP_DDBL:
>          env->CP0_Debug |= 1 << CP0DB_DDBL;
>      set_DEPC:
> -        if (env->hflags & MIPS_HFLAG_BMASK) {
> -            /* If the exception was raised from a delay slot,
> -               come back to the jump.  */
> -            env->CP0_DEPC = env->active_tc.PC - 4;
> -            env->hflags &= ~MIPS_HFLAG_BMASK;
> -        } else {
> -            env->CP0_DEPC = env->active_tc.PC;
> -        }
> +        env->CP0_DEPC = exception_resume_pc(env);
> +        env->hflags &= ~MIPS_HFLAG_BMASK;
>   enter_debug_mode:
>          env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
>          env->hflags &= ~(MIPS_HFLAG_KSU);
> @@ -398,6 +406,8 @@ 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->active_tc.ISAMode = 0;
>          break;
>      case EXCP_RESET:
>          cpu_reset(env);
> @@ -409,20 +419,16 @@ void do_interrupt (CPUState *env)
>      case EXCP_NMI:
>          env->CP0_Status |= (1 << CP0St_NMI);
>   set_error_EPC:
> -        if (env->hflags & MIPS_HFLAG_BMASK) {
> -            /* If the exception was raised from a delay slot,
> -               come back to the jump.  */
> -            env->CP0_ErrorEPC = env->active_tc.PC - 4;
> -            env->hflags &= ~MIPS_HFLAG_BMASK;
> -        } else {
> -            env->CP0_ErrorEPC = env->active_tc.PC;
> -        }
> +        env->CP0_ErrorEPC = exception_resume_pc(env);
> +        env->hflags &= ~MIPS_HFLAG_BMASK;
>          env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
>          env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
>          env->hflags &= ~(MIPS_HFLAG_KSU);
>          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->active_tc.ISAMode = 0;
>          break;
>      case EXCP_EXT_INTERRUPT:
>          cause = 0;
> @@ -524,13 +530,10 @@ void do_interrupt (CPUState *env)
>          }
>   set_EPC:
>          if (!(env->CP0_Status & (1 << CP0St_EXL))) {
> +            env->CP0_EPC = exception_resume_pc(env);
>              if (env->hflags & MIPS_HFLAG_BMASK) {
> -                /* If the exception was raised from a delay slot,
> -                   come back to the jump.  */
> -                env->CP0_EPC = env->active_tc.PC - 4;
>                  env->CP0_Cause |= (1 << CP0Ca_BD);
>              } else {
> -                env->CP0_EPC = env->active_tc.PC;
>                  env->CP0_Cause &= ~(1 << CP0Ca_BD);
>              }
>              env->CP0_Status |= (1 << CP0St_EXL);
> @@ -544,6 +547,8 @@ 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->active_tc.ISAMode = 0;
>          env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
>          break;
>      default:
> diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
> index 52d687d..d585d65 100644
> --- a/target-mips/op_helper.c
> +++ b/target-mips/op_helper.c
> @@ -1701,10 +1701,12 @@ void helper_eret (void)
>  {
>      debug_pre_eret();
>      if (env->CP0_Status & (1 << CP0St_ERL)) {
> -        env->active_tc.PC = env->CP0_ErrorEPC;
> +        env->active_tc.PC = env->CP0_ErrorEPC & ~(target_ulong)1;
> +        env->active_tc.ISAMode = env->CP0_ErrorEPC & 1;
>          env->CP0_Status &= ~(1 << CP0St_ERL);
>      } else {
> -        env->active_tc.PC = env->CP0_EPC;
> +        env->active_tc.PC = env->CP0_EPC & ~(target_ulong)1;
> +        env->active_tc.ISAMode = env->CP0_EPC & 1;
>          env->CP0_Status &= ~(1 << CP0St_EXL);
>      }
>      compute_hflags(env);
> @@ -1715,7 +1717,9 @@ void helper_eret (void)
>  void helper_deret (void)
>  {
>      debug_pre_eret();
> -    env->active_tc.PC = env->CP0_DEPC;
> +    env->active_tc.PC = env->CP0_DEPC & ~(target_ulong)1;
> +    env->active_tc.ISAMode = env->CP0_DEPC & 1;
> +
>      env->hflags &= MIPS_HFLAG_DM;
>      compute_hflags(env);
>      debug_post_eret();
> -- 
> 1.6.3.2
> 
> 
> 
> 

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

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

* Re: [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding Nathan Froyd
@ 2009-11-28 10:17   ` Aurelien Jarno
  0 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Mon, Nov 23, 2009 at 12:50:07PM -0800, Nathan Froyd wrote:
> There's no good way to add this incrementally, so we do it all at once.
> The only changes to shared code are in handle_delay_slot.  We need to
> flip ISAMode when doing a jump-and-exchange.  We also need to set
> ISAMode the low bit of the target address for jump-to-register.

This patch breaks the boot of both MIPS kernel. On little endian, the
kernel crashes with the following message:
  CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 00000000, ra == 80120004

On big endian, it fails before printing a single message on the console.

See also my other comments inline.

> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
>  target-mips/translate.c |  980 ++++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 976 insertions(+), 4 deletions(-)
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index 611774b..49d2264 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -83,6 +83,7 @@ enum {
>      OPC_LH       = (0x21 << 26),
>      OPC_LWL      = (0x22 << 26),
>      OPC_LW       = (0x23 << 26),
> +    OPC_LWPC     = OPC_LW | 0x5,
>      OPC_LBU      = (0x24 << 26),
>      OPC_LHU      = (0x25 << 26),
>      OPC_LWR      = (0x26 << 26),
> @@ -173,6 +174,7 @@ enum {
>      /* Jumps */
>      OPC_JR       = 0x08 | OPC_SPECIAL, /* Also JR.HB */
>      OPC_JALR     = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
> +    OPC_JALRC    = OPC_JALR | (0x5 << 6),
>      /* Traps */
>      OPC_TGE      = 0x30 | OPC_SPECIAL,
>      OPC_TGEU     = 0x31 | OPC_SPECIAL,
> @@ -1074,6 +1076,19 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
>          opn = "sdr";
>          break;
>  #endif
> +    case OPC_LWPC:
> +        save_cpu_state(ctx, 1);
> +        if (ctx->hflags & MIPS_HFLAG_BMASK) {
> +            int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4;
> +
> +            tcg_gen_movi_tl(t1, (ctx->pc - branch_bytes) & ~(target_ulong)3);
> +        } else {
> +            tcg_gen_movi_tl(t1, ctx->pc & ~(target_ulong)3);
> +        }
> +        gen_op_addr_add(ctx, t0, t0, t1);
> +        op_ldst_lw(t0, t0, ctx);
> +        gen_store_gpr(t0, rt);
> +        break;
>      case OPC_LW:
>          save_cpu_state(ctx, 0);
>          op_ldst_lw(t0, t0, ctx);
> @@ -2450,11 +2465,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
>          break;
>      case OPC_J:
>      case OPC_JAL:
> +    case OPC_JALX:
>          /* Jump to immediate */
>          btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
>          break;
>      case OPC_JR:
>      case OPC_JALR:
> +    case OPC_JALRC:
>          /* Jump to register */
>          if (offset != 0 && offset != 16) {
>              /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
> @@ -2517,18 +2534,29 @@ 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_JALX:
> +            ctx->hflags |= MIPS_HFLAG_BX;
> +            /* Fallthrough */
>          case OPC_JAL:
>              blink = 31;
>              ctx->hflags |= MIPS_HFLAG_B;
> +            ctx->hflags |= (ctx->isa_mode
> +                            ? MIPS_HFLAG_BDS16
> +                            : MIPS_HFLAG_BDS32);
>              MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
>              break;
>          case OPC_JR:
>              ctx->hflags |= MIPS_HFLAG_BR;
> +            if (ctx->isa_mode)
> +                ctx->hflags |= MIPS_HFLAG_BDS16;
>              MIPS_DEBUG("jr %s", regnames[rs]);
>              break;
>          case OPC_JALR:
> +        case OPC_JALRC:
>              blink = rt;
>              ctx->hflags |= MIPS_HFLAG_BR;
> +            if (ctx->isa_mode)
> +                ctx->hflags |= MIPS_HFLAG_BDS16;
>              MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
>              break;
>          default:
> @@ -2625,7 +2653,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
>  
>      ctx->btarget = btgt;
>      if (blink > 0) {
> -        tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + 8);
> +        int post_delay = insn_bytes;
> +        int lowbit = ctx->isa_mode;
> +
> +        if (opc != OPC_JALRC)
> +            post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4);
> +
> +        tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit);
>      }
>  
>   out:
> @@ -7558,10 +7592,17 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
>          ctx->bstate = BS_BRANCH;
>          save_cpu_state(ctx, 0);
>          /* FIXME: Need to clear can_do_io.  */
> -        switch (hflags) {
> +        switch (hflags & MIPS_HFLAG_BMASK_BASE) {
>          case MIPS_HFLAG_B:
>              /* unconditional branch */
>              MIPS_DEBUG("unconditional branch");
> +            if (hflags & MIPS_HFLAG_BX) {
> +                TCGv_i32 t0 = tcg_temp_new_i32();
> +
> +                tcg_gen_movi_i32(t0, 1 - ctx->isa_mode);
> +                tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, active_tc.ISAMode));
> +                tcg_temp_free_i32(t0);
> +            }
>              gen_goto_tb(ctx, 0, ctx->btarget);
>              break;
>          case MIPS_HFLAG_BL:
> @@ -7584,7 +7625,20 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
>          case MIPS_HFLAG_BR:
>              /* unconditional branch to register */
>              MIPS_DEBUG("branch to register");
> -            tcg_gen_mov_tl(cpu_PC, btarget);
> +            if (env->insn_flags & ASE_MIPS16) {
> +                TCGv t0 = tcg_temp_new();
> +                TCGv_i32 t1 = tcg_temp_new_i32();
> +
> +                tcg_gen_andi_tl(t0, btarget, 0x1);
> +                tcg_gen_trunc_tl_i32(t1, t0);
> +                tcg_temp_free(t0);
> +                tcg_gen_st_i32(t1, cpu_env, offsetof(CPUState, active_tc.ISAMode));
> +                tcg_temp_free_i32(t1);
> +
> +                tcg_gen_andi_tl(cpu_PC, btarget, ~(target_ulong)0x1);
> +            } else {
> +                tcg_gen_mov_tl(cpu_PC, btarget);
> +            }
>              if (ctx->singlestep_enabled) {
>                  save_cpu_state(ctx, 0);
>                  gen_helper_0i(raise_exception, EXCP_DEBUG);
> @@ -7712,6 +7766,918 @@ enum {
>    RR_RY_CNVT_SEW = 0x6,
>  };
>  
> +static int xlat (int r)
> +{
> +  static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
> +
> +  return map[r];
> +}
> +
> +static void gen_mips16_save (DisasContext *ctx,
> +                             int xsregs, int aregs,
> +                             int do_ra, int do_s0, int do_s1,
> +                             int framesize)
> +{
> +    TCGv t0 = tcg_temp_new();
> +    TCGv t1 = tcg_temp_new();
> +    int args, astatic;
> +
> +    switch (aregs) {
> +    case 0:
> +    case 1:
> +    case 2:
> +    case 3:
> +    case 11:
> +        args = 0;
> +        break;
> +    case 4:
> +    case 5:
> +    case 6:
> +    case 7:
> +        args = 1;
> +        break;
> +    case 8:
> +    case 9:
> +    case 10:
> +        args = 2;
> +        break;
> +    case 12:
> +    case 13:
> +        args = 3;
> +        break;
> +    case 14:
> +        args = 4;
> +        break;
> +    default:
> +        generate_exception(ctx, EXCP_RI);
> +        return;
> +    }
> +
> +    switch (args) {
> +    case 4:
> +        gen_base_offset_addr(ctx, t0, 29, 12);
> +        gen_load_gpr(t1, 7);
> +        op_ldst_sw(t1, t0, ctx);
> +        /* Fall through */
> +    case 3:
> +        gen_base_offset_addr(ctx, t0, 29, 8);
> +        gen_load_gpr(t1, 6);
> +        op_ldst_sw(t1, t0, ctx);
> +        /* Fall through */
> +    case 2:
> +        gen_base_offset_addr(ctx, t0, 29, 4);
> +        gen_load_gpr(t1, 5);
> +        op_ldst_sw(t1, t0, ctx);
> +        /* Fall through */
> +    case 1:
> +        gen_base_offset_addr(ctx, t0, 29, 0);
> +        gen_load_gpr(t1, 4);
> +        op_ldst_sw(t1, t0, ctx);
> +    }
> +
> +    gen_load_gpr(t0, 29);
> +
> +#define DECR_AND_STORE(reg) do {                \
> +        tcg_gen_subi_tl(t0, t0, 4);             \
> +        gen_load_gpr(t1, reg);                  \
> +        op_ldst_sw(t1, t0, ctx);                \
> +    } while (0)
> +
> +    if (do_ra) {
> +        DECR_AND_STORE(31);
> +    }
> +
> +    switch (xsregs) {
> +    case 7:
> +        DECR_AND_STORE(30);
> +        /* Fall through */
> +    case 6:
> +        DECR_AND_STORE(23);
> +        /* Fall through */
> +    case 5:
> +        DECR_AND_STORE(22);
> +        /* Fall through */
> +    case 4:
> +        DECR_AND_STORE(21);
> +        /* Fall through */
> +    case 3:
> +        DECR_AND_STORE(20);
> +        /* Fall through */
> +    case 2:
> +        DECR_AND_STORE(19);
> +        /* Fall through */
> +    case 1:
> +        DECR_AND_STORE(18);
> +    }
> +
> +    if (do_s1) {
> +        DECR_AND_STORE(17);
> +    }
> +    if (do_s0) {
> +        DECR_AND_STORE(16);
> +    }
> +
> +    switch (aregs) {
> +    case 0:
> +    case 4:
> +    case 8:
> +    case 12:
> +    case 14:
> +        astatic = 0;
> +        break;
> +    case 1:
> +    case 5:
> +    case 9:
> +    case 13:
> +        astatic = 1;
> +        break;
> +    case 2:
> +    case 6:
> +    case 10:
> +        astatic = 2;
> +        break;
> +    case 3:
> +    case 7:
> +        astatic = 3;
> +        break;
> +    case 11:
> +        astatic = 4;
> +        break;
> +    default:
> +        generate_exception(ctx, EXCP_RI);
> +        return;
> +    }
> +
> +    if (astatic > 0) {
> +        DECR_AND_STORE(7);
> +        if (astatic > 1) {
> +            DECR_AND_STORE(6);
> +            if (astatic > 2) {
> +                DECR_AND_STORE(5);
> +                if (astatic > 3) {
> +                    DECR_AND_STORE(4);
> +                }
> +            }
> +        }
> +    }
> +#undef DECR_AND_STORE
> +
> +    tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +}
> +
> +static void gen_mips16_restore (DisasContext *ctx,
> +                                int xsregs, int aregs,
> +                                int do_ra, int do_s0, int do_s1,
> +                                int framesize)
> +{
> +    int astatic;
> +    TCGv t0 = tcg_temp_new();
> +    TCGv t1 = tcg_temp_new();
> +
> +    tcg_gen_addi_tl(t0, cpu_gpr[29], framesize);
> +
> +#define DECR_AND_LOAD(reg) do {                 \
> +        tcg_gen_subi_tl(t0, t0, 4);             \
> +        op_ldst_lw(t1, t0, ctx);                \
> +        gen_store_gpr(t1, reg);                 \
> +    } while (0)
> +
> +    if (do_ra) {
> +        DECR_AND_LOAD(31);
> +    }
> +
> +    switch (xsregs) {
> +    case 7:
> +        DECR_AND_LOAD(30);
> +        /* Fall through */
> +    case 6:
> +        DECR_AND_LOAD(23);
> +        /* Fall through */
> +    case 5:
> +        DECR_AND_LOAD(22);
> +        /* Fall through */
> +    case 4:
> +        DECR_AND_LOAD(21);
> +        /* Fall through */
> +    case 3:
> +        DECR_AND_LOAD(20);
> +        /* Fall through */
> +    case 2:
> +        DECR_AND_LOAD(19);
> +        /* Fall through */
> +    case 1:
> +        DECR_AND_LOAD(18);
> +    }
> +
> +    if (do_s1) {
> +        DECR_AND_LOAD(17);
> +    }
> +    if (do_s0) {
> +        DECR_AND_LOAD(16);
> +    }
> +
> +    switch (aregs) {
> +    case 0:
> +    case 4:
> +    case 8:
> +    case 12:
> +    case 14:
> +        astatic = 0;
> +        break;
> +    case 1:
> +    case 5:
> +    case 9:
> +    case 13:
> +        astatic = 1;
> +        break;
> +    case 2:
> +    case 6:
> +    case 10:
> +        astatic = 2;
> +        break;
> +    case 3:
> +    case 7:
> +        astatic = 3;
> +        break;
> +    case 11:
> +        astatic = 4;
> +        break;
> +    default:
> +        generate_exception(ctx, EXCP_RI);
> +        return;
> +    }
> +
> +    if (astatic > 0) {
> +        DECR_AND_LOAD(7);
> +        if (astatic > 1) {
> +            DECR_AND_LOAD(6);
> +            if (astatic > 2) {
> +                DECR_AND_LOAD(5);
> +                if (astatic > 3) {
> +                    DECR_AND_LOAD(4);
> +                }
> +            }
> +        }
> +    }
> +#undef DECR_AND_LOAD
> +
> +    tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +}
> +
> +static void gen_addiupc (DisasContext *ctx, int rx, int imm)
> +{
> +    TCGv t0 = tcg_temp_new();
> +
> +    tcg_gen_movi_tl(t0, ctx->pc & ~(target_ulong)3);
> +    tcg_gen_addi_tl(cpu_gpr[rx], t0, imm);
> +
> +    tcg_temp_free(t0);
> +}
> +
> +static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx,
> +                                       int *is_branch)
> +{
> +    int extend = lduw_code(ctx->pc + 2);
> +    int op, rx, ry, funct, sa;
> +    int16_t imm, offset;
> +
> +    ctx->opcode = (ctx->opcode << 16) | extend;
> +    op = (ctx->opcode >> 11) & 0x1f;
> +    sa = (ctx->opcode >> 22) & 0x1f;
> +    funct = (ctx->opcode >> 8) & 0x7;
> +    rx = xlat((ctx->opcode >> 8) & 0x7);
> +    ry = xlat((ctx->opcode >> 5) & 0x7);
> +    offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11
> +                              | ((ctx->opcode >> 21) & 0x3f) << 5
> +                              | (ctx->opcode & 0x1f));
> +
> +    /* The extended opcodes cleverly reuse the opcodes from their 16-bit
> +       counterparts.  */
> +    switch (op) {
> +    case M16_OPC_ADDIUSP:
> +        gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
> +        break;
> +    case M16_OPC_ADDIUPC:
> +        gen_addiupc(ctx, rx, imm);
> +        break;
> +    case M16_OPC_B:
> +        gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1);
> +        /* No delay slot, so just process as a normal instruction */
> +        break;
> +    case M16_OPC_BEQZ:
> +        gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1);
> +        /* No delay slot, so just process as a normal instruction */
> +        break;
> +    case M16_OPC_BNEQZ:
> +        gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1);
> +        /* No delay slot, so just process as a normal instruction */
> +        break;
> +    case M16_OPC_SHIFT:
> +        switch (ctx->opcode & 0x3) {
> +        case 0x0:
> +            gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
> +            break;
> +        case 0x1:
> +#if defined(TARGET_MIPS64)
> +            gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);

Shouldn't this generate an exception on 64-bit CPU, but with 64-bit
instructions not enabled? The MIPS16e manual is not really clear about
that.

Same for other instructions below.

> +#else
> +            generate_exception(ctx, EXCP_RI);
> +#endif
> +            break;
> +        case 0x2:
> +            gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
> +            break;
> +        case 0x3:
> +            gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
> +            break;
> +        }
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case M16_OPC_LD:
> +        gen_ldst(ctx, OPC_LD, ry, rx, offset);
> +        break;
> +#endif
> +    case M16_OPC_RRIA:
> +        imm = ctx->opcode & 0xf;
> +        imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4;
> +        imm = imm | ((ctx->opcode >> 16) & 0xf) << 11;
> +        imm = (int16_t) (imm << 1) >> 1;
> +        if ((ctx->opcode >> 4) & 0x1) {
> +#if defined(TARGET_MIPS64)
> +            gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
> +#else
> +            generate_exception(ctx, EXCP_RI);
> +#endif
> +        } else {
> +            gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
> +        }
> +        break;
> +    case M16_OPC_ADDIU8:
> +        gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
> +        break;
> +    case M16_OPC_SLTI:
> +        gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
> +        break;
> +    case M16_OPC_SLTIU:
> +        gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
> +        break;
> +    case M16_OPC_I8:
> +        switch (funct) {
> +        case I8_BTEQZ:
> +            gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1);
> +            break;
> +        case I8_BTNEZ:
> +            gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1);
> +            break;
> +        case I8_SWRASP:
> +            gen_ldst(ctx, OPC_SW, 31, 29, imm);
> +            break;
> +        case I8_ADJSP:
> +            gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm);
> +            break;
> +        case I8_SVRS:
> +            {
> +                int xsregs = (ctx->opcode >> 24) & 0x7;
> +                int aregs = (ctx->opcode >> 16) & 0xf;
> +                int do_ra = (ctx->opcode >> 6) & 0x1;
> +                int do_s0 = (ctx->opcode >> 5) & 0x1;
> +                int do_s1 = (ctx->opcode >> 4) & 0x1;
> +                int framesize = (((ctx->opcode >> 20) & 0xf) << 4
> +                                 | (ctx->opcode & 0xf)) << 3;
> +
> +                if (ctx->opcode & (1 << 7)) {
> +                    gen_mips16_save(ctx, xsregs, aregs,
> +                                    do_ra, do_s0, do_s1,
> +                                    framesize);
> +                } else {
> +                    gen_mips16_restore(ctx, xsregs, aregs,
> +                                       do_ra, do_s0, do_s1,
> +                                       framesize);
> +                }
> +            }
> +            break;
> +        default:
> +            generate_exception(ctx, EXCP_RI);
> +            break;
> +        }
> +        break;
> +    case M16_OPC_LI:
> +        tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm);
> +        break;
> +    case M16_OPC_CMPI:
> +        tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm);
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case M16_OPC_SD:
> +        gen_ldst(ctx, OPC_SD, ry, rx, offset);
> +        break;
> +#endif
> +    case M16_OPC_LB:
> +        gen_ldst(ctx, OPC_LB, ry, rx, offset);
> +        break;
> +    case M16_OPC_LH:
> +        gen_ldst(ctx, OPC_LH, ry, rx, offset);
> +        break;
> +    case M16_OPC_LWSP:
> +        gen_ldst(ctx, OPC_LW, rx, 29, offset);
> +        break;
> +    case M16_OPC_LW:
> +        gen_ldst(ctx, OPC_LW, ry, rx, offset);
> +        break;
> +    case M16_OPC_LBU:
> +        gen_ldst(ctx, OPC_LBU, ry, rx, offset);
> +        break;
> +    case M16_OPC_LHU:
> +        gen_ldst(ctx, OPC_LHU, ry, rx, offset);
> +        break;
> +    case M16_OPC_LWPC:
> +        gen_ldst(ctx, OPC_LWPC, rx, 0, offset);
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case M16_OPC_LWU:
> +        gen_ldst(ctx, OPC_LWU, ry, rx, offset);
> +        break;
> +#endif
> +    case M16_OPC_SB:
> +        gen_ldst(ctx, OPC_SB, ry, rx, offset);
> +        break;
> +    case M16_OPC_SH:
> +        gen_ldst(ctx, OPC_SH, ry, rx, offset);
> +        break;
> +    case M16_OPC_SWSP:
> +        gen_ldst(ctx, OPC_SW, rx, 29, offset);
> +        break;
> +    case M16_OPC_SW:
> +        gen_ldst(ctx, OPC_SW, ry, rx, offset);
> +        break;
> +    default:
> +        generate_exception(ctx, EXCP_RI);
> +        break;
> +    }
> +
> +    return 4;
> +}
> +
> +static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
> +                              int *is_branch)
> +{
> +    int rx, ry;
> +    int sa;
> +    int op, cnvt_op, op1, offset;
> +    int funct;
> +    int n_bytes;
> +
> +    op = (ctx->opcode >> 11) & 0x1f;
> +    sa = (ctx->opcode >> 2) & 0x7;
> +    sa = sa == 0 ? 8 : sa;
> +    rx = xlat((ctx->opcode >> 8) & 0x7);
> +    cnvt_op = (ctx->opcode >> 5) & 0x7;
> +    ry = xlat((ctx->opcode >> 5) & 0x7);
> +    op1 = offset = ctx->opcode & 0x1f;
> +
> +    n_bytes = 2;
> +
> +    switch (op) {
> +    case M16_OPC_ADDIUSP:
> +        {
> +            int16_t imm = ((uint8_t) ctx->opcode) << 2;
> +
> +            gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
> +        }
> +        break;
> +    case M16_OPC_ADDIUPC:
> +        gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2);
> +        break;
> +    case M16_OPC_B:
> +        offset = (ctx->opcode & 0x7ff) << 1;
> +        offset = (int16_t)(offset << 4) >> 4;
> +        gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset);
> +        /* No delay slot, so just process as a normal instruction */
> +        break;
> +    case M16_OPC_JAL:
> +        offset = lduw_code(ctx->pc + 2);
> +        offset = (((ctx->opcode & 0x1f) << 21)
> +                  | ((ctx->opcode >> 5) & 0x1f) << 16
> +                  | offset) << 2;
> +        op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL;
> +        gen_compute_branch(ctx, op, 4, rx, ry, offset);
> +        n_bytes = 4;
> +        *is_branch = 1;
> +        break;
> +    case M16_OPC_BEQZ:
> +        gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
> +        /* No delay slot, so just process as a normal instruction */
> +        break;
> +    case M16_OPC_BNEQZ:
> +        gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
> +        /* No delay slot, so just process as a normal instruction */
> +        break;
> +    case M16_OPC_SHIFT:
> +        switch (ctx->opcode & 0x3) {
> +        case 0x0:
> +            gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
> +            break;
> +        case 0x1:
> +#if defined(TARGET_MIPS64)
> +            gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
> +#else
> +            generate_exception(ctx, EXCP_RI);
> +#endif
> +            break;
> +        case 0x2:
> +            gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
> +            break;
> +        case 0x3:
> +            gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
> +            break;
> +        }
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case M16_OPC_LD:
> +        gen_ldst(ctx, OPC_LD, ry, rx, offset << 3);
> +        break;
> +#endif
> +    case M16_OPC_RRIA:
> +        {
> +            int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4;
> +
> +            if ((ctx->opcode >> 4) & 1) {
> +#if defined(TARGET_MIPS64)
> +                gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
> +#else
> +                generate_exception(ctx, EXCP_RI);
> +#endif
> +            } else {
> +                gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
> +            }
> +        }
> +        break;
> +    case M16_OPC_ADDIU8:
> +        {
> +            int16_t imm = (int8_t) ctx->opcode;
> +
> +            gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
> +        }
> +        break;
> +    case M16_OPC_SLTI:
> +        {
> +            int16_t imm = (uint8_t) ctx->opcode;
> +
> +            gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
> +        }
> +        break;
> +    case M16_OPC_SLTIU:
> +        {
> +            int16_t imm = (uint8_t) ctx->opcode;
> +
> +            gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
> +        }
> +        break;
> +    case M16_OPC_I8:
> +        {
> +            int reg32;
> +
> +            funct = (ctx->opcode >> 8) & 0x7;
> +            switch (funct) {
> +            case I8_BTEQZ:
> +                gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0,
> +                                   ((int8_t)ctx->opcode) << 1);
> +                break;
> +            case I8_BTNEZ:
> +                gen_compute_branch(ctx, OPC_BNE, 2, 24, 0,
> +                                   ((int8_t)ctx->opcode) << 1);
> +                break;
> +            case I8_SWRASP:
> +                gen_ldst(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
> +                break;
> +            case I8_ADJSP:
> +                gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29,
> +                              ((int8_t)ctx->opcode) << 3);
> +                break;
> +            case I8_SVRS:
> +                {
> +                    int do_ra = ctx->opcode & (1 << 6);
> +                    int do_s0 = ctx->opcode & (1 << 5);
> +                    int do_s1 = ctx->opcode & (1 << 4);
> +                    int framesize = ctx->opcode & 0xf;
> +
> +                    if (framesize == 0) {
> +                        framesize = 128;
> +                    } else {
> +                        framesize = framesize << 3;
> +                    }
> +
> +                    if (ctx->opcode & (1 << 7)) {
> +                        gen_mips16_save(ctx, 0, 0,
> +                                        do_ra, do_s0, do_s1, framesize);
> +                    } else {
> +                        gen_mips16_restore(ctx, 0, 0,
> +                                           do_ra, do_s0, do_s1, framesize);
> +                    }
> +                }
> +                break;
> +            case I8_MOV32R:
> +                {
> +                    int rz = xlat(ctx->opcode & 0x7);
> +
> +                    reg32 = (((ctx->opcode >> 3) & 0x3) << 3) |
> +                        ((ctx->opcode >> 5) & 0x7);
> +                    gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0);
> +                }
> +                break;
> +            case I8_MOVR32:
> +                reg32 = ctx->opcode & 0x1f;
> +                gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0);
> +                break;
> +            default:
> +                generate_exception(ctx, EXCP_RI);
> +                break;
> +            }
> +        }
> +        break;
> +    case M16_OPC_LI:
> +        {
> +            int16_t imm = (uint8_t) ctx->opcode;
> +
> +            gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm);
> +        }
> +        break;
> +    case M16_OPC_CMPI:
> +        {
> +            int16_t imm = (uint8_t) ctx->opcode;
> +
> +            gen_logic_imm(env, OPC_XORI, 24, rx, imm);
> +        }
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case M16_OPC_SD:
> +        gen_ldst(ctx, OPC_SD, ry, rx, offset << 3);
> +        break;
> +#endif
> +    case M16_OPC_LB:
> +        gen_ldst(ctx, OPC_LB, ry, rx, offset);
> +        break;
> +    case M16_OPC_LH:
> +        gen_ldst(ctx, OPC_LH, ry, rx, offset << 1);
> +        break;
> +    case M16_OPC_LWSP:
> +        gen_ldst(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2);
> +        break;
> +    case M16_OPC_LW:
> +        gen_ldst(ctx, OPC_LW, ry, rx, offset << 2);
> +        break;
> +    case M16_OPC_LBU:
> +        gen_ldst(ctx, OPC_LBU, ry, rx, offset);
> +        break;
> +    case M16_OPC_LHU:
> +        gen_ldst(ctx, OPC_LHU, ry, rx, offset << 1);
> +        break;
> +    case M16_OPC_LWPC:
> +        gen_ldst(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2);
> +        break;
> +#if defined (TARGET_MIPS64)
> +    case M16_OPC_LWU:
> +        gen_ldst(ctx, OPC_LWU, ry, rx, offset << 2);
> +        break;
> +#endif
> +    case M16_OPC_SB:
> +        gen_ldst(ctx, OPC_SB, ry, rx, offset);
> +        break;
> +    case M16_OPC_SH:
> +        gen_ldst(ctx, OPC_SH, ry, rx, offset << 1);
> +        break;
> +    case M16_OPC_SWSP:
> +        gen_ldst(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2);
> +        break;
> +    case M16_OPC_SW:
> +        gen_ldst(ctx, OPC_SW, ry, rx, offset << 2);
> +        break;
> +    case M16_OPC_RRR:
> +        {
> +            int rz = xlat((ctx->opcode >> 2) & 0x7);
> +            int mips32_op;
> +
> +            switch (ctx->opcode & 0x3) {
> +            case RRR_ADDU:
> +                mips32_op = OPC_ADDU;
> +                break;
> +            case RRR_SUBU:
> +                mips32_op = OPC_SUBU;
> +                break;
> +#if defined(TARGET_MIPS64)
> +            case RRR_DADDU:
> +                mips32_op = OPC_DADDU;
> +                break;
> +            case RRR_DSUBU:
> +                mips32_op = OPC_DSUBU;
> +                break;
> +#endif
> +            default:
> +                generate_exception(ctx, EXCP_RI);
> +                goto done;
> +            }
> +
> +            gen_arith(env, ctx, mips32_op, rz, rx, ry);
> +        done:
> +            ;
> +        }
> +        break;
> +    case M16_OPC_RR:
> +        switch (op1) {
> +        case RR_JR:
> +            {
> +                int nd = (ctx->opcode >> 7) & 0x1;
> +                int link = (ctx->opcode >> 6) & 0x1;
> +                int ra = (ctx->opcode >> 5) & 0x1;
> +
> +                if (link) {
> +                    op = nd ? OPC_JALRC : OPC_JALR;
> +                } else {
> +                    op = OPC_JR;
> +                }
> +
> +                gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0);
> +                if (!nd) {
> +                    *is_branch = 1;
> +                }
> +            }
> +            break;
> +        case RR_SDBBP:
> +            /* 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 RR_SLT:
> +            gen_slt(env, OPC_SLT, 24, rx, ry);
> +            break;
> +        case RR_SLTU:
> +            gen_slt(env, OPC_SLTU, 24, rx, ry);
> +            break;
> +        case RR_BREAK:
> +            generate_exception(ctx, EXCP_BREAK);
> +            break;
> +        case RR_SLLV:
> +            gen_shift(env, ctx, OPC_SLLV, ry, rx, ry);
> +            break;
> +        case RR_SRLV:
> +            gen_shift(env, ctx, OPC_SRLV, ry, rx, ry);
> +            break;
> +        case RR_SRAV:
> +            gen_shift(env, ctx, OPC_SRAV, ry, rx, ry);
> +            break;
> +#if defined (TARGET_MIPS64)
> +        case RR_DSRL:
> +            gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa);
> +            break;
> +#endif
> +        case RR_CMP:
> +            gen_logic(env, OPC_XOR, 24, rx, ry);
> +            break;
> +        case RR_NEG:
> +            gen_arith(env, ctx, OPC_SUBU, rx, 0, ry);
> +            break;
> +        case RR_AND:
> +            gen_logic(env, OPC_AND, rx, rx, ry);
> +            break;
> +        case RR_OR:
> +            gen_logic(env, OPC_OR, rx, rx, ry);
> +            break;
> +        case RR_XOR:
> +            gen_logic(env, OPC_XOR, rx, rx, ry);
> +            break;
> +        case RR_NOT:
> +            gen_logic(env, OPC_NOR, rx, ry, 0);
> +            break;
> +        case RR_MFHI:
> +            gen_HILO(ctx, OPC_MFHI, rx);
> +            break;
> +        case RR_CNVT:
> +            switch (cnvt_op) {
> +            case RR_RY_CNVT_ZEB:
> +                tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]);
> +                break;
> +            case RR_RY_CNVT_ZEH:
> +                tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]);
> +                break;
> +            case RR_RY_CNVT_SEB:
> +                tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]);
> +                break;
> +            case RR_RY_CNVT_SEH:
> +                tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]);
> +                break;
> +#if defined (TARGET_MIPS64)
> +            case RR_RY_CNVT_ZEW:
> +                tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]);
> +                break;
> +            case RR_RY_CNVT_SEW:
> +                tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
> +                break;
> +#endif
> +            default:
> +                generate_exception(ctx, EXCP_RI);
> +                break;
> +            }
> +            break;
> +        case RR_MFLO:
> +            gen_HILO(ctx, OPC_MFLO, rx);
> +            break;
> +#if defined (TARGET_MIPS64)
> +        case RR_DSRA:
> +            gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa);
> +            break;
> +        case RR_DSLLV:
> +            gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry);
> +        case RR_DSRLV:
> +            gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry);
> +            break;
> +        case RR_DSRAV:
> +            gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry);
> +            break;
> +#endif
> +        case RR_MULT:
> +            gen_muldiv(ctx, OPC_MULT, rx, ry);
> +            break;
> +        case RR_MULTU:
> +            gen_muldiv(ctx, OPC_MULTU, rx, ry);
> +            break;
> +        case RR_DIV:
> +            gen_muldiv(ctx, OPC_DIV, rx, ry);
> +            break;
> +        case RR_DIVU:
> +            gen_muldiv(ctx, OPC_DIVU, rx, ry);
> +            break;
> +#if defined (TARGET_MIPS64)
> +        case RR_DMULT:
> +            gen_muldiv(ctx, OPC_DMULT, rx, ry);
> +            break;
> +        case RR_DMULTU:
> +            gen_muldiv(ctx, OPC_DMULTU, rx, ry);
> +            break;
> +        case RR_DDIV:
> +            gen_muldiv(ctx, OPC_DDIV, rx, ry);
> +            break;
> +        case RR_DDIVU:
> +            gen_muldiv(ctx, OPC_DDIVU, rx, ry);
> +            break;
> +#endif
> +        default:
> +            generate_exception(ctx, EXCP_RI);
> +            break;
> +        }
> +        break;
> +    case M16_OPC_EXTEND:
> +        decode_extended_mips16_opc(env, ctx, is_branch);
> +        n_bytes = 4;
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case M16_OPC_I64:
> +        funct = (ctx->opcode >> 8) & 0x7;
> +        switch (funct) {
> +        case I64_LDSP:
> +            gen_ldst(ctx, OPC_LD, ry, 29, offset << 3);
> +            break;
> +        case I64_SDSP:
> +            gen_ldst(ctx, OPC_SD, ry, 29, offset << 3);
> +            break;
> +        case I64_SDRASP:
> +            gen_ldst(ctx, OPC_SD, 31, 29, (ctx->opcode & 0xff) << 3);
> +            break;
> +        case I64_DADJSP:
> +            gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29,
> +                          ((int8_t)ctx->opcode) << 3);
> +            break;
> +        case I64_LDPC:
> +            break;
> +        case I64_DADDIU:
> +            gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry,
> +                          ((int8_t)(offset << 3)) >> 3);
> +            break;
> +        case I64_DADDIUPC:
> +            break;
> +        case I64_DADDIUSP:
> +            gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29,
> +                          ((int8_t)(offset << 3)) >> 1);
> +            break;
> +        }
> +#endif
> +    default:
> +        generate_exception(ctx, EXCP_RI);
> +        break;
> +    }
> +
> +    return n_bytes;
> +}
> +
>  /* SmartMIPS extension to MIPS32 */
>  
>  #if defined(TARGET_MIPS64)
> @@ -8400,7 +9366,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
>  #endif
>      case OPC_JALX:
>          check_insn(env, ctx, ASE_MIPS16);
> -        /* MIPS16: Not implemented. */
> +        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
> +        gen_compute_branch(ctx, op, 4, rs, rt, offset);
> +        *is_branch = 1;
> +        break;
>      case OPC_MDMX:
>          check_insn(env, ctx, ASE_MDMX);
>          /* MDMX: Not implemented. */
> @@ -8490,6 +9459,9 @@ 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_MIPS16) {
> +            ctx.opcode = lduw_code(ctx.pc);
> +            insn_bytes = decode_mips16_opc(env, &ctx, &is_branch);
>          } else {
>              generate_exception(&ctx, EXCP_RI);
>              break;
> -- 
> 1.6.3.2
> 
> 
> 
> 

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

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

* Re: [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr Nathan Froyd
@ 2009-11-28 10:17   ` Aurelien Jarno
  0 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Mon, Nov 23, 2009 at 12:50:04PM -0800, Nathan Froyd wrote:
> This is a common pattern in existing code.  We'll also use it to
> implement the mips16 SAVE/RESTORE instructions.
> 
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
>  target-mips/translate.c |   40 ++++++++++++++++------------------------
>  1 files changed, 16 insertions(+), 24 deletions(-)
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index 1157e97..fece3c1 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -997,6 +997,19 @@ OP_ST_ATOMIC(scd,st64,ld64,0x7);
>  #endif
>  #undef OP_ST_ATOMIC
>  
> +static void gen_base_offset_addr (DisasContext *ctx, TCGv addr,
> +                                  int base, int16_t offset)
> +{
> +    if (base == 0) {
> +        tcg_gen_movi_tl(addr, offset);
> +    } else if (offset == 0) {
> +        gen_load_gpr(addr, base);
> +    } else {
> +        tcg_gen_movi_tl(addr, offset);
> +        gen_op_addr_add(ctx, addr, addr, cpu_gpr[base]);

I am nitpicking a bit, but it's better to keep the two last argument as
in the original version to keep the immediate value in the last
position. This saves one instruction on non-RISC hosts.

> +    }
> +}
> +
>  /* Load and store */
>  static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
>                        int base, int16_t offset)
> @@ -1005,14 +1018,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
>      TCGv t0 = tcg_temp_new();
>      TCGv t1 = tcg_temp_new();
>  
> -    if (base == 0) {
> -        tcg_gen_movi_tl(t0, offset);
> -    } else if (offset == 0) {
> -        gen_load_gpr(t0, base);
> -    } else {
> -        tcg_gen_movi_tl(t0, offset);
> -        gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
> -    }
> +    gen_base_offset_addr(ctx, t0, base, offset);
>      /* Don't do NOP if destination is zero: we must perform the actual
>         memory access. */
>      switch (opc) {
> @@ -1163,14 +1169,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
>  
>      t0 = tcg_temp_local_new();
>  
> -    if (base == 0) {
> -        tcg_gen_movi_tl(t0, offset);
> -    } else if (offset == 0) {
> -        gen_load_gpr(t0, base);
> -    } else {
> -        tcg_gen_movi_tl(t0, offset);
> -        gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
> -    }
> +    gen_base_offset_addr(ctx, t0, base, offset);
>      /* Don't do NOP if destination is zero: we must perform the actual
>         memory access. */
>  
> @@ -1202,14 +1201,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
>      const char *opn = "flt_ldst";
>      TCGv t0 = tcg_temp_new();
>  
> -    if (base == 0) {
> -        tcg_gen_movi_tl(t0, offset);
> -    } else if (offset == 0) {
> -        gen_load_gpr(t0, base);
> -    } else {
> -        tcg_gen_movi_tl(t0, offset);
> -        gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
> -    }
> +    gen_base_offset_addr(ctx, t0, base, offset);
>      /* Don't do NOP if destination is zero: we must perform the actual
>         memory access. */
>      switch (opc) {
> -- 
> 1.6.3.2
> 
> 
> 
> 

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

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

* Re: [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution
  2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
@ 2009-11-28 10:17   ` Aurelien Jarno
  2009-11-30 17:45     ` Aurelien Jarno
  0 siblings, 1 reply; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Mon, Nov 23, 2009 at 12:49:59PM -0800, Nathan Froyd wrote:
> 
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
>  target-mips/cpu.h       |    1 +
>  target-mips/translate.c |    2 ++
>  2 files changed, 3 insertions(+), 0 deletions(-)
> 
> diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> index 82f9a38..e8febe6 100644
> --- a/target-mips/cpu.h
> +++ b/target-mips/cpu.h
> @@ -167,6 +167,7 @@ struct TCState {
>      target_ulong CP0_TCContext;
>      target_ulong CP0_TCSchedule;
>      target_ulong CP0_TCScheFBack;
> +    uint32_t ISAMode; /* MIPS32 or MIPS16 mode */
>      int32_t CP0_Debug_tcstatus;
>  };

I am fine with this.

> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index e9d9224..b0a1b29 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -463,6 +463,7 @@ typedef struct DisasContext {
>      struct TranslationBlock *tb;
>      target_ulong pc, saved_pc;
>      uint32_t opcode;
> +    int isa_mode;
>      int singlestep_enabled;
>      /* Routine used to access memory */
>      int mem_idx;
> @@ -8306,6 +8307,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
>      ctx.pc = pc_start;
>      ctx.saved_pc = -1;
>      ctx.singlestep_enabled = env->singlestep_enabled;
> +    ctx.isa_mode = env->active_tc.ISAMode;
>      ctx.tb = tb;
>      ctx.bstate = BS_NONE;
>      /* Restore delay slot state from the tb context.  */

Instead of a new ctx value, it's probably better to use a new bit in
hflags. It is also necessary to change MIPS_HFLAG_TMASK accordingly, to
ensure a MIPS16 translation block is not later executed while ISAMode is
0 (while it should generate an exception) and vice-versa.

This also mean that hflags should be recomputed each time ISAMode is
changed.

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

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

* Re: [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support
  2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
                   ` (10 preceding siblings ...)
  2009-11-23 20:50 ` [Qemu-devel] [PATCH 11/11] target-mips: add copyright notice for mips16 work Nathan Froyd
@ 2009-11-28 10:17 ` Aurelien Jarno
  11 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

Hi,

On Mon, Nov 23, 2009 at 12:49:58PM -0800, Nathan Froyd wrote:
> This patchset adds MIPS16 support to the MIPS backend.  MIPS16 is a
> compact encoding of a subset of the MIPS integer instructions, similar
> to ARM's Thumb mode.  The processor enters MIPS16 mode by executing a
> special jump instruction; execution continus at the jump target in
> MIPS16 mode until the processor returns to MIPS32/64 mode by executing a
> special jump instruction.
> 
> The patches have been tested with GCC's testsuite and GDB's testsuite.

It's nice there is someone working on items from target-mips/TODO. By 
the way, this patchset misses one patch to remove the entry from this
file ;-)

More seriously, this patchset still has a few problems, but I don't
expect them difficult to solve. Please see the comments on different
patches.

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

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

* Re: [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution
  2009-11-28 10:17   ` Aurelien Jarno
@ 2009-11-30 17:45     ` Aurelien Jarno
  0 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-30 17:45 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Sat, Nov 28, 2009 at 11:17:20AM +0100, Aurelien Jarno wrote:
> On Mon, Nov 23, 2009 at 12:49:59PM -0800, Nathan Froyd wrote:
> > 
> > Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> > ---
> >  target-mips/cpu.h       |    1 +
> >  target-mips/translate.c |    2 ++
> >  2 files changed, 3 insertions(+), 0 deletions(-)
> > 
> > diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> > index 82f9a38..e8febe6 100644
> > --- a/target-mips/cpu.h
> > +++ b/target-mips/cpu.h
> > @@ -167,6 +167,7 @@ struct TCState {
> >      target_ulong CP0_TCContext;
> >      target_ulong CP0_TCSchedule;
> >      target_ulong CP0_TCScheFBack;
> > +    uint32_t ISAMode; /* MIPS32 or MIPS16 mode */
> >      int32_t CP0_Debug_tcstatus;
> >  };
> 
> I am fine with this.
> 
> > diff --git a/target-mips/translate.c b/target-mips/translate.c
> > index e9d9224..b0a1b29 100644
> > --- a/target-mips/translate.c
> > +++ b/target-mips/translate.c
> > @@ -463,6 +463,7 @@ typedef struct DisasContext {
> >      struct TranslationBlock *tb;
> >      target_ulong pc, saved_pc;
> >      uint32_t opcode;
> > +    int isa_mode;
> >      int singlestep_enabled;
> >      /* Routine used to access memory */
> >      int mem_idx;
> > @@ -8306,6 +8307,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
> >      ctx.pc = pc_start;
> >      ctx.saved_pc = -1;
> >      ctx.singlestep_enabled = env->singlestep_enabled;
> > +    ctx.isa_mode = env->active_tc.ISAMode;
> >      ctx.tb = tb;
> >      ctx.bstate = BS_NONE;
> >      /* Restore delay slot state from the tb context.  */
> 
> Instead of a new ctx value, it's probably better to use a new bit in
> hflags. It is also necessary to change MIPS_HFLAG_TMASK accordingly, to
> ensure a MIPS16 translation block is not later executed while ISAMode is
> 0 (while it should generate an exception) and vice-versa.
> 
> This also mean that hflags should be recomputed each time ISAMode is
> changed.
> 

Actually just changing ctx.hflags is enough, as it is automatically
saved to env->hflags at the end of the TB or if an exception can occur.

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

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

end of thread, other threads:[~2009-11-30 19:27 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
2009-11-28 10:17   ` Aurelien Jarno
2009-11-30 17:45     ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 02/11] target-mips: add new HFLAGs for JALX and 16/32-bit delay slots Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware Nathan Froyd
2009-11-28 10:17   ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 04/11] target-mips: move ROTR and ROTRV inside gen_shift_{imm, } Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 05/11] target-mips: make gen_compute_branch 16/32-bit-aware Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr Nathan Froyd
2009-11-28 10:17   ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 07/11] target-mips: split out delay slot handling Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 08/11] target-mips: add enums for MIPS16 opcodes Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding Nathan Froyd
2009-11-28 10:17   ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 10/11] gdbstub: add MIPS16 support Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 11/11] target-mips: add copyright notice for mips16 work Nathan Froyd
2009-11-28 10:17 ` [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Aurelien Jarno

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