qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/28] target-mips queue
@ 2014-10-15  9:53 Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 01/28] target-mips: define ISA_MIPS64R6 Leon Alrae
                   ` (29 more replies)
  0 siblings, 30 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:53 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Aurelien Jarno

Hi,

This pull request has been assembled from pending target-mips patches which
look good to me and received in my opinion sufficient review comments. They
were tested mainly in context of MIPS. Please have a look and pull.

Thanks,
Leon

Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Aurelien Jarno <aurelien@aurel32.net>

The following changes since commit b1d28ec6a7dbdaadda39d29322f0de694aeb0b74:

  Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20141010' into staging (2014-10-10 14:55:29 +0100)

are available in the git repository at:

  git://github.com/lalrae/qemu.git tags/mips-20141015

for you to fetch changes up to 340fff722d8a7cf9c0d4f1e1b4fad03a145a9657:

  target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX (2014-10-14 13:29:15 +0100)

----------------------------------------------------------------
MIPS patches 2014-10-15

Changes:
* MIPS64R6 (unprivileged) support
* fix for broken MIPS16 and microMIPS
* SYNCI improvement
* unused MIPS code removal

----------------------------------------------------------------
Dongxue Zhang (1):
  target-mips/translate.c: Update OPC_SYNCI

Leon Alrae (17):
  target-mips: define ISA_MIPS64R6
  target-mips: signal RI Exception on instructions removed in R6
  target-mips: add SELEQZ and SELNEZ instructions
  target-mips: move LL and SC instructions
  target-mips: extract decode_opc_special* from decode_opc
  target-mips: split decode_opc_special* into *_r6 and *_legacy
  target-mips: signal RI Exception on DSP and Loongson instructions
  target-mips: move PREF, CACHE, LLD and SCD instructions
  target-mips: redefine Integer Multiply and Divide instructions
  target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6
  target-mips: Status.UX/SX/KX enable 32-bit address wrapping
  target-mips: add AUI, LSA and PCREL instruction families
  softfloat: add functions corresponding to IEEE-2008 min/maxNumMag
  target-mips: add new Floating Point instructions
  target-mips: do not allow Status.FR=0 mode in 64-bit FPU
  mips_malta: update malta's pseudo-bootloader - replace JR with JALR
  target-mips: define a new generic CPU supporting MIPS64 Release 6 ISA

Peter Maydell (5):
  target-mips/dsp_helper.c: Remove unused function get_DSPControl_24()
  target-mips/op_helper.c: Remove unused do_lbu() function
  target-mips/translate.c: Add ifdef guard around check_mips64()
  target-mips/dsp_helper.c: Add ifdef guards around various functions
  target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX

Yongbok Kim (5):
  target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  target-mips: add compact and CP1 branches
  target-mips: add new Floating Point Comparison instructions
  target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions
  target-mips: fix broken MIPS16 and microMIPS

 disas/mips.c                 |  211 ++-
 fpu/softfloat.c              |   37 +-
 hw/mips/mips_malta.c         |   10 +-
 include/fpu/softfloat.h      |    4 +
 target-mips/cpu.h            |   31 +-
 target-mips/dsp_helper.c     |   26 +-
 target-mips/helper.h         |   52 +
 target-mips/mips-defs.h      |   28 +-
 target-mips/op_helper.c      |  239 ++-
 target-mips/translate.c      | 4114 ++++++++++++++++++++++++++++++------------
 target-mips/translate_init.c |   30 +
 11 files changed, 3563 insertions(+), 1219 deletions(-)

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

* [Qemu-devel] [PULL 01/28] target-mips: define ISA_MIPS64R6
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
@ 2014-10-15  9:53 ` Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 02/28] target-mips: signal RI Exception on instructions removed in R6 Leon Alrae
                   ` (28 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:53 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-mips/mips-defs.h | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
index 9dfa516..6cb62b2 100644
--- a/target-mips/mips-defs.h
+++ b/target-mips/mips-defs.h
@@ -30,17 +30,21 @@
 #define		ISA_MIPS64	0x00000080
 #define		ISA_MIPS64R2	0x00000100
 #define   ISA_MIPS32R3  0x00000200
-#define   ISA_MIPS32R5  0x00000400
+#define   ISA_MIPS64R3  0x00000400
+#define   ISA_MIPS32R5  0x00000800
+#define   ISA_MIPS64R5  0x00001000
+#define   ISA_MIPS32R6  0x00002000
+#define   ISA_MIPS64R6  0x00004000
 
 /* MIPS ASEs. */
-#define		ASE_MIPS16	0x00001000
-#define		ASE_MIPS3D	0x00002000
-#define		ASE_MDMX	0x00004000
-#define		ASE_DSP		0x00008000
-#define		ASE_DSPR2	0x00010000
-#define		ASE_MT		0x00020000
-#define		ASE_SMARTMIPS	0x00040000
-#define 	ASE_MICROMIPS	0x00080000
+#define   ASE_MIPS16    0x00010000
+#define   ASE_MIPS3D    0x00020000
+#define   ASE_MDMX      0x00040000
+#define   ASE_DSP       0x00080000
+#define   ASE_DSPR2     0x00100000
+#define   ASE_MT        0x00200000
+#define   ASE_SMARTMIPS 0x00400000
+#define   ASE_MICROMIPS 0x00800000
 
 /* Chip specific instructions. */
 #define		INSN_LOONGSON2E  0x20000000
@@ -68,9 +72,15 @@
 
 /* MIPS Technologies "Release 3" */
 #define CPU_MIPS32R3 (CPU_MIPS32R2 | ISA_MIPS32R3)
+#define CPU_MIPS64R3 (CPU_MIPS64R2 | CPU_MIPS32R3 | ISA_MIPS64R3)
 
 /* MIPS Technologies "Release 5" */
 #define CPU_MIPS32R5 (CPU_MIPS32R3 | ISA_MIPS32R5)
+#define CPU_MIPS64R5 (CPU_MIPS64R3 | CPU_MIPS32R5 | ISA_MIPS64R5)
+
+/* MIPS Technologies "Release 6" */
+#define CPU_MIPS32R6 (CPU_MIPS32R5 | ISA_MIPS32R6)
+#define CPU_MIPS64R6 (CPU_MIPS64R5 | CPU_MIPS32R6 | ISA_MIPS64R6)
 
 /* Strictly follow the architecture standard:
    - Disallow "special" instruction handling for PMON/SPIM.
-- 
2.1.0

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

* [Qemu-devel] [PULL 02/28] target-mips: signal RI Exception on instructions removed in R6
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 01/28] target-mips: define ISA_MIPS64R6 Leon Alrae
@ 2014-10-15  9:53 ` Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 03/28] target-mips: add SELEQZ and SELNEZ instructions Leon Alrae
                   ` (27 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:53 UTC (permalink / raw)
  To: qemu-devel

Signal Reserved Instruction Exception on instructions that do not exist in R6.
In this commit the following groups of preR6 instructions are marked as deleted:
- Floating Point Paired Single
- Floating Point Compare
- conditional moves / branches on FPU conditions
- branch likelies
- unaligned loads / stores
- traps
- legacy accumulator instructions
- COP1X
- MIPS-3D

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-mips/translate.c | 64 ++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 56 insertions(+), 8 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 06db150..de11747 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1436,6 +1436,16 @@ static inline void check_insn(DisasContext *ctx, int flags)
     }
 }
 
+/* This code generates a "reserved instruction" exception if the
+   CPU has corresponding flag set which indicates that the instruction
+   has been removed. */
+static inline void check_insn_opc_removed(DisasContext *ctx, int flags)
+{
+    if (unlikely(ctx->insn_flags & flags)) {
+        generate_exception(ctx, EXCP_RI);
+    }
+}
+
 /* This code generates a "reserved instruction" exception if 64-bit
    instructions are not enabled. */
 static inline void check_mips_64(DisasContext *ctx)
@@ -7712,10 +7722,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "floor.w.s";
         break;
     case OPC_MOVCF_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
         opn = "movcf.s";
         break;
     case OPC_MOVZ_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         {
             int l1 = gen_new_label();
             TCGv_i32 fp0;
@@ -7732,6 +7744,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "movz.s";
         break;
     case OPC_MOVN_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         {
             int l1 = gen_new_label();
             TCGv_i32 fp0;
@@ -7865,6 +7878,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "cvt.l.s";
         break;
     case OPC_CVT_PS_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp64 = tcg_temp_new_i64();
@@ -7897,6 +7911,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
     case OPC_CMP_NGE_S:
     case OPC_CMP_LE_S:
     case OPC_CMP_NGT_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         if (ctx->opcode & (1 << 6)) {
             gen_cmpabs_s(ctx, func-48, ft, fs, cc);
             opn = condnames_abs[func-48];
@@ -8121,10 +8136,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "floor.w.d";
         break;
     case OPC_MOVCF_D:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
         opn = "movcf.d";
         break;
     case OPC_MOVZ_D:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         {
             int l1 = gen_new_label();
             TCGv_i64 fp0;
@@ -8141,6 +8158,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "movz.d";
         break;
     case OPC_MOVN_D:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         {
             int l1 = gen_new_label();
             TCGv_i64 fp0;
@@ -8250,6 +8268,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
     case OPC_CMP_NGE_D:
     case OPC_CMP_LE_D:
     case OPC_CMP_NGT_D:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         if (ctx->opcode & (1 << 6)) {
             gen_cmpabs_d(ctx, func-48, ft, fs, cc);
             opn = condnames_abs[func-48];
@@ -8350,6 +8369,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "cvt.d.l";
         break;
     case OPC_CVT_PS_PW:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         check_cp1_64bitmode(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -14508,6 +14528,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
         case OPC_MOVN:         /* Conditional move */
         case OPC_MOVZ:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
                                  INSN_LOONGSON2E | INSN_LOONGSON2F);
             gen_cond_move(ctx, op1, rd, rs, rt);
@@ -14568,10 +14589,12 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
         case OPC_MFHI:          /* Move from HI/LO */
         case OPC_MFLO:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             gen_HILO(ctx, op1, rs & 3, rd);
             break;
         case OPC_MTHI:
         case OPC_MTLO:          /* Move to HI/LO */
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             gen_HILO(ctx, op1, rd & 3, rs);
             break;
         case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
@@ -14604,6 +14627,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
 
         case OPC_MOVCI:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
             if (ctx->CP0_Config1 & (1 << CP0C1_FP)) {
                 check_cp1_enabled(ctx);
@@ -14706,10 +14730,12 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         switch (op1) {
         case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
         case OPC_MSUB ... OPC_MSUBU:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             check_insn(ctx, ISA_MIPS32);
             gen_muldiv(ctx, op1, rd & 3, rs, rt);
             break;
         case OPC_MUL:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             gen_arith(ctx, op1, rd, rs, rt);
             break;
         case OPC_CLO:
@@ -15327,12 +15353,20 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
     case OPC_REGIMM:
         op1 = MASK_REGIMM(ctx->opcode);
         switch (op1) {
-        case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
-        case OPC_BLTZAL ... OPC_BGEZALL:
+        case OPC_BLTZL: /* REGIMM branches */
+        case OPC_BGEZL:
+        case OPC_BLTZALL:
+        case OPC_BGEZALL:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        case OPC_BLTZ:
+        case OPC_BGEZ:
+        case OPC_BLTZAL:
+        case OPC_BGEZAL:
             gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
             break;
         case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
         case OPC_TNEI:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             gen_trap(ctx, op1, rs, -1, imm);
             break;
         case OPC_SYNCI:
@@ -15457,16 +15491,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
          gen_compute_branch(ctx, op, 4, rs, rt, offset);
          break;
-    case OPC_BEQ ... OPC_BGTZ: /* Branch */
-    case OPC_BEQL ... OPC_BGTZL:
+    case OPC_BEQL ... OPC_BGTZL:  /* Branch */
+         check_insn_opc_removed(ctx, ISA_MIPS32R6);
+    case OPC_BEQ ... OPC_BGTZ:
          gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
          break;
-    case OPC_LB ... OPC_LWR: /* Load and stores */
+    case OPC_LWL: /* Load and stores */
+    case OPC_LWR:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+    case OPC_LB ... OPC_LH:
+    case OPC_LW ... OPC_LHU:
     case OPC_LL:
          gen_ld(ctx, op, rt, rs, imm);
          break;
-    case OPC_SB ... OPC_SW:
+    case OPC_SWL:
     case OPC_SWR:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+    case OPC_SB ... OPC_SH:
+    case OPC_SW:
          gen_st(ctx, op, rt, rs, imm);
          break;
     case OPC_SC:
@@ -15513,18 +15555,21 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
 #endif
             case OPC_BC1ANY2:
             case OPC_BC1ANY4:
+                check_insn_opc_removed(ctx, ISA_MIPS32R6);
                 check_cop1x(ctx);
                 check_insn(ctx, ASE_MIPS3D);
                 /* fall through */
             case OPC_BC1:
+                check_insn_opc_removed(ctx, ISA_MIPS32R6);
                 gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
                                     (rt >> 2) & 0x7, imm << 2);
                 break;
+            case OPC_PS_FMT:
+                check_insn_opc_removed(ctx, ISA_MIPS32R6);
             case OPC_S_FMT:
             case OPC_D_FMT:
             case OPC_W_FMT:
             case OPC_L_FMT:
-            case OPC_PS_FMT:
                 gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
                            (imm >> 8) & 0x7);
                 break;
@@ -15553,6 +15598,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         break;
 
     case OPC_CP3:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         if (ctx->CP0_Config1 & (1 << CP0C1_FP)) {
             check_cp1_enabled(ctx);
             op1 = MASK_CP3(ctx->opcode);
@@ -15595,8 +15641,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
 
 #if defined(TARGET_MIPS64)
     /* MIPS64 opcodes */
-    case OPC_LWU:
     case OPC_LDL ... OPC_LDR:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+    case OPC_LWU:
     case OPC_LLD:
     case OPC_LD:
         check_insn(ctx, ISA_MIPS3);
@@ -15604,6 +15651,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         gen_ld(ctx, op, rt, rs, imm);
         break;
     case OPC_SDL ... OPC_SDR:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
     case OPC_SD:
         check_insn(ctx, ISA_MIPS3);
         check_mips_64(ctx);
-- 
2.1.0

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

* [Qemu-devel] [PULL 03/28] target-mips: add SELEQZ and SELNEZ instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 01/28] target-mips: define ISA_MIPS64R6 Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 02/28] target-mips: signal RI Exception on instructions removed in R6 Leon Alrae
@ 2014-10-15  9:53 ` Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 04/28] target-mips: move LL and SC instructions Leon Alrae
                   ` (26 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:53 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: James Hogan <james.hogan@imgtec.com>
---
 disas/mips.c            |  8 ++++++++
 target-mips/translate.c | 18 ++++++++++++++++--
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 2106b57..b950e53 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -521,6 +521,8 @@ struct mips_opcode
 #define INSN_ISA64                0x00000040
 #define INSN_ISA32R2              0x00000080
 #define INSN_ISA64R2              0x00000100
+#define INSN_ISA32R6              0x00000200
+#define INSN_ISA64R6              0x00000400
 
 /* Masks used for MIPS-defined ASEs.  */
 #define INSN_ASE_MASK		  0x0000f000
@@ -585,6 +587,8 @@ struct mips_opcode
 #define       ISA_MIPS32R2    (ISA_MIPS32 | INSN_ISA32R2)
 #define       ISA_MIPS64R2    (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2)
 
+#define       ISA_MIPS32R6    (ISA_MIPS32R2 | INSN_ISA32R6)
+#define       ISA_MIPS64R6    (ISA_MIPS64R2 | INSN_ISA32R6 | INSN_ISA64R6)
 
 /* CPU defines, use instead of hardcoding processor number. Keep this
    in sync with bfd/archures.c in order for machine selection to work.  */
@@ -1121,6 +1125,8 @@ extern const int bfd_mips16_num_opcodes;
 #define I64     INSN_ISA64
 #define I33	INSN_ISA32R2
 #define I65	INSN_ISA64R2
+#define I32R6   INSN_ISA32R6
+#define I64R6   INSN_ISA64R6
 
 /* MIPS64 MIPS-3D ASE support.  */
 #define I16     INSN_MIPS16
@@ -1209,6 +1215,8 @@ const struct mips_opcode mips_builtin_opcodes[] =
    them first.  The assemblers uses a hash table based on the
    instruction name anyhow.  */
 /* name,    args,	match,	    mask,	pinfo,          	membership */
+{"seleqz",  "d,v,t",    0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"selnez",  "d,v,t",    0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	0,		I4|I32|G3	},
 {"prefx",   "h,t(b)",	0x4c00000f, 0xfc0007ff, RD_b|RD_t,		0,		I4|I33	},
 {"nop",     "",         0x00000000, 0xffffffff, 0,              	INSN2_ALIAS,	I1      }, /* sll */
diff --git a/target-mips/translate.c b/target-mips/translate.c
index de11747..ba9daac 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -193,6 +193,9 @@ enum {
     OPC_MOVZ     = 0x0A | OPC_SPECIAL,
     OPC_MOVN     = 0x0B | OPC_SPECIAL,
 
+    OPC_SELEQZ   = 0x35 | OPC_SPECIAL,
+    OPC_SELNEZ   = 0x37 | OPC_SPECIAL,
+
     OPC_MOVCI    = 0x01 | OPC_SPECIAL,
 
     /* Special */
@@ -205,8 +208,6 @@ enum {
     OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL,
     OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL,
     OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL,
-    OPC_SPECIAL35_RESERVED = 0x35 | OPC_SPECIAL,
-    OPC_SPECIAL37_RESERVED = 0x37 | OPC_SPECIAL,
     OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL,
     OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
 };
@@ -2412,6 +2413,14 @@ static void gen_cond_move(DisasContext *ctx, uint32_t opc,
         tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1, t2, cpu_gpr[rd]);
         opn = "movz";
         break;
+    case OPC_SELNEZ:
+        tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[rd], t0, t1, t2, t1);
+        opn = "selnez";
+        break;
+    case OPC_SELEQZ:
+        tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1, t2, t1);
+        opn = "seleqz";
+        break;
     }
     tcg_temp_free(t2);
     tcg_temp_free(t1);
@@ -14533,6 +14542,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
                                  INSN_LOONGSON2E | INSN_LOONGSON2F);
             gen_cond_move(ctx, op1, rd, rs, rt);
             break;
+        case OPC_SELEQZ:
+        case OPC_SELNEZ:
+            check_insn(ctx, ISA_MIPS32R6);
+            gen_cond_move(ctx, op1, rd, rs, rt);
+            break;
         case OPC_ADD ... OPC_SUBU:
             gen_arith(ctx, op1, rd, rs, rt);
             break;
-- 
2.1.0

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

* [Qemu-devel] [PULL 04/28] target-mips: move LL and SC instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (2 preceding siblings ...)
  2014-10-15  9:53 ` [Qemu-devel] [PULL 03/28] target-mips: add SELEQZ and SELNEZ instructions Leon Alrae
@ 2014-10-15  9:53 ` Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 05/28] target-mips: extract decode_opc_special* from decode_opc Leon Alrae
                   ` (25 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:53 UTC (permalink / raw)
  To: qemu-devel

The encoding of LL and SC instruction has changed in MIPS32 Release 6.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: James Hogan <james.hogan@imgtec.com>
---
 disas/mips.c            |  9 ++++++++-
 target-mips/translate.c | 28 ++++++++++++++++++++++++++--
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index b950e53..f0efa8b 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -119,6 +119,8 @@ see <http://www.gnu.org/licenses/>.  */
 #define OP_SH_IMMEDIATE		0
 #define OP_MASK_DELTA		0xffff
 #define OP_SH_DELTA		0
+#define OP_MASK_DELTA_R6        0x1ff
+#define OP_SH_DELTA_R6          7
 #define OP_MASK_FUNCT		0x3f
 #define OP_SH_FUNCT		0
 #define OP_MASK_SPEC		0x3f
@@ -1215,6 +1217,8 @@ const struct mips_opcode mips_builtin_opcodes[] =
    them first.  The assemblers uses a hash table based on the
    instruction name anyhow.  */
 /* name,    args,	match,	    mask,	pinfo,          	membership */
+{"ll",      "t,o(b)",   0x7c000036, 0xfc00007f, LDD|RD_b|WR_t,        0, I32R6},
+{"sc",      "t,o(b)",   0x7c000026, 0xfc00007f, LDD|RD_b|WR_t,        0, I32R6},
 {"seleqz",  "d,v,t",    0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"selnez",  "d,v,t",    0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	0,		I4|I32|G3	},
@@ -3734,7 +3738,10 @@ print_insn_args (const char *d,
 
 	case 'j': /* Same as i, but sign-extended.  */
 	case 'o':
-	  delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
+            delta = (opp->membership == I32R6) ?
+                (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6 :
+                (l >> OP_SH_DELTA) & OP_MASK_DELTA;
+
 	  if (delta & 0x8000)
 	    delta |= ~0xffff;
 	  (*info->fprintf_func) (info->stream, "%d",
diff --git a/target-mips/translate.c b/target-mips/translate.c
index ba9daac..8606f32 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -347,6 +347,10 @@ enum {
     /* MIPS DSP Accumulator and DSPControl Access Sub-class */
     OPC_EXTR_W_DSP     = 0x38 | OPC_SPECIAL3,
     OPC_DEXTR_W_DSP    = 0x3C | OPC_SPECIAL3,
+
+    /* R6 */
+    R6_OPC_LL          = 0x36 | OPC_SPECIAL3,
+    R6_OPC_SC          = 0x26 | OPC_SPECIAL3,
 };
 
 /* BSHFL opcodes */
@@ -1775,6 +1779,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
         opn = "lwr";
         break;
     case OPC_LL:
+    case R6_OPC_LL:
         save_cpu_state(ctx, 1);
         op_ld_ll(t0, t0, ctx);
         gen_store_gpr(t0, rt);
@@ -1868,6 +1873,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
         break;
 #endif
     case OPC_SC:
+    case R6_OPC_SC:
         save_cpu_state(ctx, 1);
         op_st_sc(t1, t0, rt, ctx);
         opn = "sc";
@@ -14804,6 +14810,10 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
     case OPC_SPECIAL3:
         op1 = MASK_SPECIAL3(ctx->opcode);
         switch (op1) {
+        case R6_OPC_LL:
+            check_insn(ctx, ISA_MIPS32R6);
+            gen_ld(ctx, op1, rt, rs, imm >> 7);
+            break;
         case OPC_EXT:
         case OPC_INS:
             check_insn(ctx, ISA_MIPS32R2);
@@ -15108,6 +15118,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
                 break;
             }
             break;
+        case R6_OPC_SC: /* OPC_DMOD_G_2E */
+            if (ctx->insn_flags & ISA_MIPS32R6) {
+                gen_st_cond(ctx, op1, rt, rs, imm >> 7);
+            } else {
+#if defined(TARGET_MIPS64)
+                check_insn(ctx, INSN_LOONGSON2E);
+                gen_loongson_integer(ctx, op1, rd, rs, rt);
+#else
+                /* Invalid in MIPS32 */
+                generate_exception(ctx, EXCP_RI);
+#endif
+            }
+            break;
 #if defined(TARGET_MIPS64)
         case OPC_DEXTM ... OPC_DEXT:
         case OPC_DINSM ... OPC_DINS:
@@ -15123,7 +15146,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
         case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
         case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
-        case OPC_DMOD_G_2E ... OPC_DMODU_G_2E:
+        case OPC_DMODU_G_2E:
             check_insn(ctx, INSN_LOONGSON2E);
             gen_loongson_integer(ctx, op1, rd, rs, rt);
             break;
@@ -15512,10 +15535,10 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          break;
     case OPC_LWL: /* Load and stores */
     case OPC_LWR:
+    case OPC_LL:
         check_insn_opc_removed(ctx, ISA_MIPS32R6);
     case OPC_LB ... OPC_LH:
     case OPC_LW ... OPC_LHU:
-    case OPC_LL:
          gen_ld(ctx, op, rt, rs, imm);
          break;
     case OPC_SWL:
@@ -15526,6 +15549,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          gen_st(ctx, op, rt, rs, imm);
          break;
     case OPC_SC:
+         check_insn_opc_removed(ctx, ISA_MIPS32R6);
          gen_st_cond(ctx, op, rt, rs, imm);
          break;
     case OPC_CACHE:
-- 
2.1.0

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

* [Qemu-devel] [PULL 05/28] target-mips: extract decode_opc_special* from decode_opc
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (3 preceding siblings ...)
  2014-10-15  9:53 ` [Qemu-devel] [PULL 04/28] target-mips: move LL and SC instructions Leon Alrae
@ 2014-10-15  9:53 ` Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 06/28] target-mips: split decode_opc_special* into *_r6 and *_legacy Leon Alrae
                   ` (24 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:53 UTC (permalink / raw)
  To: qemu-devel

Creating separate decode functions for special, special2 and special3
instructions to ease adding new R6 instructions and removing legacy
instructions.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-mips/translate.c | 1678 ++++++++++++++++++++++++-----------------------
 1 file changed, 859 insertions(+), 819 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 8606f32..5b8f762 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -14482,911 +14482,950 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2,
 
 /* End MIPSDSP functions. */
 
-static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
+static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
 {
-    int32_t offset;
     int rs, rt, rd, sa;
-    uint32_t op, op1, op2;
-    int16_t imm;
-
-    /* make sure instructions are on a word boundary */
-    if (ctx->pc & 0x3) {
-        env->CP0_BadVAddr = ctx->pc;
-        generate_exception(ctx, EXCP_AdEL);
-        return;
-    }
-
-    /* Handle blikely not taken case */
-    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);
-        tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
-        tcg_gen_movi_i32(hflags, ctx->hflags & ~MIPS_HFLAG_BMASK);
-        gen_goto_tb(ctx, 1, ctx->pc + 4);
-        gen_set_label(l1);
-    }
-
-    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
-        tcg_gen_debug_insn_start(ctx->pc);
-    }
+    uint32_t op1;
 
-    op = MASK_OP_MAJOR(ctx->opcode);
     rs = (ctx->opcode >> 21) & 0x1f;
     rt = (ctx->opcode >> 16) & 0x1f;
     rd = (ctx->opcode >> 11) & 0x1f;
     sa = (ctx->opcode >> 6) & 0x1f;
-    imm = (int16_t)ctx->opcode;
-    switch (op) {
-    case OPC_SPECIAL:
-        op1 = MASK_SPECIAL(ctx->opcode);
-        switch (op1) {
-        case OPC_SLL:          /* Shift with immediate */
-        case OPC_SRA:
-            gen_shift_imm(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 (ctx->insn_flags & ISA_MIPS32R2) {
-                    op1 = OPC_ROTR;
-                }
-                /* Fallthrough */
-            case 0:
-                gen_shift_imm(ctx, op1, rd, rt, sa);
-                break;
-            default:
-                generate_exception(ctx, EXCP_RI);
-                break;
+
+    op1 = MASK_SPECIAL(ctx->opcode);
+    switch (op1) {
+    case OPC_SLL:          /* Shift with immediate */
+    case OPC_SRA:
+        gen_shift_imm(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 (ctx->insn_flags & ISA_MIPS32R2) {
+                op1 = OPC_ROTR;
             }
+            /* Fallthrough */
+        case 0:
+            gen_shift_imm(ctx, op1, rd, rt, sa);
             break;
-        case OPC_MOVN:         /* Conditional move */
-        case OPC_MOVZ:
-            check_insn_opc_removed(ctx, ISA_MIPS32R6);
-            check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
-                                 INSN_LOONGSON2E | INSN_LOONGSON2F);
-            gen_cond_move(ctx, op1, rd, rs, rt);
-            break;
-        case OPC_SELEQZ:
-        case OPC_SELNEZ:
-            check_insn(ctx, ISA_MIPS32R6);
-            gen_cond_move(ctx, op1, rd, rs, rt);
-            break;
-        case OPC_ADD ... OPC_SUBU:
-            gen_arith(ctx, op1, rd, rs, rt);
-            break;
-        case OPC_SLLV:         /* Shifts */
-        case OPC_SRAV:
-            gen_shift(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 (ctx->insn_flags & ISA_MIPS32R2) {
-                    op1 = OPC_ROTRV;
-                }
-                /* Fallthrough */
-            case 0:
-                gen_shift(ctx, op1, rd, rs, rt);
-                break;
-            default:
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
+        default:
+            generate_exception(ctx, EXCP_RI);
             break;
-        case OPC_SLT:          /* Set on less than */
-        case OPC_SLTU:
-            gen_slt(ctx, op1, rd, rs, rt);
-            break;
-        case OPC_AND:          /* Logic*/
-        case OPC_OR:
-        case OPC_NOR:
-        case OPC_XOR:
-            gen_logic(ctx, op1, rd, rs, rt);
-            break;
-        case OPC_MULT:
-        case OPC_MULTU:
-            if (sa) {
-                check_insn(ctx, INSN_VR54XX);
-                op1 = MASK_MUL_VR54XX(ctx->opcode);
-                gen_mul_vr54xx(ctx, op1, rd, rs, rt);
-            } else {
-                gen_muldiv(ctx, op1, rd & 3, rs, rt);
+        }
+        break;
+    case OPC_MOVN:         /* Conditional move */
+    case OPC_MOVZ:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
+                   INSN_LOONGSON2E | INSN_LOONGSON2F);
+        gen_cond_move(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_SELEQZ:
+    case OPC_SELNEZ:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_cond_move(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_ADD ... OPC_SUBU:
+        gen_arith(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_SLLV:         /* Shifts */
+    case OPC_SRAV:
+        gen_shift(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 (ctx->insn_flags & ISA_MIPS32R2) {
+                op1 = OPC_ROTRV;
             }
+            /* Fallthrough */
+        case 0:
+            gen_shift(ctx, op1, rd, rs, rt);
             break;
-        case OPC_DIV:
-        case OPC_DIVU:
-            gen_muldiv(ctx, op1, 0, rs, rt);
-            break;
-        case OPC_JR ... OPC_JALR:
-            gen_compute_branch(ctx, op1, 4, rs, rd, sa);
-            break;
-        case OPC_TGE ... OPC_TEQ: /* Traps */
-        case OPC_TNE:
-            gen_trap(ctx, op1, rs, rt, -1);
-            break;
-        case OPC_MFHI:          /* Move from HI/LO */
-        case OPC_MFLO:
-            check_insn_opc_removed(ctx, ISA_MIPS32R6);
-            gen_HILO(ctx, op1, rs & 3, rd);
-            break;
-        case OPC_MTHI:
-        case OPC_MTLO:          /* Move to HI/LO */
-            check_insn_opc_removed(ctx, ISA_MIPS32R6);
-            gen_HILO(ctx, op1, rd & 3, rs);
+        default:
+            generate_exception(ctx, EXCP_RI);
             break;
-        case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
+        }
+        break;
+    case OPC_SLT:          /* Set on less than */
+    case OPC_SLTU:
+        gen_slt(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_AND:          /* Logic*/
+    case OPC_OR:
+    case OPC_NOR:
+    case OPC_XOR:
+        gen_logic(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_MULT:
+    case OPC_MULTU:
+        if (sa) {
+            check_insn(ctx, INSN_VR54XX);
+            op1 = MASK_MUL_VR54XX(ctx->opcode);
+            gen_mul_vr54xx(ctx, op1, rd, rs, rt);
+        } else {
+            gen_muldiv(ctx, op1, rd & 3, rs, rt);
+        }
+        break;
+    case OPC_DIV:
+    case OPC_DIVU:
+        gen_muldiv(ctx, op1, 0, rs, rt);
+        break;
+    case OPC_JR ... OPC_JALR:
+        gen_compute_branch(ctx, op1, 4, rs, rd, sa);
+        break;
+    case OPC_TGE ... OPC_TEQ: /* Traps */
+    case OPC_TNE:
+        gen_trap(ctx, op1, rs, rt, -1);
+        break;
+    case OPC_MFHI:          /* Move from HI/LO */
+    case OPC_MFLO:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        gen_HILO(ctx, op1, rs & 3, rd);
+        break;
+    case OPC_MTHI:
+    case OPC_MTLO:          /* Move to HI/LO */
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        gen_HILO(ctx, op1, rd & 3, rs);
+        break;
+    case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
 #ifdef MIPS_STRICT_STANDARD
-            MIPS_INVAL("PMON / selsl");
-            generate_exception(ctx, EXCP_RI);
+        MIPS_INVAL("PMON / selsl");
+        generate_exception(ctx, EXCP_RI);
 #else
-            gen_helper_0e0i(pmon, sa);
+        gen_helper_0e0i(pmon, sa);
 #endif
-            break;
-        case OPC_SYSCALL:
-            generate_exception(ctx, EXCP_SYSCALL);
-            ctx->bstate = BS_STOP;
-            break;
-        case OPC_BREAK:
-            generate_exception(ctx, EXCP_BREAK);
-            break;
-        case OPC_SPIM:
+        break;
+    case OPC_SYSCALL:
+        generate_exception(ctx, EXCP_SYSCALL);
+        ctx->bstate = BS_STOP;
+        break;
+    case OPC_BREAK:
+        generate_exception(ctx, EXCP_BREAK);
+        break;
+    case OPC_SPIM:
 #ifdef MIPS_STRICT_STANDARD
-            MIPS_INVAL("SPIM");
-            generate_exception(ctx, EXCP_RI);
+        MIPS_INVAL("SPIM");
+        generate_exception(ctx, EXCP_RI);
 #else
-           /* Implemented as RI exception for now. */
-            MIPS_INVAL("spim (unofficial)");
-            generate_exception(ctx, EXCP_RI);
+        /* Implemented as RI exception for now. */
+        MIPS_INVAL("spim (unofficial)");
+        generate_exception(ctx, EXCP_RI);
 #endif
-            break;
-        case OPC_SYNC:
-            /* Treat as NOP. */
-            break;
+        break;
+    case OPC_SYNC:
+        /* Treat as NOP. */
+        break;
 
-        case OPC_MOVCI:
-            check_insn_opc_removed(ctx, ISA_MIPS32R6);
-            check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
-            if (ctx->CP0_Config1 & (1 << CP0C1_FP)) {
-                check_cp1_enabled(ctx);
-                gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
-                          (ctx->opcode >> 16) & 1);
-            } else {
-                generate_exception_err(ctx, EXCP_CpU, 1);
-            }
-            break;
+    case OPC_MOVCI:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
+        if (ctx->CP0_Config1 & (1 << CP0C1_FP)) {
+            check_cp1_enabled(ctx);
+            gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+                      (ctx->opcode >> 16) & 1);
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
+        }
+        break;
 
 #if defined(TARGET_MIPS64)
-       /* MIPS64 specific opcodes */
-        case OPC_DSLL:
-        case OPC_DSRA:
-        case OPC_DSLL32:
-        case OPC_DSRA32:
-            check_insn(ctx, ISA_MIPS3);
-            check_mips_64(ctx);
-            gen_shift_imm(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 (ctx->insn_flags & ISA_MIPS32R2) {
-                    op1 = OPC_DROTR;
-                }
-                /* Fallthrough */
-            case 0:
-                check_insn(ctx, ISA_MIPS3);
-                check_mips_64(ctx);
-                gen_shift_imm(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 (ctx->insn_flags & ISA_MIPS32R2) {
-                    op1 = OPC_DROTR32;
-                }
-                /* Fallthrough */
-            case 0:
-                check_insn(ctx, ISA_MIPS3);
-                check_mips_64(ctx);
-                gen_shift_imm(ctx, op1, rd, rt, sa);
-                break;
-            default:
-                generate_exception(ctx, EXCP_RI);
-                break;
+        /* MIPS64 specific opcodes */
+    case OPC_DSLL:
+    case OPC_DSRA:
+    case OPC_DSLL32:
+    case OPC_DSRA32:
+        check_insn(ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_shift_imm(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 (ctx->insn_flags & ISA_MIPS32R2) {
+                op1 = OPC_DROTR;
             }
-            break;
-        case OPC_DADD ... OPC_DSUBU:
+            /* Fallthrough */
+        case 0:
             check_insn(ctx, ISA_MIPS3);
             check_mips_64(ctx);
-            gen_arith(ctx, op1, rd, rs, rt);
+            gen_shift_imm(ctx, op1, rd, rt, sa);
             break;
-        case OPC_DSLLV:
-        case OPC_DSRAV:
-            check_insn(ctx, ISA_MIPS3);
-            check_mips_64(ctx);
-            gen_shift(ctx, op1, rd, rs, rt);
+        default:
+            generate_exception(ctx, EXCP_RI);
             break;
-        case OPC_DSRLV:
-            switch ((ctx->opcode >> 6) & 0x1f) {
-            case 1:
-                /* drotrv is decoded as dsrlv on non-R2 CPUs */
-                if (ctx->insn_flags & ISA_MIPS32R2) {
-                    op1 = OPC_DROTRV;
-                }
-                /* Fallthrough */
-            case 0:
-                check_insn(ctx, ISA_MIPS3);
-                check_mips_64(ctx);
-                gen_shift(ctx, op1, rd, rs, rt);
-                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 (ctx->insn_flags & ISA_MIPS32R2) {
+                op1 = OPC_DROTR32;
             }
-            break;
-        case OPC_DMULT ... OPC_DDIVU:
+            /* Fallthrough */
+        case 0:
             check_insn(ctx, ISA_MIPS3);
             check_mips_64(ctx);
-            gen_muldiv(ctx, op1, 0, rs, rt);
+            gen_shift_imm(ctx, op1, rd, rt, sa);
             break;
-#endif
-        default:            /* Invalid */
-            MIPS_INVAL("special");
+        default:
             generate_exception(ctx, EXCP_RI);
             break;
         }
         break;
-    case OPC_SPECIAL2:
-        op1 = MASK_SPECIAL2(ctx->opcode);
-        switch (op1) {
-        case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
-        case OPC_MSUB ... OPC_MSUBU:
-            check_insn_opc_removed(ctx, ISA_MIPS32R6);
-            check_insn(ctx, ISA_MIPS32);
-            gen_muldiv(ctx, op1, rd & 3, rs, rt);
-            break;
-        case OPC_MUL:
-            check_insn_opc_removed(ctx, ISA_MIPS32R6);
-            gen_arith(ctx, op1, rd, rs, rt);
-            break;
-        case OPC_CLO:
-        case OPC_CLZ:
-            check_insn(ctx, ISA_MIPS32);
-            gen_cl(ctx, op1, rd, rs);
-            break;
-        case OPC_SDBBP:
-            /* XXX: not clear which exception should be raised
-             *      when in debug mode...
-             */
-            check_insn(ctx, ISA_MIPS32);
-            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
-                generate_exception(ctx, EXCP_DBp);
-            } else {
-                generate_exception(ctx, EXCP_DBp);
+    case OPC_DADD ... OPC_DSUBU:
+        check_insn(ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_arith(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_DSLLV:
+    case OPC_DSRAV:
+        check_insn(ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_shift(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 (ctx->insn_flags & ISA_MIPS32R2) {
+                op1 = OPC_DROTRV;
             }
-            /* Treat as NOP. */
-            break;
-        case OPC_DIV_G_2F:
-        case OPC_DIVU_G_2F:
-        case OPC_MULT_G_2F:
-        case OPC_MULTU_G_2F:
-        case OPC_MOD_G_2F:
-        case OPC_MODU_G_2F:
-            check_insn(ctx, INSN_LOONGSON2F);
-            gen_loongson_integer(ctx, op1, rd, rs, rt);
-            break;
-#if defined(TARGET_MIPS64)
-        case OPC_DCLO:
-        case OPC_DCLZ:
-            check_insn(ctx, ISA_MIPS64);
+            /* Fallthrough */
+        case 0:
+            check_insn(ctx, ISA_MIPS3);
             check_mips_64(ctx);
-            gen_cl(ctx, op1, rd, rs);
-            break;
-        case OPC_DMULT_G_2F:
-        case OPC_DMULTU_G_2F:
-        case OPC_DDIV_G_2F:
-        case OPC_DDIVU_G_2F:
-        case OPC_DMOD_G_2F:
-        case OPC_DMODU_G_2F:
-            check_insn(ctx, INSN_LOONGSON2F);
-            gen_loongson_integer(ctx, op1, rd, rs, rt);
+            gen_shift(ctx, op1, rd, rs, rt);
             break;
-#endif
-        default:            /* Invalid */
-            MIPS_INVAL("special2");
+        default:
             generate_exception(ctx, EXCP_RI);
             break;
         }
         break;
-    case OPC_SPECIAL3:
-        op1 = MASK_SPECIAL3(ctx->opcode);
-        switch (op1) {
-        case R6_OPC_LL:
-            check_insn(ctx, ISA_MIPS32R6);
-            gen_ld(ctx, op1, rt, rs, imm >> 7);
-            break;
-        case OPC_EXT:
-        case OPC_INS:
-            check_insn(ctx, ISA_MIPS32R2);
-            gen_bitops(ctx, op1, rt, rs, sa, rd);
-            break;
-        case OPC_BSHFL:
-            check_insn(ctx, ISA_MIPS32R2);
-            op2 = MASK_BSHFL(ctx->opcode);
-            gen_bshfl(ctx, op2, rt, rd);
-            break;
-        case OPC_RDHWR:
-            gen_rdhwr(ctx, rt, rd);
-            break;
-        case OPC_FORK:
-            check_insn(ctx, ASE_MT);
-            {
-                TCGv t0 = tcg_temp_new();
-                TCGv t1 = tcg_temp_new();
+    case OPC_DMULT ... OPC_DDIVU:
+        check_insn(ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_muldiv(ctx, op1, 0, rs, rt);
+        break;
+#endif
+    default:            /* Invalid */
+        MIPS_INVAL("special");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
 
-                gen_load_gpr(t0, rt);
-                gen_load_gpr(t1, rs);
-                gen_helper_fork(t0, t1);
-                tcg_temp_free(t0);
-                tcg_temp_free(t1);
-            }
-            break;
-        case OPC_YIELD:
-            check_insn(ctx, ASE_MT);
-            {
-                TCGv t0 = tcg_temp_new();
+static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
+{
+    int rs, rt, rd;
+    uint32_t op1;
 
-                save_cpu_state(ctx, 1);
-                gen_load_gpr(t0, rs);
-                gen_helper_yield(t0, cpu_env, t0);
-                gen_store_gpr(t0, rd);
-                tcg_temp_free(t0);
-            }
-            break;
-        case OPC_DIV_G_2E ... OPC_DIVU_G_2E:
-        case OPC_MOD_G_2E ... OPC_MODU_G_2E:
-        case OPC_MULT_G_2E ... OPC_MULTU_G_2E:
-        /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
-         * the same mask and op1. */
-            if ((ctx->insn_flags & ASE_DSPR2) && (op1 == OPC_MULT_G_2E)) {
-                op2 = MASK_ADDUH_QB(ctx->opcode);
-                switch (op2) {
-                case OPC_ADDUH_QB:
-                case OPC_ADDUH_R_QB:
-                case OPC_ADDQH_PH:
-                case OPC_ADDQH_R_PH:
-                case OPC_ADDQH_W:
-                case OPC_ADDQH_R_W:
-                case OPC_SUBUH_QB:
-                case OPC_SUBUH_R_QB:
-                case OPC_SUBQH_PH:
-                case OPC_SUBQH_R_PH:
-                case OPC_SUBQH_W:
-                case OPC_SUBQH_R_W:
-                    gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
-                    break;
-                case OPC_MUL_PH:
-                case OPC_MUL_S_PH:
-                case OPC_MULQ_S_W:
-                case OPC_MULQ_RS_W:
-                    gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
-                    break;
-                default:
-                    MIPS_INVAL("MASK ADDUH.QB");
-                    generate_exception(ctx, EXCP_RI);
-                    break;
-                }
-            } else if (ctx->insn_flags & INSN_LOONGSON2E) {
-                gen_loongson_integer(ctx, op1, rd, rs, rt);
-            } else {
-                generate_exception(ctx, EXCP_RI);
-            }
-            break;
-        case OPC_LX_DSP:
-            op2 = MASK_LX(ctx->opcode);
-            switch (op2) {
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+
+    op1 = MASK_SPECIAL2(ctx->opcode);
+    switch (op1) {
+    case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
+    case OPC_MSUB ... OPC_MSUBU:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        check_insn(ctx, ISA_MIPS32);
+        gen_muldiv(ctx, op1, rd & 3, rs, rt);
+        break;
+    case OPC_MUL:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        gen_arith(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_CLO:
+    case OPC_CLZ:
+        check_insn(ctx, ISA_MIPS32);
+        gen_cl(ctx, op1, rd, rs);
+        break;
+    case OPC_SDBBP:
+        /* XXX: not clear which exception should be raised
+         *      when in debug mode...
+         */
+        check_insn(ctx, ISA_MIPS32);
+        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+            generate_exception(ctx, EXCP_DBp);
+        } else {
+            generate_exception(ctx, EXCP_DBp);
+        }
+        /* Treat as NOP. */
+        break;
+    case OPC_DIV_G_2F:
+    case OPC_DIVU_G_2F:
+    case OPC_MULT_G_2F:
+    case OPC_MULTU_G_2F:
+    case OPC_MOD_G_2F:
+    case OPC_MODU_G_2F:
+        check_insn(ctx, INSN_LOONGSON2F);
+        gen_loongson_integer(ctx, op1, rd, rs, rt);
+        break;
 #if defined(TARGET_MIPS64)
-            case OPC_LDX:
+    case OPC_DCLO:
+    case OPC_DCLZ:
+        check_insn(ctx, ISA_MIPS64);
+        check_mips_64(ctx);
+        gen_cl(ctx, op1, rd, rs);
+        break;
+    case OPC_DMULT_G_2F:
+    case OPC_DMULTU_G_2F:
+    case OPC_DDIV_G_2F:
+    case OPC_DDIVU_G_2F:
+    case OPC_DMOD_G_2F:
+    case OPC_DMODU_G_2F:
+        check_insn(ctx, INSN_LOONGSON2F);
+        gen_loongson_integer(ctx, op1, rd, rs, rt);
+        break;
 #endif
-            case OPC_LBUX:
-            case OPC_LHX:
-            case OPC_LWX:
-                gen_mipsdsp_ld(ctx, op2, rd, rs, rt);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK LX");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
-            break;
-        case OPC_ABSQ_S_PH_DSP:
-            op2 = MASK_ABSQ_S_PH(ctx->opcode);
+    default:            /* Invalid */
+        MIPS_INVAL("special2");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
+{
+    int rs, rt, rd, sa;
+    uint32_t op1, op2;
+    int16_t imm;
+
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 6) & 0x1f;
+    imm = (int16_t)ctx->opcode;
+
+    op1 = MASK_SPECIAL3(ctx->opcode);
+    switch (op1) {
+    case R6_OPC_LL:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_ld(ctx, op1, rt, rs, imm >> 7);
+        break;
+    case OPC_EXT:
+    case OPC_INS:
+        check_insn(ctx, ISA_MIPS32R2);
+        gen_bitops(ctx, op1, rt, rs, sa, rd);
+        break;
+    case OPC_BSHFL:
+        check_insn(ctx, ISA_MIPS32R2);
+        op2 = MASK_BSHFL(ctx->opcode);
+        gen_bshfl(ctx, op2, rt, rd);
+        break;
+    case OPC_RDHWR:
+        gen_rdhwr(ctx, rt, rd);
+        break;
+    case OPC_FORK:
+        check_insn(ctx, ASE_MT);
+        {
+            TCGv t0 = tcg_temp_new();
+            TCGv t1 = tcg_temp_new();
+
+            gen_load_gpr(t0, rt);
+            gen_load_gpr(t1, rs);
+            gen_helper_fork(t0, t1);
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+        }
+        break;
+    case OPC_YIELD:
+        check_insn(ctx, ASE_MT);
+        {
+            TCGv t0 = tcg_temp_new();
+
+            save_cpu_state(ctx, 1);
+            gen_load_gpr(t0, rs);
+            gen_helper_yield(t0, cpu_env, t0);
+            gen_store_gpr(t0, rd);
+            tcg_temp_free(t0);
+        }
+        break;
+    case OPC_DIV_G_2E ... OPC_DIVU_G_2E:
+    case OPC_MOD_G_2E ... OPC_MODU_G_2E:
+    case OPC_MULT_G_2E ... OPC_MULTU_G_2E:
+        /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
+         * the same mask and op1. */
+        if ((ctx->insn_flags & ASE_DSPR2) && (op1 == OPC_MULT_G_2E)) {
+            op2 = MASK_ADDUH_QB(ctx->opcode);
             switch (op2) {
-            case OPC_ABSQ_S_QB:
-            case OPC_ABSQ_S_PH:
-            case OPC_ABSQ_S_W:
-            case OPC_PRECEQ_W_PHL:
-            case OPC_PRECEQ_W_PHR:
-            case OPC_PRECEQU_PH_QBL:
-            case OPC_PRECEQU_PH_QBR:
-            case OPC_PRECEQU_PH_QBLA:
-            case OPC_PRECEQU_PH_QBRA:
-            case OPC_PRECEU_PH_QBL:
-            case OPC_PRECEU_PH_QBR:
-            case OPC_PRECEU_PH_QBLA:
-            case OPC_PRECEU_PH_QBRA:
+            case OPC_ADDUH_QB:
+            case OPC_ADDUH_R_QB:
+            case OPC_ADDQH_PH:
+            case OPC_ADDQH_R_PH:
+            case OPC_ADDQH_W:
+            case OPC_ADDQH_R_W:
+            case OPC_SUBUH_QB:
+            case OPC_SUBUH_R_QB:
+            case OPC_SUBQH_PH:
+            case OPC_SUBQH_R_PH:
+            case OPC_SUBQH_W:
+            case OPC_SUBQH_R_W:
                 gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
                 break;
-            case OPC_BITREV:
-            case OPC_REPL_QB:
-            case OPC_REPLV_QB:
-            case OPC_REPL_PH:
-            case OPC_REPLV_PH:
-                gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt);
+            case OPC_MUL_PH:
+            case OPC_MUL_S_PH:
+            case OPC_MULQ_S_W:
+            case OPC_MULQ_RS_W:
+                gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
                 break;
             default:
-                MIPS_INVAL("MASK ABSQ_S.PH");
+                MIPS_INVAL("MASK ADDUH.QB");
                 generate_exception(ctx, EXCP_RI);
                 break;
             }
+        } else if (ctx->insn_flags & INSN_LOONGSON2E) {
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+        } else {
+            generate_exception(ctx, EXCP_RI);
+        }
+        break;
+    case OPC_LX_DSP:
+        op2 = MASK_LX(ctx->opcode);
+        switch (op2) {
+#if defined(TARGET_MIPS64)
+        case OPC_LDX:
+#endif
+        case OPC_LBUX:
+        case OPC_LHX:
+        case OPC_LWX:
+            gen_mipsdsp_ld(ctx, op2, rd, rs, rt);
+            break;
+        default:            /* Invalid */
+            MIPS_INVAL("MASK LX");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_ABSQ_S_PH_DSP:
+        op2 = MASK_ABSQ_S_PH(ctx->opcode);
+        switch (op2) {
+        case OPC_ABSQ_S_QB:
+        case OPC_ABSQ_S_PH:
+        case OPC_ABSQ_S_W:
+        case OPC_PRECEQ_W_PHL:
+        case OPC_PRECEQ_W_PHR:
+        case OPC_PRECEQU_PH_QBL:
+        case OPC_PRECEQU_PH_QBR:
+        case OPC_PRECEQU_PH_QBLA:
+        case OPC_PRECEQU_PH_QBRA:
+        case OPC_PRECEU_PH_QBL:
+        case OPC_PRECEU_PH_QBR:
+        case OPC_PRECEU_PH_QBLA:
+        case OPC_PRECEU_PH_QBRA:
+            gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
+            break;
+        case OPC_BITREV:
+        case OPC_REPL_QB:
+        case OPC_REPLV_QB:
+        case OPC_REPL_PH:
+        case OPC_REPLV_PH:
+            gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt);
+            break;
+        default:
+            MIPS_INVAL("MASK ABSQ_S.PH");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_ADDU_QB_DSP:
+        op2 = MASK_ADDU_QB(ctx->opcode);
+        switch (op2) {
+        case OPC_ADDQ_PH:
+        case OPC_ADDQ_S_PH:
+        case OPC_ADDQ_S_W:
+        case OPC_ADDU_QB:
+        case OPC_ADDU_S_QB:
+        case OPC_ADDU_PH:
+        case OPC_ADDU_S_PH:
+        case OPC_SUBQ_PH:
+        case OPC_SUBQ_S_PH:
+        case OPC_SUBQ_S_W:
+        case OPC_SUBU_QB:
+        case OPC_SUBU_S_QB:
+        case OPC_SUBU_PH:
+        case OPC_SUBU_S_PH:
+        case OPC_ADDSC:
+        case OPC_ADDWC:
+        case OPC_MODSUB:
+        case OPC_RADDU_W_QB:
+            gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
+            break;
+        case OPC_MULEU_S_PH_QBL:
+        case OPC_MULEU_S_PH_QBR:
+        case OPC_MULQ_RS_PH:
+        case OPC_MULEQ_S_W_PHL:
+        case OPC_MULEQ_S_W_PHR:
+        case OPC_MULQ_S_PH:
+            gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
+            break;
+        default:            /* Invalid */
+            MIPS_INVAL("MASK ADDU.QB");
+            generate_exception(ctx, EXCP_RI);
             break;
-        case OPC_ADDU_QB_DSP:
-            op2 = MASK_ADDU_QB(ctx->opcode);
-            switch (op2) {
-            case OPC_ADDQ_PH:
-            case OPC_ADDQ_S_PH:
-            case OPC_ADDQ_S_W:
-            case OPC_ADDU_QB:
-            case OPC_ADDU_S_QB:
-            case OPC_ADDU_PH:
-            case OPC_ADDU_S_PH:
-            case OPC_SUBQ_PH:
-            case OPC_SUBQ_S_PH:
-            case OPC_SUBQ_S_W:
-            case OPC_SUBU_QB:
-            case OPC_SUBU_S_QB:
-            case OPC_SUBU_PH:
-            case OPC_SUBU_S_PH:
-            case OPC_ADDSC:
-            case OPC_ADDWC:
-            case OPC_MODSUB:
-            case OPC_RADDU_W_QB:
-                gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
-                break;
-            case OPC_MULEU_S_PH_QBL:
-            case OPC_MULEU_S_PH_QBR:
-            case OPC_MULQ_RS_PH:
-            case OPC_MULEQ_S_W_PHL:
-            case OPC_MULEQ_S_W_PHR:
-            case OPC_MULQ_S_PH:
-                gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK ADDU.QB");
-                generate_exception(ctx, EXCP_RI);
-                break;
 
-            }
+        }
+        break;
+    case OPC_CMPU_EQ_QB_DSP:
+        op2 = MASK_CMPU_EQ_QB(ctx->opcode);
+        switch (op2) {
+        case OPC_PRECR_SRA_PH_W:
+        case OPC_PRECR_SRA_R_PH_W:
+            gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd);
             break;
-        case OPC_CMPU_EQ_QB_DSP:
-            op2 = MASK_CMPU_EQ_QB(ctx->opcode);
-            switch (op2) {
-            case OPC_PRECR_SRA_PH_W:
-            case OPC_PRECR_SRA_R_PH_W:
-                gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd);
-                break;
-            case OPC_PRECR_QB_PH:
-            case OPC_PRECRQ_QB_PH:
-            case OPC_PRECRQ_PH_W:
-            case OPC_PRECRQ_RS_PH_W:
-            case OPC_PRECRQU_S_QB_PH:
-                gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
-                break;
-            case OPC_CMPU_EQ_QB:
-            case OPC_CMPU_LT_QB:
-            case OPC_CMPU_LE_QB:
-            case OPC_CMP_EQ_PH:
-            case OPC_CMP_LT_PH:
-            case OPC_CMP_LE_PH:
-                gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0);
-                break;
-            case OPC_CMPGU_EQ_QB:
-            case OPC_CMPGU_LT_QB:
-            case OPC_CMPGU_LE_QB:
-            case OPC_CMPGDU_EQ_QB:
-            case OPC_CMPGDU_LT_QB:
-            case OPC_CMPGDU_LE_QB:
-            case OPC_PICK_QB:
-            case OPC_PICK_PH:
-            case OPC_PACKRL_PH:
-                gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK CMPU.EQ.QB");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
+        case OPC_PRECR_QB_PH:
+        case OPC_PRECRQ_QB_PH:
+        case OPC_PRECRQ_PH_W:
+        case OPC_PRECRQ_RS_PH_W:
+        case OPC_PRECRQU_S_QB_PH:
+            gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
             break;
-        case OPC_SHLL_QB_DSP:
-            gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+        case OPC_CMPU_EQ_QB:
+        case OPC_CMPU_LT_QB:
+        case OPC_CMPU_LE_QB:
+        case OPC_CMP_EQ_PH:
+        case OPC_CMP_LT_PH:
+        case OPC_CMP_LE_PH:
+            gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0);
             break;
-        case OPC_DPA_W_PH_DSP:
-            op2 = MASK_DPA_W_PH(ctx->opcode);
-            switch (op2) {
-            case OPC_DPAU_H_QBL:
-            case OPC_DPAU_H_QBR:
-            case OPC_DPSU_H_QBL:
-            case OPC_DPSU_H_QBR:
-            case OPC_DPA_W_PH:
-            case OPC_DPAX_W_PH:
-            case OPC_DPAQ_S_W_PH:
-            case OPC_DPAQX_S_W_PH:
-            case OPC_DPAQX_SA_W_PH:
-            case OPC_DPS_W_PH:
-            case OPC_DPSX_W_PH:
-            case OPC_DPSQ_S_W_PH:
-            case OPC_DPSQX_S_W_PH:
-            case OPC_DPSQX_SA_W_PH:
-            case OPC_MULSAQ_S_W_PH:
-            case OPC_DPAQ_SA_L_W:
-            case OPC_DPSQ_SA_L_W:
-            case OPC_MAQ_S_W_PHL:
-            case OPC_MAQ_S_W_PHR:
-            case OPC_MAQ_SA_W_PHL:
-            case OPC_MAQ_SA_W_PHR:
-            case OPC_MULSA_W_PH:
-                gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK DPAW.PH");
-                generate_exception(ctx, EXCP_RI);
+        case OPC_CMPGU_EQ_QB:
+        case OPC_CMPGU_LT_QB:
+        case OPC_CMPGU_LE_QB:
+        case OPC_CMPGDU_EQ_QB:
+        case OPC_CMPGDU_LT_QB:
+        case OPC_CMPGDU_LE_QB:
+        case OPC_PICK_QB:
+        case OPC_PICK_PH:
+        case OPC_PACKRL_PH:
+            gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1);
+            break;
+        default:            /* Invalid */
+            MIPS_INVAL("MASK CMPU.EQ.QB");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_SHLL_QB_DSP:
+        gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_DPA_W_PH_DSP:
+        op2 = MASK_DPA_W_PH(ctx->opcode);
+        switch (op2) {
+        case OPC_DPAU_H_QBL:
+        case OPC_DPAU_H_QBR:
+        case OPC_DPSU_H_QBL:
+        case OPC_DPSU_H_QBR:
+        case OPC_DPA_W_PH:
+        case OPC_DPAX_W_PH:
+        case OPC_DPAQ_S_W_PH:
+        case OPC_DPAQX_S_W_PH:
+        case OPC_DPAQX_SA_W_PH:
+        case OPC_DPS_W_PH:
+        case OPC_DPSX_W_PH:
+        case OPC_DPSQ_S_W_PH:
+        case OPC_DPSQX_S_W_PH:
+        case OPC_DPSQX_SA_W_PH:
+        case OPC_MULSAQ_S_W_PH:
+        case OPC_DPAQ_SA_L_W:
+        case OPC_DPSQ_SA_L_W:
+        case OPC_MAQ_S_W_PHL:
+        case OPC_MAQ_S_W_PHR:
+        case OPC_MAQ_SA_W_PHL:
+        case OPC_MAQ_SA_W_PHR:
+        case OPC_MULSA_W_PH:
+            gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
+            break;
+        default:            /* Invalid */
+            MIPS_INVAL("MASK DPAW.PH");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_INSV_DSP:
+        op2 = MASK_INSV(ctx->opcode);
+        switch (op2) {
+        case OPC_INSV:
+            check_dsp(ctx);
+            {
+                TCGv t0, t1;
+
+                if (rt == 0) {
+                    MIPS_DEBUG("NOP");
+                    break;
+                }
+
+                t0 = tcg_temp_new();
+                t1 = tcg_temp_new();
+
+                gen_load_gpr(t0, rt);
+                gen_load_gpr(t1, rs);
+
+                gen_helper_insv(cpu_gpr[rt], cpu_env, t1, t0);
+
+                tcg_temp_free(t0);
+                tcg_temp_free(t1);
                 break;
             }
+        default:            /* Invalid */
+            MIPS_INVAL("MASK INSV");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_APPEND_DSP:
+        gen_mipsdsp_append(env, ctx, op1, rt, rs, rd);
+        break;
+    case OPC_EXTR_W_DSP:
+        op2 = MASK_EXTR_W(ctx->opcode);
+        switch (op2) {
+        case OPC_EXTR_W:
+        case OPC_EXTR_R_W:
+        case OPC_EXTR_RS_W:
+        case OPC_EXTR_S_H:
+        case OPC_EXTRV_S_H:
+        case OPC_EXTRV_W:
+        case OPC_EXTRV_R_W:
+        case OPC_EXTRV_RS_W:
+        case OPC_EXTP:
+        case OPC_EXTPV:
+        case OPC_EXTPDP:
+        case OPC_EXTPDPV:
+            gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
+            break;
+        case OPC_RDDSP:
+            gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 1);
+            break;
+        case OPC_SHILO:
+        case OPC_SHILOV:
+        case OPC_MTHLIP:
+        case OPC_WRDSP:
+            gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
+            break;
+        default:            /* Invalid */
+            MIPS_INVAL("MASK EXTR.W");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case R6_OPC_SC: /* OPC_DMOD_G_2E */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            gen_st_cond(ctx, op1, rt, rs, imm >> 7);
+        } else {
+#if defined(TARGET_MIPS64)
+            check_insn(ctx, INSN_LOONGSON2E);
+            gen_loongson_integer(ctx, op1, rd, rs, rt);
+#else
+            /* Invalid in MIPS32 */
+            generate_exception(ctx, EXCP_RI);
+#endif
+        }
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DEXTM ... OPC_DEXT:
+    case OPC_DINSM ... OPC_DINS:
+        check_insn(ctx, ISA_MIPS64R2);
+        check_mips_64(ctx);
+        gen_bitops(ctx, op1, rt, rs, sa, rd);
+        break;
+    case OPC_DBSHFL:
+        check_insn(ctx, ISA_MIPS64R2);
+        check_mips_64(ctx);
+        op2 = MASK_DBSHFL(ctx->opcode);
+        gen_bshfl(ctx, op2, rt, rd);
+        break;
+    case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
+    case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
+    case OPC_DMODU_G_2E:
+        check_insn(ctx, INSN_LOONGSON2E);
+        gen_loongson_integer(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_ABSQ_S_QH_DSP:
+        op2 = MASK_ABSQ_S_QH(ctx->opcode);
+        switch (op2) {
+        case OPC_PRECEQ_L_PWL:
+        case OPC_PRECEQ_L_PWR:
+        case OPC_PRECEQ_PW_QHL:
+        case OPC_PRECEQ_PW_QHR:
+        case OPC_PRECEQ_PW_QHLA:
+        case OPC_PRECEQ_PW_QHRA:
+        case OPC_PRECEQU_QH_OBL:
+        case OPC_PRECEQU_QH_OBR:
+        case OPC_PRECEQU_QH_OBLA:
+        case OPC_PRECEQU_QH_OBRA:
+        case OPC_PRECEU_QH_OBL:
+        case OPC_PRECEU_QH_OBR:
+        case OPC_PRECEU_QH_OBLA:
+        case OPC_PRECEU_QH_OBRA:
+        case OPC_ABSQ_S_OB:
+        case OPC_ABSQ_S_PW:
+        case OPC_ABSQ_S_QH:
+            gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
+            break;
+        case OPC_REPL_OB:
+        case OPC_REPL_PW:
+        case OPC_REPL_QH:
+        case OPC_REPLV_OB:
+        case OPC_REPLV_PW:
+        case OPC_REPLV_QH:
+            gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt);
+            break;
+        default:            /* Invalid */
+            MIPS_INVAL("MASK ABSQ_S.QH");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_ADDU_OB_DSP:
+        op2 = MASK_ADDU_OB(ctx->opcode);
+        switch (op2) {
+        case OPC_RADDU_L_OB:
+        case OPC_SUBQ_PW:
+        case OPC_SUBQ_S_PW:
+        case OPC_SUBQ_QH:
+        case OPC_SUBQ_S_QH:
+        case OPC_SUBU_OB:
+        case OPC_SUBU_S_OB:
+        case OPC_SUBU_QH:
+        case OPC_SUBU_S_QH:
+        case OPC_SUBUH_OB:
+        case OPC_SUBUH_R_OB:
+        case OPC_ADDQ_PW:
+        case OPC_ADDQ_S_PW:
+        case OPC_ADDQ_QH:
+        case OPC_ADDQ_S_QH:
+        case OPC_ADDU_OB:
+        case OPC_ADDU_S_OB:
+        case OPC_ADDU_QH:
+        case OPC_ADDU_S_QH:
+        case OPC_ADDUH_OB:
+        case OPC_ADDUH_R_OB:
+            gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
             break;
-        case OPC_INSV_DSP:
-            op2 = MASK_INSV(ctx->opcode);
-            switch (op2) {
-            case OPC_INSV:
-                check_dsp(ctx);
-                {
-                    TCGv t0, t1;
-
-                    if (rt == 0) {
-                        MIPS_DEBUG("NOP");
-                        break;
-                    }
-
-                    t0 = tcg_temp_new();
-                    t1 = tcg_temp_new();
-
-                    gen_load_gpr(t0, rt);
-                    gen_load_gpr(t1, rs);
-
-                    gen_helper_insv(cpu_gpr[rt], cpu_env, t1, t0);
-
-                    tcg_temp_free(t0);
-                    tcg_temp_free(t1);
-                    break;
-                }
-            default:            /* Invalid */
-                MIPS_INVAL("MASK INSV");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
+        case OPC_MULEQ_S_PW_QHL:
+        case OPC_MULEQ_S_PW_QHR:
+        case OPC_MULEU_S_QH_OBL:
+        case OPC_MULEU_S_QH_OBR:
+        case OPC_MULQ_RS_QH:
+            gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
             break;
-        case OPC_APPEND_DSP:
-            gen_mipsdsp_append(env, ctx, op1, rt, rs, rd);
+        default:            /* Invalid */
+            MIPS_INVAL("MASK ADDU.OB");
+            generate_exception(ctx, EXCP_RI);
             break;
-        case OPC_EXTR_W_DSP:
-            op2 = MASK_EXTR_W(ctx->opcode);
-            switch (op2) {
-            case OPC_EXTR_W:
-            case OPC_EXTR_R_W:
-            case OPC_EXTR_RS_W:
-            case OPC_EXTR_S_H:
-            case OPC_EXTRV_S_H:
-            case OPC_EXTRV_W:
-            case OPC_EXTRV_R_W:
-            case OPC_EXTRV_RS_W:
-            case OPC_EXTP:
-            case OPC_EXTPV:
-            case OPC_EXTPDP:
-            case OPC_EXTPDPV:
-                gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
-                break;
-            case OPC_RDDSP:
-                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 1);
-                break;
-            case OPC_SHILO:
-            case OPC_SHILOV:
-            case OPC_MTHLIP:
-            case OPC_WRDSP:
-                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK EXTR.W");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
+        }
+        break;
+    case OPC_CMPU_EQ_OB_DSP:
+        op2 = MASK_CMPU_EQ_OB(ctx->opcode);
+        switch (op2) {
+        case OPC_PRECR_SRA_QH_PW:
+        case OPC_PRECR_SRA_R_QH_PW:
+            /* Return value is rt. */
+            gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd);
             break;
-        case R6_OPC_SC: /* OPC_DMOD_G_2E */
-            if (ctx->insn_flags & ISA_MIPS32R6) {
-                gen_st_cond(ctx, op1, rt, rs, imm >> 7);
-            } else {
-#if defined(TARGET_MIPS64)
-                check_insn(ctx, INSN_LOONGSON2E);
-                gen_loongson_integer(ctx, op1, rd, rs, rt);
-#else
-                /* Invalid in MIPS32 */
-                generate_exception(ctx, EXCP_RI);
-#endif
-            }
+        case OPC_PRECR_OB_QH:
+        case OPC_PRECRQ_OB_QH:
+        case OPC_PRECRQ_PW_L:
+        case OPC_PRECRQ_QH_PW:
+        case OPC_PRECRQ_RS_QH_PW:
+        case OPC_PRECRQU_S_OB_QH:
+            gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
             break;
-#if defined(TARGET_MIPS64)
-        case OPC_DEXTM ... OPC_DEXT:
-        case OPC_DINSM ... OPC_DINS:
-            check_insn(ctx, ISA_MIPS64R2);
-            check_mips_64(ctx);
-            gen_bitops(ctx, op1, rt, rs, sa, rd);
+        case OPC_CMPU_EQ_OB:
+        case OPC_CMPU_LT_OB:
+        case OPC_CMPU_LE_OB:
+        case OPC_CMP_EQ_QH:
+        case OPC_CMP_LT_QH:
+        case OPC_CMP_LE_QH:
+        case OPC_CMP_EQ_PW:
+        case OPC_CMP_LT_PW:
+        case OPC_CMP_LE_PW:
+            gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0);
             break;
-        case OPC_DBSHFL:
-            check_insn(ctx, ISA_MIPS64R2);
-            check_mips_64(ctx);
-            op2 = MASK_DBSHFL(ctx->opcode);
-            gen_bshfl(ctx, op2, rt, rd);
+        case OPC_CMPGDU_EQ_OB:
+        case OPC_CMPGDU_LT_OB:
+        case OPC_CMPGDU_LE_OB:
+        case OPC_CMPGU_EQ_OB:
+        case OPC_CMPGU_LT_OB:
+        case OPC_CMPGU_LE_OB:
+        case OPC_PACKRL_PW:
+        case OPC_PICK_OB:
+        case OPC_PICK_PW:
+        case OPC_PICK_QH:
+            gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1);
             break;
-        case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
-        case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
-        case OPC_DMODU_G_2E:
-            check_insn(ctx, INSN_LOONGSON2E);
-            gen_loongson_integer(ctx, op1, rd, rs, rt);
+        default:            /* Invalid */
+            MIPS_INVAL("MASK CMPU_EQ.OB");
+            generate_exception(ctx, EXCP_RI);
             break;
-        case OPC_ABSQ_S_QH_DSP:
-            op2 = MASK_ABSQ_S_QH(ctx->opcode);
-            switch (op2) {
-            case OPC_PRECEQ_L_PWL:
-            case OPC_PRECEQ_L_PWR:
-            case OPC_PRECEQ_PW_QHL:
-            case OPC_PRECEQ_PW_QHR:
-            case OPC_PRECEQ_PW_QHLA:
-            case OPC_PRECEQ_PW_QHRA:
-            case OPC_PRECEQU_QH_OBL:
-            case OPC_PRECEQU_QH_OBR:
-            case OPC_PRECEQU_QH_OBLA:
-            case OPC_PRECEQU_QH_OBRA:
-            case OPC_PRECEU_QH_OBL:
-            case OPC_PRECEU_QH_OBR:
-            case OPC_PRECEU_QH_OBLA:
-            case OPC_PRECEU_QH_OBRA:
-            case OPC_ABSQ_S_OB:
-            case OPC_ABSQ_S_PW:
-            case OPC_ABSQ_S_QH:
-                gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
-                break;
-            case OPC_REPL_OB:
-            case OPC_REPL_PW:
-            case OPC_REPL_QH:
-            case OPC_REPLV_OB:
-            case OPC_REPLV_PW:
-            case OPC_REPLV_QH:
-                gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK ABSQ_S.QH");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
+        }
+        break;
+    case OPC_DAPPEND_DSP:
+        gen_mipsdsp_append(env, ctx, op1, rt, rs, rd);
+        break;
+    case OPC_DEXTR_W_DSP:
+        op2 = MASK_DEXTR_W(ctx->opcode);
+        switch (op2) {
+        case OPC_DEXTP:
+        case OPC_DEXTPDP:
+        case OPC_DEXTPDPV:
+        case OPC_DEXTPV:
+        case OPC_DEXTR_L:
+        case OPC_DEXTR_R_L:
+        case OPC_DEXTR_RS_L:
+        case OPC_DEXTR_W:
+        case OPC_DEXTR_R_W:
+        case OPC_DEXTR_RS_W:
+        case OPC_DEXTR_S_H:
+        case OPC_DEXTRV_L:
+        case OPC_DEXTRV_R_L:
+        case OPC_DEXTRV_RS_L:
+        case OPC_DEXTRV_S_H:
+        case OPC_DEXTRV_W:
+        case OPC_DEXTRV_R_W:
+        case OPC_DEXTRV_RS_W:
+            gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
             break;
-        case OPC_ADDU_OB_DSP:
-            op2 = MASK_ADDU_OB(ctx->opcode);
-            switch (op2) {
-            case OPC_RADDU_L_OB:
-            case OPC_SUBQ_PW:
-            case OPC_SUBQ_S_PW:
-            case OPC_SUBQ_QH:
-            case OPC_SUBQ_S_QH:
-            case OPC_SUBU_OB:
-            case OPC_SUBU_S_OB:
-            case OPC_SUBU_QH:
-            case OPC_SUBU_S_QH:
-            case OPC_SUBUH_OB:
-            case OPC_SUBUH_R_OB:
-            case OPC_ADDQ_PW:
-            case OPC_ADDQ_S_PW:
-            case OPC_ADDQ_QH:
-            case OPC_ADDQ_S_QH:
-            case OPC_ADDU_OB:
-            case OPC_ADDU_S_OB:
-            case OPC_ADDU_QH:
-            case OPC_ADDU_S_QH:
-            case OPC_ADDUH_OB:
-            case OPC_ADDUH_R_OB:
-                gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
-                break;
-            case OPC_MULEQ_S_PW_QHL:
-            case OPC_MULEQ_S_PW_QHR:
-            case OPC_MULEU_S_QH_OBL:
-            case OPC_MULEU_S_QH_OBR:
-            case OPC_MULQ_RS_QH:
-                gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK ADDU.OB");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
+        case OPC_DMTHLIP:
+        case OPC_DSHILO:
+        case OPC_DSHILOV:
+            gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
             break;
-        case OPC_CMPU_EQ_OB_DSP:
-            op2 = MASK_CMPU_EQ_OB(ctx->opcode);
-            switch (op2) {
-            case OPC_PRECR_SRA_QH_PW:
-            case OPC_PRECR_SRA_R_QH_PW:
-                /* Return value is rt. */
-                gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd);
-                break;
-            case OPC_PRECR_OB_QH:
-            case OPC_PRECRQ_OB_QH:
-            case OPC_PRECRQ_PW_L:
-            case OPC_PRECRQ_QH_PW:
-            case OPC_PRECRQ_RS_QH_PW:
-            case OPC_PRECRQU_S_OB_QH:
-                gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
-                break;
-            case OPC_CMPU_EQ_OB:
-            case OPC_CMPU_LT_OB:
-            case OPC_CMPU_LE_OB:
-            case OPC_CMP_EQ_QH:
-            case OPC_CMP_LT_QH:
-            case OPC_CMP_LE_QH:
-            case OPC_CMP_EQ_PW:
-            case OPC_CMP_LT_PW:
-            case OPC_CMP_LE_PW:
-                gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0);
-                break;
-            case OPC_CMPGDU_EQ_OB:
-            case OPC_CMPGDU_LT_OB:
-            case OPC_CMPGDU_LE_OB:
-            case OPC_CMPGU_EQ_OB:
-            case OPC_CMPGU_LT_OB:
-            case OPC_CMPGU_LE_OB:
-            case OPC_PACKRL_PW:
-            case OPC_PICK_OB:
-            case OPC_PICK_PW:
-            case OPC_PICK_QH:
-                gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK CMPU_EQ.OB");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
+        default:            /* Invalid */
+            MIPS_INVAL("MASK EXTR.W");
+            generate_exception(ctx, EXCP_RI);
             break;
-        case OPC_DAPPEND_DSP:
-            gen_mipsdsp_append(env, ctx, op1, rt, rs, rd);
+        }
+        break;
+    case OPC_DPAQ_W_QH_DSP:
+        op2 = MASK_DPAQ_W_QH(ctx->opcode);
+        switch (op2) {
+        case OPC_DPAU_H_OBL:
+        case OPC_DPAU_H_OBR:
+        case OPC_DPSU_H_OBL:
+        case OPC_DPSU_H_OBR:
+        case OPC_DPA_W_QH:
+        case OPC_DPAQ_S_W_QH:
+        case OPC_DPS_W_QH:
+        case OPC_DPSQ_S_W_QH:
+        case OPC_MULSAQ_S_W_QH:
+        case OPC_DPAQ_SA_L_PW:
+        case OPC_DPSQ_SA_L_PW:
+        case OPC_MULSAQ_S_L_PW:
+            gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
+            break;
+        case OPC_MAQ_S_W_QHLL:
+        case OPC_MAQ_S_W_QHLR:
+        case OPC_MAQ_S_W_QHRL:
+        case OPC_MAQ_S_W_QHRR:
+        case OPC_MAQ_SA_W_QHLL:
+        case OPC_MAQ_SA_W_QHLR:
+        case OPC_MAQ_SA_W_QHRL:
+        case OPC_MAQ_SA_W_QHRR:
+        case OPC_MAQ_S_L_PWL:
+        case OPC_MAQ_S_L_PWR:
+        case OPC_DMADD:
+        case OPC_DMADDU:
+        case OPC_DMSUB:
+        case OPC_DMSUBU:
+            gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
             break;
-        case OPC_DEXTR_W_DSP:
-            op2 = MASK_DEXTR_W(ctx->opcode);
-            switch (op2) {
-            case OPC_DEXTP:
-            case OPC_DEXTPDP:
-            case OPC_DEXTPDPV:
-            case OPC_DEXTPV:
-            case OPC_DEXTR_L:
-            case OPC_DEXTR_R_L:
-            case OPC_DEXTR_RS_L:
-            case OPC_DEXTR_W:
-            case OPC_DEXTR_R_W:
-            case OPC_DEXTR_RS_W:
-            case OPC_DEXTR_S_H:
-            case OPC_DEXTRV_L:
-            case OPC_DEXTRV_R_L:
-            case OPC_DEXTRV_RS_L:
-            case OPC_DEXTRV_S_H:
-            case OPC_DEXTRV_W:
-            case OPC_DEXTRV_R_W:
-            case OPC_DEXTRV_RS_W:
-                gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
-                break;
-            case OPC_DMTHLIP:
-            case OPC_DSHILO:
-            case OPC_DSHILOV:
-                gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK EXTR.W");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
+        default:            /* Invalid */
+            MIPS_INVAL("MASK DPAQ.W.QH");
+            generate_exception(ctx, EXCP_RI);
             break;
-        case OPC_DPAQ_W_QH_DSP:
-            op2 = MASK_DPAQ_W_QH(ctx->opcode);
-            switch (op2) {
-            case OPC_DPAU_H_OBL:
-            case OPC_DPAU_H_OBR:
-            case OPC_DPSU_H_OBL:
-            case OPC_DPSU_H_OBR:
-            case OPC_DPA_W_QH:
-            case OPC_DPAQ_S_W_QH:
-            case OPC_DPS_W_QH:
-            case OPC_DPSQ_S_W_QH:
-            case OPC_MULSAQ_S_W_QH:
-            case OPC_DPAQ_SA_L_PW:
-            case OPC_DPSQ_SA_L_PW:
-            case OPC_MULSAQ_S_L_PW:
-                gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
-                break;
-            case OPC_MAQ_S_W_QHLL:
-            case OPC_MAQ_S_W_QHLR:
-            case OPC_MAQ_S_W_QHRL:
-            case OPC_MAQ_S_W_QHRR:
-            case OPC_MAQ_SA_W_QHLL:
-            case OPC_MAQ_SA_W_QHLR:
-            case OPC_MAQ_SA_W_QHRL:
-            case OPC_MAQ_SA_W_QHRR:
-            case OPC_MAQ_S_L_PWL:
-            case OPC_MAQ_S_L_PWR:
-            case OPC_DMADD:
-            case OPC_DMADDU:
-            case OPC_DMSUB:
-            case OPC_DMSUBU:
-                gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
-                break;
-            default:            /* Invalid */
-                MIPS_INVAL("MASK DPAQ.W.QH");
-                generate_exception(ctx, EXCP_RI);
+        }
+        break;
+    case OPC_DINSV_DSP:
+        op2 = MASK_INSV(ctx->opcode);
+        switch (op2) {
+        case OPC_DINSV:
+        {
+            TCGv t0, t1;
+
+            if (rt == 0) {
+                MIPS_DEBUG("NOP");
                 break;
             }
-            break;
-        case OPC_DINSV_DSP:
-            op2 = MASK_INSV(ctx->opcode);
-            switch (op2) {
-            case OPC_DINSV:
-                {
-                    TCGv t0, t1;
-
-                    if (rt == 0) {
-                        MIPS_DEBUG("NOP");
-                        break;
-                    }
-                    check_dsp(ctx);
+            check_dsp(ctx);
 
-                    t0 = tcg_temp_new();
-                    t1 = tcg_temp_new();
+            t0 = tcg_temp_new();
+            t1 = tcg_temp_new();
 
-                    gen_load_gpr(t0, rt);
-                    gen_load_gpr(t1, rs);
+            gen_load_gpr(t0, rt);
+            gen_load_gpr(t1, rs);
 
-                    gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0);
+            gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0);
 
-                    tcg_temp_free(t0);
-                    tcg_temp_free(t1);
-                    break;
-                }
-            default:            /* Invalid */
-                MIPS_INVAL("MASK DINSV");
-                generate_exception(ctx, EXCP_RI);
-                break;
-            }
-            break;
-        case OPC_SHLL_OB_DSP:
-            gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
             break;
-#endif
+        }
         default:            /* Invalid */
-            MIPS_INVAL("special3");
+            MIPS_INVAL("MASK DINSV");
             generate_exception(ctx, EXCP_RI);
             break;
         }
         break;
+    case OPC_SHLL_OB_DSP:
+        gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+        break;
+#endif
+    default:            /* Invalid */
+        MIPS_INVAL("special3");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
+{
+    int32_t offset;
+    int rs, rt, rd, sa;
+    uint32_t op, op1;
+    int16_t imm;
+
+    /* make sure instructions are on a word boundary */
+    if (ctx->pc & 0x3) {
+        env->CP0_BadVAddr = ctx->pc;
+        generate_exception(ctx, EXCP_AdEL);
+        return;
+    }
+
+    /* Handle blikely not taken case */
+    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);
+        tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
+        tcg_gen_movi_i32(hflags, ctx->hflags & ~MIPS_HFLAG_BMASK);
+        gen_goto_tb(ctx, 1, ctx->pc + 4);
+        gen_set_label(l1);
+    }
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
+        tcg_gen_debug_insn_start(ctx->pc);
+    }
+
+    op = MASK_OP_MAJOR(ctx->opcode);
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 6) & 0x1f;
+    imm = (int16_t)ctx->opcode;
+    switch (op) {
+    case OPC_SPECIAL:
+        decode_opc_special(env, ctx);
+        break;
+    case OPC_SPECIAL2:
+        decode_opc_special2(env, ctx);
+        break;
+    case OPC_SPECIAL3:
+        decode_opc_special3(env, ctx);
+        break;
     case OPC_REGIMM:
         op1 = MASK_REGIMM(ctx->opcode);
         switch (op1) {
@@ -15447,6 +15486,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         case OPC_MFMC0:
 #ifndef CONFIG_USER_ONLY
             {
+                uint32_t op2;
                 TCGv t0 = tcg_temp_new();
 
                 op2 = MASK_MFMC0(ctx->opcode);
-- 
2.1.0

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

* [Qemu-devel] [PULL 06/28] target-mips: split decode_opc_special* into *_r6 and *_legacy
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (4 preceding siblings ...)
  2014-10-15  9:53 ` [Qemu-devel] [PULL 05/28] target-mips: extract decode_opc_special* from decode_opc Leon Alrae
@ 2014-10-15  9:53 ` Leon Alrae
  2014-10-15  9:53 ` [Qemu-devel] [PULL 07/28] target-mips: signal RI Exception on DSP and Loongson instructions Leon Alrae
                   ` (23 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:53 UTC (permalink / raw)
  To: qemu-devel

For better code readability and to avoid 'if' statements for all R6 and preR6
instructions whose opcodes are the same - decode_opc_special* functions are
split into functions with _r6 and _legacy suffixes.

*_r6 functions will contain instructions which were introduced in R6.
*_legacy functions will contain instructions which were removed in R6.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-mips/translate.c | 228 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 160 insertions(+), 68 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 5b8f762..0c64aeb 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -14482,6 +14482,70 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2,
 
 /* End MIPSDSP functions. */
 
+static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
+{
+    int rs, rt, rd;
+    uint32_t op1;
+
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+
+    op1 = MASK_SPECIAL(ctx->opcode);
+    switch (op1) {
+    case OPC_SELEQZ:
+    case OPC_SELNEZ:
+        gen_cond_move(ctx, op1, rd, rs, rt);
+        break;
+    default:            /* Invalid */
+        MIPS_INVAL("special_r6");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
+{
+    int rs, rt, rd;
+    uint32_t op1;
+
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+
+    op1 = MASK_SPECIAL(ctx->opcode);
+    switch (op1) {
+    case OPC_MOVN:         /* Conditional move */
+    case OPC_MOVZ:
+        check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
+                   INSN_LOONGSON2E | INSN_LOONGSON2F);
+        gen_cond_move(ctx, op1, rd, rs, rt);
+        break;
+    case OPC_MFHI:          /* Move from HI/LO */
+    case OPC_MFLO:
+        gen_HILO(ctx, op1, rs & 3, rd);
+        break;
+    case OPC_MTHI:
+    case OPC_MTLO:          /* Move to HI/LO */
+        gen_HILO(ctx, op1, rd & 3, rs);
+        break;
+    case OPC_MOVCI:
+        check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            check_cp1_enabled(ctx);
+            gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+                      (ctx->opcode >> 16) & 1);
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
+        }
+        break;
+    default:            /* Invalid */
+        MIPS_INVAL("special_legacy");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
 static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd, sa;
@@ -14514,18 +14578,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
             break;
         }
         break;
-    case OPC_MOVN:         /* Conditional move */
-    case OPC_MOVZ:
-        check_insn_opc_removed(ctx, ISA_MIPS32R6);
-        check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
-                   INSN_LOONGSON2E | INSN_LOONGSON2F);
-        gen_cond_move(ctx, op1, rd, rs, rt);
-        break;
-    case OPC_SELEQZ:
-    case OPC_SELNEZ:
-        check_insn(ctx, ISA_MIPS32R6);
-        gen_cond_move(ctx, op1, rd, rs, rt);
-        break;
     case OPC_ADD ... OPC_SUBU:
         gen_arith(ctx, op1, rd, rs, rt);
         break;
@@ -14580,16 +14632,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
     case OPC_TNE:
         gen_trap(ctx, op1, rs, rt, -1);
         break;
-    case OPC_MFHI:          /* Move from HI/LO */
-    case OPC_MFLO:
-        check_insn_opc_removed(ctx, ISA_MIPS32R6);
-        gen_HILO(ctx, op1, rs & 3, rd);
-        break;
-    case OPC_MTHI:
-    case OPC_MTLO:          /* Move to HI/LO */
-        check_insn_opc_removed(ctx, ISA_MIPS32R6);
-        gen_HILO(ctx, op1, rd & 3, rs);
-        break;
     case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
 #ifdef MIPS_STRICT_STANDARD
         MIPS_INVAL("PMON / selsl");
@@ -14619,18 +14661,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
         /* Treat as NOP. */
         break;
 
-    case OPC_MOVCI:
-        check_insn_opc_removed(ctx, ISA_MIPS32R6);
-        check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
-        if (ctx->CP0_Config1 & (1 << CP0C1_FP)) {
-            check_cp1_enabled(ctx);
-            gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
-                      (ctx->opcode >> 16) & 1);
-        } else {
-            generate_exception_err(ctx, EXCP_CpU, 1);
-        }
-        break;
-
 #if defined(TARGET_MIPS64)
         /* MIPS64 specific opcodes */
     case OPC_DSLL:
@@ -14712,14 +14742,29 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
         gen_muldiv(ctx, op1, 0, rs, rt);
         break;
 #endif
+    default:
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            decode_opc_special_r6(env, ctx);
+        } else {
+            decode_opc_special_legacy(env, ctx);
+        }
+    }
+}
+
+static void decode_opc_special2_r6(CPUMIPSState *env, DisasContext *ctx)
+{
+    uint32_t op1;
+
+    op1 = MASK_SPECIAL2(ctx->opcode);
+    switch (op1) {
     default:            /* Invalid */
-        MIPS_INVAL("special");
+        MIPS_INVAL("special2_r6");
         generate_exception(ctx, EXCP_RI);
         break;
     }
 }
 
-static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
+static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd;
     uint32_t op1;
@@ -14732,14 +14777,30 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
     switch (op1) {
     case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
     case OPC_MSUB ... OPC_MSUBU:
-        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         check_insn(ctx, ISA_MIPS32);
         gen_muldiv(ctx, op1, rd & 3, rs, rt);
         break;
     case OPC_MUL:
-        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         gen_arith(ctx, op1, rd, rs, rt);
         break;
+    default:            /* Invalid */
+        MIPS_INVAL("special2_legacy");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
+{
+    int rs, rt, rd;
+    uint32_t op1;
+
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+
+    op1 = MASK_SPECIAL2(ctx->opcode);
+    switch (op1) {
     case OPC_CLO:
     case OPC_CLZ:
         check_insn(ctx, ISA_MIPS32);
@@ -14783,30 +14844,78 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
         gen_loongson_integer(ctx, op1, rd, rs, rt);
         break;
 #endif
+    default:
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            decode_opc_special2_r6(env, ctx);
+        } else {
+            decode_opc_special2_legacy(env, ctx);
+        }
+    }
+}
+
+static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
+{
+    int rs, rt;
+    uint32_t op1;
+    int16_t imm;
+
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    imm = (int16_t)ctx->opcode >> 7;
+
+    op1 = MASK_SPECIAL3(ctx->opcode);
+    switch (op1) {
+    case R6_OPC_SC:
+        gen_st_cond(ctx, op1, rt, rs, imm);
+        break;
+    case R6_OPC_LL:
+        gen_ld(ctx, op1, rt, rs, imm);
+        break;
     default:            /* Invalid */
-        MIPS_INVAL("special2");
+        MIPS_INVAL("special3_r6");
         generate_exception(ctx, EXCP_RI);
         break;
     }
 }
+
+static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
+{
+    uint32_t op1;
+#if defined(TARGET_MIPS64)
+    int rd = (ctx->opcode >> 11) & 0x1f;
+    int rs = (ctx->opcode >> 21) & 0x1f;
+    int rt = (ctx->opcode >> 16) & 0x1f;
+#endif
+
+    op1 = MASK_SPECIAL3(ctx->opcode);
+    switch (op1) {
+#if defined(TARGET_MIPS64)
+    case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
+    case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
+    case OPC_DMOD_G_2E ... OPC_DMODU_G_2E:
+        check_insn(ctx, INSN_LOONGSON2E);
+        gen_loongson_integer(ctx, op1, rd, rs, rt);
+        break;
+#endif
+    default:            /* Invalid */
+        MIPS_INVAL("special3_legacy");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
 static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd, sa;
     uint32_t op1, op2;
-    int16_t imm;
 
     rs = (ctx->opcode >> 21) & 0x1f;
     rt = (ctx->opcode >> 16) & 0x1f;
     rd = (ctx->opcode >> 11) & 0x1f;
     sa = (ctx->opcode >> 6) & 0x1f;
-    imm = (int16_t)ctx->opcode;
 
     op1 = MASK_SPECIAL3(ctx->opcode);
     switch (op1) {
-    case R6_OPC_LL:
-        check_insn(ctx, ISA_MIPS32R6);
-        gen_ld(ctx, op1, rt, rs, imm >> 7);
-        break;
     case OPC_EXT:
     case OPC_INS:
         check_insn(ctx, ISA_MIPS32R2);
@@ -15111,19 +15220,6 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
             break;
         }
         break;
-    case R6_OPC_SC: /* OPC_DMOD_G_2E */
-        if (ctx->insn_flags & ISA_MIPS32R6) {
-            gen_st_cond(ctx, op1, rt, rs, imm >> 7);
-        } else {
-#if defined(TARGET_MIPS64)
-            check_insn(ctx, INSN_LOONGSON2E);
-            gen_loongson_integer(ctx, op1, rd, rs, rt);
-#else
-            /* Invalid in MIPS32 */
-            generate_exception(ctx, EXCP_RI);
-#endif
-        }
-        break;
 #if defined(TARGET_MIPS64)
     case OPC_DEXTM ... OPC_DEXT:
     case OPC_DINSM ... OPC_DINS:
@@ -15137,12 +15233,6 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
         op2 = MASK_DBSHFL(ctx->opcode);
         gen_bshfl(ctx, op2, rt, rd);
         break;
-    case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
-    case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
-    case OPC_DMODU_G_2E:
-        check_insn(ctx, INSN_LOONGSON2E);
-        gen_loongson_integer(ctx, op1, rd, rs, rt);
-        break;
     case OPC_ABSQ_S_QH_DSP:
         op2 = MASK_ABSQ_S_QH(ctx->opcode);
         switch (op2) {
@@ -15374,10 +15464,12 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
         gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
         break;
 #endif
-    default:            /* Invalid */
-        MIPS_INVAL("special3");
-        generate_exception(ctx, EXCP_RI);
-        break;
+    default:
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            decode_opc_special3_r6(env, ctx);
+        } else {
+            decode_opc_special3_legacy(env, ctx);
+        }
     }
 }
 
-- 
2.1.0

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

* [Qemu-devel] [PULL 07/28] target-mips: signal RI Exception on DSP and Loongson instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (5 preceding siblings ...)
  2014-10-15  9:53 ` [Qemu-devel] [PULL 06/28] target-mips: split decode_opc_special* into *_r6 and *_legacy Leon Alrae
@ 2014-10-15  9:53 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 08/28] target-mips: move PREF, CACHE, LLD and SCD instructions Leon Alrae
                   ` (22 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:53 UTC (permalink / raw)
  To: qemu-devel

Move DSP and Loongson instruction to *_legacy functions as they have been
removed in R6.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-mips/translate.c | 195 ++++++++++++++++++++++++------------------------
 1 file changed, 98 insertions(+), 97 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 0c64aeb..11967a0 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -14783,6 +14783,26 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
     case OPC_MUL:
         gen_arith(ctx, op1, rd, rs, rt);
         break;
+    case OPC_DIV_G_2F:
+    case OPC_DIVU_G_2F:
+    case OPC_MULT_G_2F:
+    case OPC_MULTU_G_2F:
+    case OPC_MOD_G_2F:
+    case OPC_MODU_G_2F:
+        check_insn(ctx, INSN_LOONGSON2F);
+        gen_loongson_integer(ctx, op1, rd, rs, rt);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT_G_2F:
+    case OPC_DMULTU_G_2F:
+    case OPC_DDIV_G_2F:
+    case OPC_DDIVU_G_2F:
+    case OPC_DMOD_G_2F:
+    case OPC_DMODU_G_2F:
+        check_insn(ctx, INSN_LOONGSON2F);
+        gen_loongson_integer(ctx, op1, rd, rs, rt);
+        break;
+#endif
     default:            /* Invalid */
         MIPS_INVAL("special2_legacy");
         generate_exception(ctx, EXCP_RI);
@@ -14792,11 +14812,10 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
 
 static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
 {
-    int rs, rt, rd;
+    int rs, rd;
     uint32_t op1;
 
     rs = (ctx->opcode >> 21) & 0x1f;
-    rt = (ctx->opcode >> 16) & 0x1f;
     rd = (ctx->opcode >> 11) & 0x1f;
 
     op1 = MASK_SPECIAL2(ctx->opcode);
@@ -14818,15 +14837,6 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
         }
         /* Treat as NOP. */
         break;
-    case OPC_DIV_G_2F:
-    case OPC_DIVU_G_2F:
-    case OPC_MULT_G_2F:
-    case OPC_MULTU_G_2F:
-    case OPC_MOD_G_2F:
-    case OPC_MODU_G_2F:
-        check_insn(ctx, INSN_LOONGSON2F);
-        gen_loongson_integer(ctx, op1, rd, rs, rt);
-        break;
 #if defined(TARGET_MIPS64)
     case OPC_DCLO:
     case OPC_DCLZ:
@@ -14834,15 +14844,6 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
         check_mips_64(ctx);
         gen_cl(ctx, op1, rd, rs);
         break;
-    case OPC_DMULT_G_2F:
-    case OPC_DMULTU_G_2F:
-    case OPC_DDIV_G_2F:
-    case OPC_DDIVU_G_2F:
-    case OPC_DMOD_G_2F:
-    case OPC_DMODU_G_2F:
-        check_insn(ctx, INSN_LOONGSON2F);
-        gen_loongson_integer(ctx, op1, rd, rs, rt);
-        break;
 #endif
     default:
         if (ctx->insn_flags & ISA_MIPS32R6) {
@@ -14880,80 +14881,15 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
 
 static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
 {
-    uint32_t op1;
-#if defined(TARGET_MIPS64)
-    int rd = (ctx->opcode >> 11) & 0x1f;
-    int rs = (ctx->opcode >> 21) & 0x1f;
-    int rt = (ctx->opcode >> 16) & 0x1f;
-#endif
-
-    op1 = MASK_SPECIAL3(ctx->opcode);
-    switch (op1) {
-#if defined(TARGET_MIPS64)
-    case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
-    case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
-    case OPC_DMOD_G_2E ... OPC_DMODU_G_2E:
-        check_insn(ctx, INSN_LOONGSON2E);
-        gen_loongson_integer(ctx, op1, rd, rs, rt);
-        break;
-#endif
-    default:            /* Invalid */
-        MIPS_INVAL("special3_legacy");
-        generate_exception(ctx, EXCP_RI);
-        break;
-    }
-}
-
-static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
-{
-    int rs, rt, rd, sa;
+    int rs, rt, rd;
     uint32_t op1, op2;
 
     rs = (ctx->opcode >> 21) & 0x1f;
     rt = (ctx->opcode >> 16) & 0x1f;
     rd = (ctx->opcode >> 11) & 0x1f;
-    sa = (ctx->opcode >> 6) & 0x1f;
 
     op1 = MASK_SPECIAL3(ctx->opcode);
     switch (op1) {
-    case OPC_EXT:
-    case OPC_INS:
-        check_insn(ctx, ISA_MIPS32R2);
-        gen_bitops(ctx, op1, rt, rs, sa, rd);
-        break;
-    case OPC_BSHFL:
-        check_insn(ctx, ISA_MIPS32R2);
-        op2 = MASK_BSHFL(ctx->opcode);
-        gen_bshfl(ctx, op2, rt, rd);
-        break;
-    case OPC_RDHWR:
-        gen_rdhwr(ctx, rt, rd);
-        break;
-    case OPC_FORK:
-        check_insn(ctx, ASE_MT);
-        {
-            TCGv t0 = tcg_temp_new();
-            TCGv t1 = tcg_temp_new();
-
-            gen_load_gpr(t0, rt);
-            gen_load_gpr(t1, rs);
-            gen_helper_fork(t0, t1);
-            tcg_temp_free(t0);
-            tcg_temp_free(t1);
-        }
-        break;
-    case OPC_YIELD:
-        check_insn(ctx, ASE_MT);
-        {
-            TCGv t0 = tcg_temp_new();
-
-            save_cpu_state(ctx, 1);
-            gen_load_gpr(t0, rs);
-            gen_helper_yield(t0, cpu_env, t0);
-            gen_store_gpr(t0, rd);
-            tcg_temp_free(t0);
-        }
-        break;
     case OPC_DIV_G_2E ... OPC_DIVU_G_2E:
     case OPC_MOD_G_2E ... OPC_MODU_G_2E:
     case OPC_MULT_G_2E ... OPC_MULTU_G_2E:
@@ -15221,17 +15157,11 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
         }
         break;
 #if defined(TARGET_MIPS64)
-    case OPC_DEXTM ... OPC_DEXT:
-    case OPC_DINSM ... OPC_DINS:
-        check_insn(ctx, ISA_MIPS64R2);
-        check_mips_64(ctx);
-        gen_bitops(ctx, op1, rt, rs, sa, rd);
-        break;
-    case OPC_DBSHFL:
-        check_insn(ctx, ISA_MIPS64R2);
-        check_mips_64(ctx);
-        op2 = MASK_DBSHFL(ctx->opcode);
-        gen_bshfl(ctx, op2, rt, rd);
+    case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
+    case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
+    case OPC_DMOD_G_2E ... OPC_DMODU_G_2E:
+        check_insn(ctx, INSN_LOONGSON2E);
+        gen_loongson_integer(ctx, op1, rd, rs, rt);
         break;
     case OPC_ABSQ_S_QH_DSP:
         op2 = MASK_ABSQ_S_QH(ctx->opcode);
@@ -15464,6 +15394,77 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
         gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
         break;
 #endif
+    default:            /* Invalid */
+        MIPS_INVAL("special3_legacy");
+        generate_exception(ctx, EXCP_RI);
+        break;
+    }
+}
+
+static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
+{
+    int rs, rt, rd, sa;
+    uint32_t op1, op2;
+
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 6) & 0x1f;
+
+    op1 = MASK_SPECIAL3(ctx->opcode);
+    switch (op1) {
+    case OPC_EXT:
+    case OPC_INS:
+        check_insn(ctx, ISA_MIPS32R2);
+        gen_bitops(ctx, op1, rt, rs, sa, rd);
+        break;
+    case OPC_BSHFL:
+        check_insn(ctx, ISA_MIPS32R2);
+        op2 = MASK_BSHFL(ctx->opcode);
+        gen_bshfl(ctx, op2, rt, rd);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DEXTM ... OPC_DEXT:
+    case OPC_DINSM ... OPC_DINS:
+        check_insn(ctx, ISA_MIPS64R2);
+        check_mips_64(ctx);
+        gen_bitops(ctx, op1, rt, rs, sa, rd);
+        break;
+    case OPC_DBSHFL:
+        check_insn(ctx, ISA_MIPS64R2);
+        check_mips_64(ctx);
+        op2 = MASK_DBSHFL(ctx->opcode);
+        gen_bshfl(ctx, op2, rt, rd);
+        break;
+#endif
+    case OPC_RDHWR:
+        gen_rdhwr(ctx, rt, rd);
+        break;
+    case OPC_FORK:
+        check_insn(ctx, ASE_MT);
+        {
+            TCGv t0 = tcg_temp_new();
+            TCGv t1 = tcg_temp_new();
+
+            gen_load_gpr(t0, rt);
+            gen_load_gpr(t1, rs);
+            gen_helper_fork(t0, t1);
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+        }
+        break;
+    case OPC_YIELD:
+        check_insn(ctx, ASE_MT);
+        {
+            TCGv t0 = tcg_temp_new();
+
+            save_cpu_state(ctx, 1);
+            gen_load_gpr(t0, rs);
+            gen_helper_yield(t0, cpu_env, t0);
+            gen_store_gpr(t0, rd);
+            tcg_temp_free(t0);
+        }
+        break;
     default:
         if (ctx->insn_flags & ISA_MIPS32R6) {
             decode_opc_special3_r6(env, ctx);
-- 
2.1.0

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

* [Qemu-devel] [PULL 08/28] target-mips: move PREF, CACHE, LLD and SCD instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (6 preceding siblings ...)
  2014-10-15  9:53 ` [Qemu-devel] [PULL 07/28] target-mips: signal RI Exception on DSP and Loongson instructions Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 09/28] target-mips: redefine Integer Multiply and Divide instructions Leon Alrae
                   ` (21 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

The encoding of PREF, CACHE, LLD and SCD instruction changed in MIPS32R6.
Additionally, the hint codes in PREF instruction greater than or
equal to 24 generate Reserved Instruction Exception.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 disas/mips.c            |  4 ++++
 target-mips/translate.c | 29 ++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/disas/mips.c b/disas/mips.c
index f0efa8b..cae76ed 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -1219,6 +1219,10 @@ const struct mips_opcode mips_builtin_opcodes[] =
 /* name,    args,	match,	    mask,	pinfo,          	membership */
 {"ll",      "t,o(b)",   0x7c000036, 0xfc00007f, LDD|RD_b|WR_t,        0, I32R6},
 {"sc",      "t,o(b)",   0x7c000026, 0xfc00007f, LDD|RD_b|WR_t,        0, I32R6},
+{"lld",     "t,o(b)",   0x7c000037, 0xfc00007f, LDD|RD_b|WR_t,        0, I64R6},
+{"scd",     "t,o(b)",   0x7c000027, 0xfc00007f, LDD|RD_b|WR_t,        0, I64R6},
+{"pref",    "h,o(b)",   0x7c000035, 0xfc00007f, RD_b,                 0, I32R6},
+{"cache",   "k,o(b)",   0x7c000025, 0xfc00007f, RD_b,                 0, I32R6},
 {"seleqz",  "d,v,t",    0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"selnez",  "d,v,t",    0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	0,		I4|I32|G3	},
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 11967a0..f50d906 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -349,8 +349,12 @@ enum {
     OPC_DEXTR_W_DSP    = 0x3C | OPC_SPECIAL3,
 
     /* R6 */
+    R6_OPC_PREF        = 0x35 | OPC_SPECIAL3,
+    R6_OPC_CACHE       = 0x25 | OPC_SPECIAL3,
     R6_OPC_LL          = 0x36 | OPC_SPECIAL3,
     R6_OPC_SC          = 0x26 | OPC_SPECIAL3,
+    R6_OPC_LLD         = 0x37 | OPC_SPECIAL3,
+    R6_OPC_SCD         = 0x27 | OPC_SPECIAL3,
 };
 
 /* BSHFL opcodes */
@@ -1645,6 +1649,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
         opn = "ld";
         break;
     case OPC_LLD:
+    case R6_OPC_LLD:
         save_cpu_state(ctx, 1);
         op_ld_lld(t0, t0, ctx);
         gen_store_gpr(t0, rt);
@@ -1867,6 +1872,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
     switch (opc) {
 #if defined(TARGET_MIPS64)
     case OPC_SCD:
+    case R6_OPC_SCD:
         save_cpu_state(ctx, 1);
         op_st_scd(t1, t0, rt, ctx);
         opn = "scd";
@@ -14866,12 +14872,30 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
 
     op1 = MASK_SPECIAL3(ctx->opcode);
     switch (op1) {
+    case R6_OPC_PREF:
+        if (rt >= 24) {
+            /* hint codes 24-31 are reserved and signal RI */
+            generate_exception(ctx, EXCP_RI);
+        }
+        /* Treat as NOP. */
+        break;
+    case R6_OPC_CACHE:
+        /* Treat as NOP. */
+        break;
     case R6_OPC_SC:
         gen_st_cond(ctx, op1, rt, rs, imm);
         break;
     case R6_OPC_LL:
         gen_ld(ctx, op1, rt, rs, imm);
         break;
+#if defined(TARGET_MIPS64)
+    case R6_OPC_SCD:
+        gen_st_cond(ctx, op1, rt, rs, imm);
+        break;
+    case R6_OPC_LLD:
+        gen_ld(ctx, op1, rt, rs, imm);
+        break;
+#endif
     default:            /* Invalid */
         MIPS_INVAL("special3_r6");
         generate_exception(ctx, EXCP_RI);
@@ -15686,11 +15710,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          gen_st_cond(ctx, op, rt, rs, imm);
          break;
     case OPC_CACHE:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         check_cp0_enabled(ctx);
         check_insn(ctx, ISA_MIPS3 | ISA_MIPS32);
         /* Treat as NOP. */
         break;
     case OPC_PREF:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
         /* Treat as NOP. */
         break;
@@ -15813,9 +15839,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
 #if defined(TARGET_MIPS64)
     /* MIPS64 opcodes */
     case OPC_LDL ... OPC_LDR:
+    case OPC_LLD:
         check_insn_opc_removed(ctx, ISA_MIPS32R6);
     case OPC_LWU:
-    case OPC_LLD:
     case OPC_LD:
         check_insn(ctx, ISA_MIPS3);
         check_mips_64(ctx);
@@ -15829,6 +15855,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         gen_st(ctx, op, rt, rs, imm);
         break;
     case OPC_SCD:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         check_insn(ctx, ISA_MIPS3);
         check_mips_64(ctx);
         gen_st_cond(ctx, op, rt, rs, imm);
-- 
2.1.0

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

* [Qemu-devel] [PULL 09/28] target-mips: redefine Integer Multiply and Divide instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (7 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 08/28] target-mips: move PREF, CACHE, LLD and SCD instructions Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 10/28] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6 Leon Alrae
                   ` (20 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

Use "R6_" prefix in front of all new Multiply / Divide instructions for
easier differentiation between R6 and preR6.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 disas/mips.c            |  16 +++
 target-mips/translate.c | 343 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 338 insertions(+), 21 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index cae76ed..16cb2ac 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -1217,6 +1217,22 @@ const struct mips_opcode mips_builtin_opcodes[] =
    them first.  The assemblers uses a hash table based on the
    instruction name anyhow.  */
 /* name,    args,	match,	    mask,	pinfo,          	membership */
+{"mul",     "d,s,t",    0x00000098, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"muh",     "d,s,t",    0x000000d8, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"mulu",    "d,s,t",    0x00000099, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"muhu",    "d,s,t",    0x000000d9, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"div",     "d,s,t",    0x0000009a, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"mod",     "d,s,t",    0x000000da, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"divu",    "d,s,t",    0x0000009b, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"modu",    "d,s,t",    0x000000db, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"dmul",    "d,s,t",    0x0000009c, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I64R6},
+{"dmuh",    "d,s,t",    0x000000dc, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I64R6},
+{"dmulu",   "d,s,t",    0x0000009d, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I64R6},
+{"dmuhu",   "d,s,t",    0x000000dd, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I64R6},
+{"ddiv",    "d,s,t",    0x0000009e, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I64R6},
+{"dmod",    "d,s,t",    0x000000de, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I64R6},
+{"ddivu",   "d,s,t",    0x0000009f, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I64R6},
+{"dmodu",   "d,s,t",    0x000000df, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I64R6},
 {"ll",      "t,o(b)",   0x7c000036, 0xfc00007f, LDD|RD_b|WR_t,        0, I32R6},
 {"sc",      "t,o(b)",   0x7c000026, 0xfc00007f, LDD|RD_b|WR_t,        0, I32R6},
 {"lld",     "t,o(b)",   0x7c000037, 0xfc00007f, LDD|RD_b|WR_t,        0, I64R6},
diff --git a/target-mips/translate.c b/target-mips/translate.c
index f50d906..3ce9641 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -157,6 +157,7 @@ enum {
     OPC_DMULTU   = 0x1D | OPC_SPECIAL,
     OPC_DDIV     = 0x1E | OPC_SPECIAL,
     OPC_DDIVU    = 0x1F | OPC_SPECIAL,
+
     /* 2 registers arithmetic / logic */
     OPC_ADD      = 0x20 | OPC_SPECIAL,
     OPC_ADDU     = 0x21 | OPC_SPECIAL,
@@ -212,6 +213,30 @@ enum {
     OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
 };
 
+/* R6 Multiply and Divide instructions have the same Opcode
+   and function field as legacy OPC_MULT[U]/OPC_DIV[U] */
+#define MASK_R6_MULDIV(op)   (MASK_SPECIAL(op) | (op & (0x7ff)))
+
+enum {
+    R6_OPC_MUL   = OPC_MULT  | (2 << 6),
+    R6_OPC_MUH   = OPC_MULT  | (3 << 6),
+    R6_OPC_MULU  = OPC_MULTU | (2 << 6),
+    R6_OPC_MUHU  = OPC_MULTU | (3 << 6),
+    R6_OPC_DIV   = OPC_DIV   | (2 << 6),
+    R6_OPC_MOD   = OPC_DIV   | (3 << 6),
+    R6_OPC_DIVU  = OPC_DIVU  | (2 << 6),
+    R6_OPC_MODU  = OPC_DIVU  | (3 << 6),
+
+    R6_OPC_DMUL   = OPC_DMULT  | (2 << 6),
+    R6_OPC_DMUH   = OPC_DMULT  | (3 << 6),
+    R6_OPC_DMULU  = OPC_DMULTU | (2 << 6),
+    R6_OPC_DMUHU  = OPC_DMULTU | (3 << 6),
+    R6_OPC_DDIV   = OPC_DDIV   | (2 << 6),
+    R6_OPC_DMOD   = OPC_DDIV   | (3 << 6),
+    R6_OPC_DDIVU  = OPC_DDIVU  | (2 << 6),
+    R6_OPC_DMODU  = OPC_DDIVU  | (3 << 6),
+};
+
 /* Multiplication variants of the vr54xx. */
 #define MASK_MUL_VR54XX(op)   MASK_SPECIAL(op) | (op & (0x1F << 6))
 
@@ -2691,6 +2716,238 @@ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg)
     MIPS_DEBUG("%s %s", opn, regnames[reg]);
 }
 
+static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt)
+{
+    const char *opn = "r6 mul/div";
+    TCGv t0, t1;
+
+    if (rd == 0) {
+        /* Treat as NOP. */
+        MIPS_DEBUG("NOP");
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+
+    gen_load_gpr(t0, rs);
+    gen_load_gpr(t1, rt);
+
+    switch (opc) {
+    case R6_OPC_DIV:
+        {
+            TCGv t2 = tcg_temp_new();
+            TCGv t3 = tcg_temp_new();
+            tcg_gen_ext32s_tl(t0, t0);
+            tcg_gen_ext32s_tl(t1, t1);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
+            tcg_gen_and_tl(t2, t2, t3);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
+            tcg_gen_or_tl(t2, t2, t3);
+            tcg_gen_movi_tl(t3, 0);
+            tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            tcg_temp_free(t3);
+            tcg_temp_free(t2);
+        }
+        opn = "div";
+        break;
+    case R6_OPC_MOD:
+        {
+            TCGv t2 = tcg_temp_new();
+            TCGv t3 = tcg_temp_new();
+            tcg_gen_ext32s_tl(t0, t0);
+            tcg_gen_ext32s_tl(t1, t1);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
+            tcg_gen_and_tl(t2, t2, t3);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
+            tcg_gen_or_tl(t2, t2, t3);
+            tcg_gen_movi_tl(t3, 0);
+            tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            tcg_temp_free(t3);
+            tcg_temp_free(t2);
+        }
+        opn = "mod";
+        break;
+    case R6_OPC_DIVU:
+        {
+            TCGv t2 = tcg_const_tl(0);
+            TCGv t3 = tcg_const_tl(1);
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            tcg_temp_free(t3);
+            tcg_temp_free(t2);
+        }
+        opn = "divu";
+        break;
+    case R6_OPC_MODU:
+        {
+            TCGv t2 = tcg_const_tl(0);
+            TCGv t3 = tcg_const_tl(1);
+            tcg_gen_ext32u_tl(t0, t0);
+            tcg_gen_ext32u_tl(t1, t1);
+            tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+            tcg_temp_free(t3);
+            tcg_temp_free(t2);
+        }
+        opn = "modu";
+        break;
+    case R6_OPC_MUL:
+        {
+            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_mul_i32(t2, t2, t3);
+            tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
+            tcg_temp_free_i32(t2);
+            tcg_temp_free_i32(t3);
+        }
+        opn = "mul";
+        break;
+    case R6_OPC_MUH:
+        {
+            TCGv_i32 t2 = tcg_temp_new_i32();
+            TCGv_i32 t3 = tcg_temp_new_i32();
+            tcg_gen_trunc_tl_i32(t2, t0);
+            tcg_gen_trunc_tl_i32(t3, t1);
+            tcg_gen_muls2_i32(t2, t3, t2, t3);
+            tcg_gen_ext_i32_tl(cpu_gpr[rd], t3);
+            tcg_temp_free_i32(t2);
+            tcg_temp_free_i32(t3);
+        }
+        opn = "muh";
+        break;
+    case R6_OPC_MULU:
+        {
+            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_mul_i32(t2, t2, t3);
+            tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
+            tcg_temp_free_i32(t2);
+            tcg_temp_free_i32(t3);
+        }
+        opn = "mulu";
+        break;
+    case R6_OPC_MUHU:
+        {
+            TCGv_i32 t2 = tcg_temp_new_i32();
+            TCGv_i32 t3 = tcg_temp_new_i32();
+            tcg_gen_trunc_tl_i32(t2, t0);
+            tcg_gen_trunc_tl_i32(t3, t1);
+            tcg_gen_mulu2_i32(t2, t3, t2, t3);
+            tcg_gen_ext_i32_tl(cpu_gpr[rd], t3);
+            tcg_temp_free_i32(t2);
+            tcg_temp_free_i32(t3);
+        }
+        opn = "muhu";
+        break;
+#if defined(TARGET_MIPS64)
+    case R6_OPC_DDIV:
+        {
+            TCGv t2 = tcg_temp_new();
+            TCGv t3 = tcg_temp_new();
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL);
+            tcg_gen_and_tl(t2, t2, t3);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
+            tcg_gen_or_tl(t2, t2, t3);
+            tcg_gen_movi_tl(t3, 0);
+            tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t3);
+            tcg_temp_free(t2);
+        }
+        opn = "ddiv";
+        break;
+    case R6_OPC_DMOD:
+        {
+            TCGv t2 = tcg_temp_new();
+            TCGv t3 = tcg_temp_new();
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL);
+            tcg_gen_and_tl(t2, t2, t3);
+            tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
+            tcg_gen_or_tl(t2, t2, t3);
+            tcg_gen_movi_tl(t3, 0);
+            tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t3);
+            tcg_temp_free(t2);
+        }
+        opn = "dmod";
+        break;
+    case R6_OPC_DDIVU:
+        {
+            TCGv t2 = tcg_const_tl(0);
+            TCGv t3 = tcg_const_tl(1);
+            tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+            tcg_gen_divu_i64(cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t3);
+            tcg_temp_free(t2);
+        }
+        opn = "ddivu";
+        break;
+    case R6_OPC_DMODU:
+        {
+            TCGv t2 = tcg_const_tl(0);
+            TCGv t3 = tcg_const_tl(1);
+            tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+            tcg_gen_remu_i64(cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t3);
+            tcg_temp_free(t2);
+        }
+        opn = "dmodu";
+        break;
+    case R6_OPC_DMUL:
+        tcg_gen_mul_i64(cpu_gpr[rd], t0, t1);
+        opn = "dmul";
+        break;
+    case R6_OPC_DMUH:
+        {
+            TCGv t2 = tcg_temp_new();
+            tcg_gen_muls2_i64(t2, cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t2);
+        }
+        opn = "dmuh";
+        break;
+    case R6_OPC_DMULU:
+        tcg_gen_mul_i64(cpu_gpr[rd], t0, t1);
+        opn = "dmulu";
+        break;
+    case R6_OPC_DMUHU:
+        {
+            TCGv t2 = tcg_temp_new();
+            tcg_gen_mulu2_i64(t2, cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t2);
+        }
+        opn = "dmuhu";
+        break;
+#endif
+    default:
+        MIPS_INVAL(opn);
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
+ out:
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
 static void gen_muldiv(DisasContext *ctx, uint32_t opc,
                        int acc, int rs, int rt)
 {
@@ -14491,7 +14748,7 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2,
 static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd;
-    uint32_t op1;
+    uint32_t op1, op2;
 
     rs = (ctx->opcode >> 21) & 0x1f;
     rt = (ctx->opcode >> 16) & 0x1f;
@@ -14499,10 +14756,51 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 
     op1 = MASK_SPECIAL(ctx->opcode);
     switch (op1) {
+    case OPC_MULT ... OPC_DIVU:
+        op2 = MASK_R6_MULDIV(ctx->opcode);
+        switch (op2) {
+        case R6_OPC_MUL:
+        case R6_OPC_MUH:
+        case R6_OPC_MULU:
+        case R6_OPC_MUHU:
+        case R6_OPC_DIV:
+        case R6_OPC_MOD:
+        case R6_OPC_DIVU:
+        case R6_OPC_MODU:
+            gen_r6_muldiv(ctx, op2, rd, rs, rt);
+            break;
+        default:
+            MIPS_INVAL("special_r6 muldiv");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
     case OPC_SELEQZ:
     case OPC_SELNEZ:
         gen_cond_move(ctx, op1, rd, rs, rt);
         break;
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT ... OPC_DDIVU:
+        op2 = MASK_R6_MULDIV(ctx->opcode);
+        switch (op2) {
+        case R6_OPC_DMUL:
+        case R6_OPC_DMUH:
+        case R6_OPC_DMULU:
+        case R6_OPC_DMUHU:
+        case R6_OPC_DDIV:
+        case R6_OPC_DMOD:
+        case R6_OPC_DDIVU:
+        case R6_OPC_DMODU:
+            check_mips_64(ctx);
+            gen_r6_muldiv(ctx, op2, rd, rs, rt);
+            break;
+        default:
+            MIPS_INVAL("special_r6 muldiv");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+#endif
     default:            /* Invalid */
         MIPS_INVAL("special_r6");
         generate_exception(ctx, EXCP_RI);
@@ -14512,12 +14810,13 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 
 static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
 {
-    int rs, rt, rd;
+    int rs, rt, rd, sa;
     uint32_t op1;
 
     rs = (ctx->opcode >> 21) & 0x1f;
     rt = (ctx->opcode >> 16) & 0x1f;
     rd = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 6) & 0x1f;
 
     op1 = MASK_SPECIAL(ctx->opcode);
     switch (op1) {
@@ -14545,6 +14844,27 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
             generate_exception_err(ctx, EXCP_CpU, 1);
         }
         break;
+    case OPC_MULT:
+    case OPC_MULTU:
+        if (sa) {
+            check_insn(ctx, INSN_VR54XX);
+            op1 = MASK_MUL_VR54XX(ctx->opcode);
+            gen_mul_vr54xx(ctx, op1, rd, rs, rt);
+        } else {
+            gen_muldiv(ctx, op1, rd & 3, rs, rt);
+        }
+        break;
+    case OPC_DIV:
+    case OPC_DIVU:
+        gen_muldiv(ctx, op1, 0, rs, rt);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_DMULT ... OPC_DDIVU:
+        check_insn(ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_muldiv(ctx, op1, 0, rs, rt);
+        break;
+#endif
     default:            /* Invalid */
         MIPS_INVAL("special_legacy");
         generate_exception(ctx, EXCP_RI);
@@ -14617,20 +14937,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
     case OPC_XOR:
         gen_logic(ctx, op1, rd, rs, rt);
         break;
-    case OPC_MULT:
-    case OPC_MULTU:
-        if (sa) {
-            check_insn(ctx, INSN_VR54XX);
-            op1 = MASK_MUL_VR54XX(ctx->opcode);
-            gen_mul_vr54xx(ctx, op1, rd, rs, rt);
-        } else {
-            gen_muldiv(ctx, op1, rd & 3, rs, rt);
-        }
-        break;
-    case OPC_DIV:
-    case OPC_DIVU:
-        gen_muldiv(ctx, op1, 0, rs, rt);
-        break;
     case OPC_JR ... OPC_JALR:
         gen_compute_branch(ctx, op1, 4, rs, rd, sa);
         break;
@@ -14742,11 +15048,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
             break;
         }
         break;
-    case OPC_DMULT ... OPC_DDIVU:
-        check_insn(ctx, ISA_MIPS3);
-        check_mips_64(ctx);
-        gen_muldiv(ctx, op1, 0, rs, rt);
-        break;
 #endif
     default:
         if (ctx->insn_flags & ISA_MIPS32R6) {
-- 
2.1.0

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

* [Qemu-devel] [PULL 10/28] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (8 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 09/28] target-mips: redefine Integer Multiply and Divide instructions Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 11/28] target-mips: Status.UX/SX/KX enable 32-bit address wrapping Leon Alrae
                   ` (19 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

Also consider OPC_SPIM instruction as deleted in R6 because it is overlaping
with MIPS32R6 SDBBP.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 disas/mips.c            |   5 ++
 target-mips/translate.c | 121 +++++++++++++++++++++++++-----------------------
 2 files changed, 67 insertions(+), 59 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 16cb2ac..8ee8758 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -1217,6 +1217,11 @@ const struct mips_opcode mips_builtin_opcodes[] =
    them first.  The assemblers uses a hash table based on the
    instruction name anyhow.  */
 /* name,    args,	match,	    mask,	pinfo,          	membership */
+{"clz",     "U,s",      0x00000050, 0xfc1f07ff, WR_d|RD_s,            0, I32R6},
+{"clo",     "U,s",      0x00000051, 0xfc1f07ff, WR_d|RD_s,            0, I32R6},
+{"dclz",    "U,s",      0x00000052, 0xfc1f07ff, WR_d|RD_s,            0, I64R6},
+{"dclo",    "U,s",      0x00000053, 0xfc1f07ff, WR_d|RD_s,            0, I64R6},
+{"sdbbp",   "B",        0x0000000e, 0xfc00003f, TRAP,                 0, I32R6},
 {"mul",     "d,s,t",    0x00000098, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"muh",     "d,s,t",    0x000000d8, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"mulu",    "d,s,t",    0x00000099, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 3ce9641..34d63ea 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -235,6 +235,12 @@ enum {
     R6_OPC_DMOD   = OPC_DDIV   | (3 << 6),
     R6_OPC_DDIVU  = OPC_DDIVU  | (2 << 6),
     R6_OPC_DMODU  = OPC_DDIVU  | (3 << 6),
+
+    R6_OPC_CLZ      = 0x10 | OPC_SPECIAL,
+    R6_OPC_CLO      = 0x11 | OPC_SPECIAL,
+    R6_OPC_DCLZ     = 0x12 | OPC_SPECIAL,
+    R6_OPC_DCLO     = 0x13 | OPC_SPECIAL,
+    R6_OPC_SDBBP    = 0x0e | OPC_SPECIAL,
 };
 
 /* Multiplication variants of the vr54xx. */
@@ -3263,19 +3269,23 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
     gen_load_gpr(t0, rs);
     switch (opc) {
     case OPC_CLO:
+    case R6_OPC_CLO:
         gen_helper_clo(cpu_gpr[rd], t0);
         opn = "clo";
         break;
     case OPC_CLZ:
+    case R6_OPC_CLZ:
         gen_helper_clz(cpu_gpr[rd], t0);
         opn = "clz";
         break;
 #if defined(TARGET_MIPS64)
     case OPC_DCLO:
+    case R6_OPC_DCLO:
         gen_helper_dclo(cpu_gpr[rd], t0);
         opn = "dclo";
         break;
     case OPC_DCLZ:
+    case R6_OPC_DCLZ:
         gen_helper_dclz(cpu_gpr[rd], t0);
         opn = "dclz";
         break;
@@ -14747,12 +14757,13 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2,
 
 static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 {
-    int rs, rt, rd;
+    int rs, rt, rd, sa;
     uint32_t op1, op2;
 
     rs = (ctx->opcode >> 21) & 0x1f;
     rt = (ctx->opcode >> 16) & 0x1f;
     rd = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 6) & 0x1f;
 
     op1 = MASK_SPECIAL(ctx->opcode);
     switch (op1) {
@@ -14779,7 +14790,31 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
     case OPC_SELNEZ:
         gen_cond_move(ctx, op1, rd, rs, rt);
         break;
+    case R6_OPC_CLO:
+    case R6_OPC_CLZ:
+        if (rt == 0 && sa == 1) {
+            /* Major opcode and function field is shared with preR6 MFHI/MTHI.
+               We need additionally to check other fields */
+            gen_cl(ctx, op1, rd, rs);
+        } else {
+            generate_exception(ctx, EXCP_RI);
+        }
+        break;
+    case R6_OPC_SDBBP:
+        generate_exception(ctx, EXCP_DBp);
+        break;
 #if defined(TARGET_MIPS64)
+    case R6_OPC_DCLO:
+    case R6_OPC_DCLZ:
+        if (rt == 0 && sa == 1) {
+            /* Major opcode and function field is shared with preR6 MFHI/MTHI.
+               We need additionally to check other fields */
+            check_mips_64(ctx);
+            gen_cl(ctx, op1, rd, rs);
+        } else {
+            generate_exception(ctx, EXCP_RI);
+        }
+        break;
     case OPC_DMULT ... OPC_DDIVU:
         op2 = MASK_R6_MULDIV(ctx->opcode);
         switch (op2) {
@@ -14865,6 +14900,16 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
         gen_muldiv(ctx, op1, 0, rs, rt);
         break;
 #endif
+    case OPC_SPIM:
+#ifdef MIPS_STRICT_STANDARD
+        MIPS_INVAL("SPIM");
+        generate_exception(ctx, EXCP_RI);
+#else
+        /* Implemented as RI exception for now. */
+        MIPS_INVAL("spim (unofficial)");
+        generate_exception(ctx, EXCP_RI);
+#endif
+        break;
     default:            /* Invalid */
         MIPS_INVAL("special_legacy");
         generate_exception(ctx, EXCP_RI);
@@ -14959,16 +15004,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
     case OPC_BREAK:
         generate_exception(ctx, EXCP_BREAK);
         break;
-    case OPC_SPIM:
-#ifdef MIPS_STRICT_STANDARD
-        MIPS_INVAL("SPIM");
-        generate_exception(ctx, EXCP_RI);
-#else
-        /* Implemented as RI exception for now. */
-        MIPS_INVAL("spim (unofficial)");
-        generate_exception(ctx, EXCP_RI);
-#endif
-        break;
     case OPC_SYNC:
         /* Treat as NOP. */
         break;
@@ -15058,24 +15093,13 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
     }
 }
 
-static void decode_opc_special2_r6(CPUMIPSState *env, DisasContext *ctx)
-{
-    uint32_t op1;
-
-    op1 = MASK_SPECIAL2(ctx->opcode);
-    switch (op1) {
-    default:            /* Invalid */
-        MIPS_INVAL("special2_r6");
-        generate_exception(ctx, EXCP_RI);
-        break;
-    }
-}
-
 static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd;
     uint32_t op1;
 
+    check_insn_opc_removed(ctx, ISA_MIPS32R6);
+
     rs = (ctx->opcode >> 21) & 0x1f;
     rt = (ctx->opcode >> 16) & 0x1f;
     rd = (ctx->opcode >> 11) & 0x1f;
@@ -15099,34 +15123,6 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
         check_insn(ctx, INSN_LOONGSON2F);
         gen_loongson_integer(ctx, op1, rd, rs, rt);
         break;
-#if defined(TARGET_MIPS64)
-    case OPC_DMULT_G_2F:
-    case OPC_DMULTU_G_2F:
-    case OPC_DDIV_G_2F:
-    case OPC_DDIVU_G_2F:
-    case OPC_DMOD_G_2F:
-    case OPC_DMODU_G_2F:
-        check_insn(ctx, INSN_LOONGSON2F);
-        gen_loongson_integer(ctx, op1, rd, rs, rt);
-        break;
-#endif
-    default:            /* Invalid */
-        MIPS_INVAL("special2_legacy");
-        generate_exception(ctx, EXCP_RI);
-        break;
-    }
-}
-
-static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
-{
-    int rs, rd;
-    uint32_t op1;
-
-    rs = (ctx->opcode >> 21) & 0x1f;
-    rd = (ctx->opcode >> 11) & 0x1f;
-
-    op1 = MASK_SPECIAL2(ctx->opcode);
-    switch (op1) {
     case OPC_CLO:
     case OPC_CLZ:
         check_insn(ctx, ISA_MIPS32);
@@ -15151,13 +15147,20 @@ static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
         check_mips_64(ctx);
         gen_cl(ctx, op1, rd, rs);
         break;
+    case OPC_DMULT_G_2F:
+    case OPC_DMULTU_G_2F:
+    case OPC_DDIV_G_2F:
+    case OPC_DDIVU_G_2F:
+    case OPC_DMOD_G_2F:
+    case OPC_DMODU_G_2F:
+        check_insn(ctx, INSN_LOONGSON2F);
+        gen_loongson_integer(ctx, op1, rd, rs, rt);
+        break;
 #endif
-    default:
-        if (ctx->insn_flags & ISA_MIPS32R6) {
-            decode_opc_special2_r6(env, ctx);
-        } else {
-            decode_opc_special2_legacy(env, ctx);
-        }
+    default:            /* Invalid */
+        MIPS_INVAL("special2_legacy");
+        generate_exception(ctx, EXCP_RI);
+        break;
     }
 }
 
@@ -15839,7 +15842,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         decode_opc_special(env, ctx);
         break;
     case OPC_SPECIAL2:
-        decode_opc_special2(env, ctx);
+        decode_opc_special2_legacy(env, ctx);
         break;
     case OPC_SPECIAL3:
         decode_opc_special3(env, ctx);
-- 
2.1.0

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

* [Qemu-devel] [PULL 11/28] target-mips: Status.UX/SX/KX enable 32-bit address wrapping
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (9 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 10/28] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6 Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 12/28] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Leon Alrae
                   ` (18 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

In R6 the special behaviour for data references is also specified for Kernel
and Supervisor mode. Therefore MIPS_HFLAG_UX is replaced by generic
MIPS_HFLAG_AWRAP indicating enabled 32-bit address wrapping.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 target-mips/cpu.h       | 18 ++++++++++++++----
 target-mips/translate.c |  6 +-----
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 8b9a92e..51a8331 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -450,7 +450,7 @@ struct CPUMIPSState {
        and RSQRT.D.  */
 #define MIPS_HFLAG_COP1X  0x00080 /* COP1X instructions enabled         */
 #define MIPS_HFLAG_RE     0x00100 /* Reversed endianness                */
-#define MIPS_HFLAG_UX     0x00200 /* 64-bit user mode                   */
+#define MIPS_HFLAG_AWRAP  0x00200 /* 32-bit compatibility address wrapping */
 #define MIPS_HFLAG_M16    0x00400 /* MIPS16 mode flag                   */
 #define MIPS_HFLAG_M16_SHIFT 10
     /* If translation is interrupted between the branch instruction and
@@ -725,7 +725,7 @@ static inline void compute_hflags(CPUMIPSState *env)
 {
     env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
                      MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
-                     MIPS_HFLAG_UX | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2);
+                     MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2);
     if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
         !(env->CP0_Status & (1 << CP0St_ERL)) &&
         !(env->hflags & MIPS_HFLAG_DM)) {
@@ -737,8 +737,18 @@ static inline void compute_hflags(CPUMIPSState *env)
         (env->CP0_Status & (1 << CP0St_UX))) {
         env->hflags |= MIPS_HFLAG_64;
     }
-    if (env->CP0_Status & (1 << CP0St_UX)) {
-        env->hflags |= MIPS_HFLAG_UX;
+
+    if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
+        !(env->CP0_Status & (1 << CP0St_UX))) {
+        env->hflags |= MIPS_HFLAG_AWRAP;
+    } else if (env->insn_flags & ISA_MIPS32R6) {
+        /* Address wrapping for Supervisor and Kernel is specified in R6 */
+        if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) &&
+             !(env->CP0_Status & (1 << CP0St_SX))) ||
+            (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_KM) &&
+             !(env->CP0_Status & (1 << CP0St_KX)))) {
+            env->hflags |= MIPS_HFLAG_AWRAP;
+        }
     }
 #endif
     if ((env->CP0_Status & (1 << CP0St_CU0)) ||
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 34d63ea..7420485 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1383,11 +1383,7 @@ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv
     tcg_gen_add_tl(ret, arg0, arg1);
 
 #if defined(TARGET_MIPS64)
-    /* For compatibility with 32-bit code, data reference in user mode
-       with Status_UX = 0 should be casted to 32-bit and sign extended.
-       See the MIPS64 PRA manual, section 4.10. */
-    if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
-        !(ctx->hflags & MIPS_HFLAG_UX)) {
+    if (ctx->hflags & MIPS_HFLAG_AWRAP) {
         tcg_gen_ext32s_i64(ret, ret);
     }
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL 12/28] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (10 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 11/28] target-mips: Status.UX/SX/KX enable 32-bit address wrapping Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 13/28] target-mips: add compact and CP1 branches Leon Alrae
                   ` (17 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yongbok Kim

From: Yongbok Kim <yongbok.kim@imgtec.com>

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 disas/mips.c            |   4 ++
 target-mips/helper.h    |   5 ++
 target-mips/op_helper.c |  23 ++++++++++
 target-mips/translate.c | 120 +++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 140 insertions(+), 12 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 8ee8758..61313f4 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -1246,6 +1246,10 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"cache",   "k,o(b)",   0x7c000025, 0xfc00007f, RD_b,                 0, I32R6},
 {"seleqz",  "d,v,t",    0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"selnez",  "d,v,t",    0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"align",   "d,v,t",    0x7c000220, 0xfc00073f, WR_d|RD_s|RD_t,       0, I32R6},
+{"dalign",  "d,v,t",    0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t,       0, I64R6},
+{"bitswap", "d,w",      0x7c000020, 0xffe007ff, WR_d|RD_t,            0, I32R6},
+{"dbitswap","d,w",      0x7c000024, 0xffe007ff, WR_d|RD_t,            0, I64R6},
 {"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	0,		I4|I32|G3	},
 {"prefx",   "h,t(b)",	0x4c00000f, 0xfc0007ff, RD_b|RD_t,		0,		I4|I33	},
 {"nop",     "",         0x00000000, 0xffffffff, 0,              	INSN2_ALIAS,	I1      }, /* sll */
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 74ef094..5511dfc 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -39,6 +39,11 @@ DEF_HELPER_3(macchiu, tl, env, tl, tl)
 DEF_HELPER_3(msachi, tl, env, tl, tl)
 DEF_HELPER_3(msachiu, tl, env, tl, tl)
 
+DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl)
+#ifdef TARGET_MIPS64
+DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl)
+#endif
+
 #ifndef CONFIG_USER_ONLY
 /* CP0 helpers */
 DEF_HELPER_1(mfc0_mvpcontrol, tl, env)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index df97b35..c9841e2 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -266,6 +266,29 @@ target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
                        (uint64_t)(uint32_t)arg2);
 }
 
+static inline target_ulong bitswap(target_ulong v)
+{
+    v = ((v >> 1) & (target_ulong)0x5555555555555555) |
+              ((v & (target_ulong)0x5555555555555555) << 1);
+    v = ((v >> 2) & (target_ulong)0x3333333333333333) |
+              ((v & (target_ulong)0x3333333333333333) << 2);
+    v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0F) |
+              ((v & (target_ulong)0x0F0F0F0F0F0F0F0F) << 4);
+    return v;
+}
+
+#ifdef TARGET_MIPS64
+target_ulong helper_dbitswap(target_ulong rt)
+{
+    return bitswap(rt);
+}
+#endif
+
+target_ulong helper_bitswap(target_ulong rt)
+{
+    return (int32_t)bitswap(rt);
+}
+
 #ifndef CONFIG_USER_ONLY
 
 static inline hwaddr do_translate_address(CPUMIPSState *env,
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 7420485..0052e24 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -392,17 +392,23 @@ enum {
 #define MASK_BSHFL(op)     MASK_SPECIAL3(op) | (op & (0x1F << 6))
 
 enum {
-    OPC_WSBH     = (0x02 << 6) | OPC_BSHFL,
-    OPC_SEB      = (0x10 << 6) | OPC_BSHFL,
-    OPC_SEH      = (0x18 << 6) | OPC_BSHFL,
+    OPC_WSBH      = (0x02 << 6) | OPC_BSHFL,
+    OPC_SEB       = (0x10 << 6) | OPC_BSHFL,
+    OPC_SEH       = (0x18 << 6) | OPC_BSHFL,
+    OPC_ALIGN     = (0x08 << 6) | OPC_BSHFL, /* 010.bp */
+    OPC_ALIGN_END = (0x0B << 6) | OPC_BSHFL, /* 010.00 to 010.11 */
+    OPC_BITSWAP   = (0x00 << 6) | OPC_BSHFL  /* 00000 */
 };
 
 /* DBSHFL opcodes */
 #define MASK_DBSHFL(op)    MASK_SPECIAL3(op) | (op & (0x1F << 6))
 
 enum {
-    OPC_DSBH     = (0x02 << 6) | OPC_DBSHFL,
-    OPC_DSHD     = (0x05 << 6) | OPC_DBSHFL,
+    OPC_DSBH       = (0x02 << 6) | OPC_DBSHFL,
+    OPC_DSHD       = (0x05 << 6) | OPC_DBSHFL,
+    OPC_DALIGN     = (0x08 << 6) | OPC_DBSHFL, /* 01.bp */
+    OPC_DALIGN_END = (0x0F << 6) | OPC_DBSHFL, /* 01.000 to 01.111 */
+    OPC_DBITSWAP   = (0x00 << 6) | OPC_DBSHFL, /* 00000 */
 };
 
 /* MIPS DSP REGIMM opcodes */
@@ -15162,12 +15168,14 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
 
 static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
 {
-    int rs, rt;
-    uint32_t op1;
+    int rs, rt, rd, sa;
+    uint32_t op1, op2;
     int16_t imm;
 
     rs = (ctx->opcode >> 21) & 0x1f;
     rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 6) & 0x1f;
     imm = (int16_t)ctx->opcode >> 7;
 
     op1 = MASK_SPECIAL3(ctx->opcode);
@@ -15188,6 +15196,43 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
     case R6_OPC_LL:
         gen_ld(ctx, op1, rt, rs, imm);
         break;
+    case OPC_BSHFL:
+        {
+            if (rd == 0) {
+                /* Treat as NOP. */
+                break;
+            }
+            TCGv t0 = tcg_temp_new();
+            gen_load_gpr(t0, rt);
+
+            op2 = MASK_BSHFL(ctx->opcode);
+            switch (op2) {
+            case OPC_ALIGN ... OPC_ALIGN_END:
+                sa &= 3;
+                if (sa == 0) {
+                    tcg_gen_mov_tl(cpu_gpr[rd], t0);
+                } else {
+                    TCGv t1 = tcg_temp_new();
+                    TCGv_i64 t2 = tcg_temp_new_i64();
+                    gen_load_gpr(t1, rs);
+                    tcg_gen_concat_tl_i64(t2, t1, t0);
+                    tcg_gen_shri_i64(t2, t2, 8 * (4 - sa));
+#if defined(TARGET_MIPS64)
+                    tcg_gen_ext32s_i64(cpu_gpr[rd], t2);
+#else
+                    tcg_gen_trunc_i64_i32(cpu_gpr[rd], t2);
+#endif
+                    tcg_temp_free_i64(t2);
+                    tcg_temp_free(t1);
+                }
+                break;
+            case OPC_BITSWAP:
+                gen_helper_bitswap(cpu_gpr[rd], t0);
+                break;
+            }
+            tcg_temp_free(t0);
+        }
+        break;
 #if defined(TARGET_MIPS64)
     case R6_OPC_SCD:
         gen_st_cond(ctx, op1, rt, rs, imm);
@@ -15195,6 +15240,38 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
     case R6_OPC_LLD:
         gen_ld(ctx, op1, rt, rs, imm);
         break;
+    case OPC_DBSHFL:
+        check_mips_64(ctx);
+        {
+            if (rd == 0) {
+                /* Treat as NOP. */
+                break;
+            }
+            TCGv t0 = tcg_temp_new();
+            gen_load_gpr(t0, rt);
+
+            op2 = MASK_DBSHFL(ctx->opcode);
+            switch (op2) {
+            case OPC_DALIGN ... OPC_DALIGN_END:
+                sa &= 7;
+                if (sa == 0) {
+                    tcg_gen_mov_tl(cpu_gpr[rd], t0);
+                } else {
+                    TCGv t1 = tcg_temp_new();
+                    gen_load_gpr(t1, rs);
+                    tcg_gen_shli_tl(t0, t0, 8 * sa);
+                    tcg_gen_shri_tl(t1, t1, 8 * (8 - sa));
+                    tcg_gen_or_tl(cpu_gpr[rd], t1, t0);
+                    tcg_temp_free(t1);
+                }
+                break;
+            case OPC_DBITSWAP:
+                gen_helper_dbitswap(cpu_gpr[rd], t0);
+                break;
+            }
+            tcg_temp_free(t0);
+        }
+        break;
 #endif
     default:            /* Invalid */
         MIPS_INVAL("special3_r6");
@@ -15743,9 +15820,18 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
         gen_bitops(ctx, op1, rt, rs, sa, rd);
         break;
     case OPC_BSHFL:
-        check_insn(ctx, ISA_MIPS32R2);
         op2 = MASK_BSHFL(ctx->opcode);
-        gen_bshfl(ctx, op2, rt, rd);
+        switch (op2) {
+        case OPC_ALIGN ... OPC_ALIGN_END:
+        case OPC_BITSWAP:
+            check_insn(ctx, ISA_MIPS32R6);
+            decode_opc_special3_r6(env, ctx);
+            break;
+        default:
+            check_insn(ctx, ISA_MIPS32R2);
+            gen_bshfl(ctx, op2, rt, rd);
+            break;
+        }
         break;
 #if defined(TARGET_MIPS64)
     case OPC_DEXTM ... OPC_DEXT:
@@ -15755,10 +15841,20 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
         gen_bitops(ctx, op1, rt, rs, sa, rd);
         break;
     case OPC_DBSHFL:
-        check_insn(ctx, ISA_MIPS64R2);
-        check_mips_64(ctx);
         op2 = MASK_DBSHFL(ctx->opcode);
-        gen_bshfl(ctx, op2, rt, rd);
+        switch (op2) {
+        case OPC_DALIGN ... OPC_DALIGN_END:
+        case OPC_DBITSWAP:
+            check_insn(ctx, ISA_MIPS32R6);
+            decode_opc_special3_r6(env, ctx);
+            break;
+        default:
+            check_insn(ctx, ISA_MIPS64R2);
+            check_mips_64(ctx);
+            op2 = MASK_DBSHFL(ctx->opcode);
+            gen_bshfl(ctx, op2, rt, rd);
+            break;
+        }
         break;
 #endif
     case OPC_RDHWR:
-- 
2.1.0

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

* [Qemu-devel] [PULL 13/28] target-mips: add compact and CP1 branches
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (11 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 12/28] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 14/28] target-mips: add AUI, LSA and PCREL instruction families Leon Alrae
                   ` (16 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yongbok Kim

From: Yongbok Kim <yongbok.kim@imgtec.com>

Introduce MIPS32R6 Compact Branch instructions which do not have delay slot -
they have forbidden slot instead. However, current implementation does not
support forbidden slot yet.

Add also BC1EQZ and BC1NEZ instructions.

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 disas/mips.c            |  67 ++++++-
 target-mips/translate.c | 473 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 523 insertions(+), 17 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 61313f4..8234369 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -1250,6 +1250,34 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"dalign",  "d,v,t",    0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t,       0, I64R6},
 {"bitswap", "d,w",      0x7c000020, 0xffe007ff, WR_d|RD_t,            0, I32R6},
 {"dbitswap","d,w",      0x7c000024, 0xffe007ff, WR_d|RD_t,            0, I64R6},
+{"balc",    "+p",       0xe8000000, 0xfc000000, UBD|WR_31,            0, I32R6},
+{"bc",      "+p",       0xc8000000, 0xfc000000, UBD|WR_31,            0, I32R6},
+{"jic",     "t,o",      0xd8000000, 0xffe00000, UBD|RD_t,             0, I32R6},
+{"beqzc",   "s,+p",     0xd8000000, 0xfc000000, CBD|RD_s,             0, I32R6},
+{"jialc",   "t,o",      0xf8000000, 0xffe00000, UBD|RD_t,             0, I32R6},
+{"bnezc",   "s,+p",     0xf8000000, 0xfc000000, CBD|RD_s,             0, I32R6},
+{"beqzalc", "s,t,p",    0x20000000, 0xffe00000, CBD|RD_s|RD_t,        0, I32R6},
+{"bovc",    "s,t,p",    0x20000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"beqc",    "s,t,p",    0x20000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bnezalc", "s,t,p",    0x60000000, 0xffe00000, CBD|RD_s|RD_t,        0, I32R6},
+{"bnvc",    "s,t,p",    0x60000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bnec",    "s,t,p",    0x60000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"blezc",   "s,t,p",    0x58000000, 0xffe00000, CBD|RD_s|RD_t,        0, I32R6},
+{"bgezc",   "s,t,p",    0x58000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bgec",    "s,t,p",    0x58000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bgtzc",   "s,t,p",    0x5c000000, 0xffe00000, CBD|RD_s|RD_t,        0, I32R6},
+{"bltzc",   "s,t,p",    0x5c000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bltc",    "s,t,p",    0x5c000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"blezalc", "s,t,p",    0x18000000, 0xffe00000, CBD|RD_s|RD_t,        0, I32R6},
+{"bgezalc", "s,t,p",    0x18000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bgeuc",   "s,t,p",    0x18000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bgtzalc", "s,t,p",    0x1c000000, 0xffe00000, CBD|RD_s|RD_t,        0, I32R6},
+{"bltzalc", "s,t,p",    0x1c000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bltuc",   "s,t,p",    0x1c000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"bc1eqz",  "T,p",      0x45200000, 0xffe00000, CBD|RD_T|FP_S|FP_D,   0, I32R6},
+{"bc1nez",  "T,p",      0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D,   0, I32R6},
+{"bc2eqz",  "E,p",      0x49200000, 0xffe00000, CBD|RD_C2,            0, I32R6},
+{"bc2nez",  "E,p",      0x49a00000, 0xffe00000, CBD|RD_C2,            0, I32R6},
 {"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	0,		I4|I32|G3	},
 {"prefx",   "h,t(b)",	0x4c00000f, 0xfc0007ff, RD_b|RD_t,		0,		I4|I33	},
 {"nop",     "",         0x00000000, 0xffffffff, 0,              	INSN2_ALIAS,	I1      }, /* sll */
@@ -3616,6 +3644,24 @@ print_insn_args (const char *d,
 	      (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
 	      break;
 
+            case 'o':
+                delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6;
+                if (delta & 0x8000) {
+                    delta |= ~0xffff;
+                }
+                (*info->fprintf_func) (info->stream, "%d", delta);
+                break;
+
+            case 'p':
+                /* Sign extend the displacement with 26 bits.  */
+                delta = (l >> OP_SH_DELTA) & OP_MASK_TARGET;
+                if (delta & 0x2000000) {
+                    delta |= ~0x3FFFFFF;
+                }
+                info->target = (delta << 2) + pc + INSNLEN;
+                (*info->print_address_func) (info->target, info);
+                break;
+
 	    case 't': /* Coprocessor 0 reg name */
 	      (*info->fprintf_func) (info->stream, "%s",
 				     mips_cp0_names[(l >> OP_SH_RT) &
@@ -3767,9 +3813,7 @@ print_insn_args (const char *d,
 
 	case 'j': /* Same as i, but sign-extended.  */
 	case 'o':
-            delta = (opp->membership == I32R6) ?
-                (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6 :
-                (l >> OP_SH_DELTA) & OP_MASK_DELTA;
+            delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
 
 	  if (delta & 0x8000)
 	    delta |= ~0xffff;
@@ -4096,6 +4140,23 @@ print_insn_mips (bfd_vma memaddr,
 		  && strcmp (op->name, "jalx"))
 		continue;
 
+              if (strcmp(op->name, "bovc") == 0
+                  || strcmp(op->name, "bnvc") == 0) {
+                  if (((word >> OP_SH_RS) & OP_MASK_RS) <
+                      ((word >> OP_SH_RT) & OP_MASK_RT)) {
+                      continue;
+                  }
+              }
+              if (strcmp(op->name, "bgezc") == 0
+                  || strcmp(op->name, "bltzc") == 0
+                  || strcmp(op->name, "bgezalc") == 0
+                  || strcmp(op->name, "bltzalc") == 0) {
+                  if (((word >> OP_SH_RS) & OP_MASK_RS) !=
+                      ((word >> OP_SH_RT) & OP_MASK_RT)) {
+                      continue;
+                  }
+              }
+
 	      /* Figure out instruction type and branch delay information.  */
 	      if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
 	        {
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 0052e24..06ececb 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -111,6 +111,31 @@ enum {
     OPC_SWC2     = (0x3A << 26),
     OPC_SDC1     = (0x3D << 26),
     OPC_SDC2     = (0x3E << 26),
+    /* Compact Branches */
+    OPC_BLEZALC  = (0x06 << 26),
+    OPC_BGEZALC  = (0x06 << 26),
+    OPC_BGEUC    = (0x06 << 26),
+    OPC_BGTZALC  = (0x07 << 26),
+    OPC_BLTZALC  = (0x07 << 26),
+    OPC_BLTUC    = (0x07 << 26),
+    OPC_BOVC     = (0x08 << 26),
+    OPC_BEQZALC  = (0x08 << 26),
+    OPC_BEQC     = (0x08 << 26),
+    OPC_BLEZC    = (0x16 << 26),
+    OPC_BGEZC    = (0x16 << 26),
+    OPC_BGEC     = (0x16 << 26),
+    OPC_BGTZC    = (0x17 << 26),
+    OPC_BLTZC    = (0x17 << 26),
+    OPC_BLTC     = (0x17 << 26),
+    OPC_BNVC     = (0x18 << 26),
+    OPC_BNEZALC  = (0x18 << 26),
+    OPC_BNEC     = (0x18 << 26),
+    OPC_BC       = (0x32 << 26),
+    OPC_BEQZC    = (0x36 << 26),
+    OPC_JIC      = (0x36 << 26),
+    OPC_BALC     = (0x3A << 26),
+    OPC_BNEZC    = (0x3E << 26),
+    OPC_JIALC    = (0x3E << 26),
     /* MDMX ASE specific */
     OPC_MDMX     = (0x1E << 26),
     /* Cache and prefetch */
@@ -897,6 +922,8 @@ enum {
     OPC_W_FMT    = (FMT_W << 21) | OPC_CP1,
     OPC_L_FMT    = (FMT_L << 21) | OPC_CP1,
     OPC_PS_FMT   = (FMT_PS << 21) | OPC_CP1,
+    OPC_BC1EQZ   = (0x09 << 21) | OPC_CP1,
+    OPC_BC1NEZ   = (0x0D << 21) | OPC_CP1,
 };
 
 #define MASK_CP1_FUNC(op)       MASK_CP1(op) | (op & 0x3F)
@@ -931,6 +958,8 @@ enum {
     OPC_CTC2    = (0x06 << 21) | OPC_CP2,
     OPC_MTHC2   = (0x07 << 21) | OPC_CP2,
     OPC_BC2     = (0x08 << 21) | OPC_CP2,
+    OPC_BC2EQZ  = (0x09 << 21) | OPC_CP2,
+    OPC_BC2NEZ  = (0x0D << 21) | OPC_CP2,
 };
 
 #define MASK_LMI(op)  (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F))
@@ -1395,6 +1424,20 @@ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv
 #endif
 }
 
+/* Addresses computation (translation time) */
+static target_long addr_add(DisasContext *ctx, target_long base,
+                            target_long offset)
+{
+    target_long sum = base + offset;
+
+#if defined(TARGET_MIPS64)
+    if (ctx->hflags & MIPS_HFLAG_AWRAP) {
+        sum = (int32_t)sum;
+    }
+#endif
+    return sum;
+}
+
 static inline void check_cp0_enabled(DisasContext *ctx)
 {
     if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0)))
@@ -7433,6 +7476,55 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op,
     tcg_temp_free_i32(t0);
 }
 
+/* R6 CP1 Branches */
+static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op,
+                                   int32_t ft, int32_t offset)
+{
+    target_ulong btarget;
+    const char *opn = "cp1 cond branch";
+    TCGv_i64 t0 = tcg_temp_new_i64();
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+#ifdef MIPS_DEBUG_DISAS
+        LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc);
+#endif
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+
+    gen_load_fpr64(ctx, t0, ft);
+    tcg_gen_andi_i64(t0, t0, 1);
+
+    btarget = addr_add(ctx, ctx->pc + 4, offset);
+
+    switch (op) {
+    case OPC_BC1EQZ:
+        tcg_gen_xori_i64(t0, t0, 1);
+        opn = "bc1eqz";
+        ctx->hflags |= MIPS_HFLAG_BC;
+        break;
+    case OPC_BC1NEZ:
+        /* t0 already set */
+        opn = "bc1nez";
+        ctx->hflags |= MIPS_HFLAG_BC;
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+
+    tcg_gen_trunc_i64_tl(bcond, t0);
+
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
+               ctx->hflags, btarget);
+    ctx->btarget = btarget;
+
+out:
+    tcg_temp_free_i64(t0);
+}
+
 /* Coprocessor 1 (FPU) */
 
 #define FOP(func, fmt) (((fmt) << 21) | (func))
@@ -9438,7 +9530,7 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
     tcg_temp_free(t0);
 }
 
-static void handle_delay_slot(DisasContext *ctx, int insn_bytes)
+static void gen_branch(DisasContext *ctx, int insn_bytes)
 {
     if (ctx->hflags & MIPS_HFLAG_BMASK) {
         int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK;
@@ -14757,6 +14849,242 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2,
 
 /* End MIPSDSP functions. */
 
+/* Compact Branches */
+static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc,
+                                       int rs, int rt, int32_t offset)
+{
+    int bcond_compute = 0;
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+#ifdef MIPS_DEBUG_DISAS
+        LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc);
+#endif
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+
+    /* Load needed operands and calculate btarget */
+    switch (opc) {
+    /* compact branch */
+    case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */
+    case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */
+        gen_load_gpr(t0, rs);
+        gen_load_gpr(t1, rt);
+        bcond_compute = 1;
+        ctx->btarget = addr_add(ctx, ctx->pc + 4, offset);
+        if (rs <= rt && rs == 0) {
+            /* OPC_BEQZALC, OPC_BNEZALC */
+            tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4);
+        }
+        break;
+    case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */
+    case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */
+        gen_load_gpr(t0, rs);
+        gen_load_gpr(t1, rt);
+        bcond_compute = 1;
+        ctx->btarget = addr_add(ctx, ctx->pc + 4, offset);
+        break;
+    case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */
+    case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */
+        if (rs == 0 || rs == rt) {
+            /* OPC_BLEZALC, OPC_BGEZALC */
+            /* OPC_BGTZALC, OPC_BLTZALC */
+            tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4);
+        }
+        gen_load_gpr(t0, rs);
+        gen_load_gpr(t1, rt);
+        bcond_compute = 1;
+        ctx->btarget = addr_add(ctx, ctx->pc + 4, offset);
+        break;
+    case OPC_BC:
+    case OPC_BALC:
+        ctx->btarget = addr_add(ctx, ctx->pc + 4, offset);
+        break;
+    case OPC_BEQZC:
+    case OPC_BNEZC:
+        if (rs != 0) {
+            /* OPC_BEQZC, OPC_BNEZC */
+            gen_load_gpr(t0, rs);
+            bcond_compute = 1;
+            ctx->btarget = addr_add(ctx, ctx->pc + 4, offset);
+        } else {
+            /* OPC_JIC, OPC_JIALC */
+            TCGv tbase = tcg_temp_new();
+            TCGv toffset = tcg_temp_new();
+
+            gen_load_gpr(tbase, rt);
+            tcg_gen_movi_tl(toffset, offset);
+            gen_op_addr_add(ctx, btarget, tbase, toffset);
+            tcg_temp_free(tbase);
+            tcg_temp_free(toffset);
+        }
+        break;
+    default:
+        MIPS_INVAL("Compact branch/jump");
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+
+    if (bcond_compute == 0) {
+        /* Uncoditional compact branch */
+        switch (opc) {
+        case OPC_JIALC:
+            tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4);
+            /* Fallthrough */
+        case OPC_JIC:
+            ctx->hflags |= MIPS_HFLAG_BR;
+            break;
+        case OPC_BALC:
+            tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4);
+            /* Fallthrough */
+        case OPC_BC:
+            ctx->hflags |= MIPS_HFLAG_B;
+            break;
+        default:
+            MIPS_INVAL("Compact branch/jump");
+            generate_exception(ctx, EXCP_RI);
+            goto out;
+        }
+
+        /* Generating branch here as compact branches don't have delay slot */
+        gen_branch(ctx, 4);
+    } else {
+        /* Conditional compact branch */
+        int l1 = gen_new_label();
+        save_cpu_state(ctx, 0);
+
+        switch (opc) {
+        case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */
+            if (rs == 0 && rt != 0) {
+                /* OPC_BLEZALC */
+                tcg_gen_brcondi_tl(TCG_COND_LE, t1, 0, l1);
+            } else if (rs != 0 && rt != 0 && rs == rt) {
+                /* OPC_BGEZALC */
+                tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+            } else {
+                /* OPC_BGEUC */
+                tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
+            }
+            break;
+        case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */
+            if (rs == 0 && rt != 0) {
+                /* OPC_BGTZALC */
+                tcg_gen_brcondi_tl(TCG_COND_GT, t1, 0, l1);
+            } else if (rs != 0 && rt != 0 && rs == rt) {
+                /* OPC_BLTZALC */
+                tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1);
+            } else {
+                /* OPC_BLTUC */
+                tcg_gen_brcond_tl(TCG_COND_LTU, t0, t1, l1);
+            }
+            break;
+        case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */
+            if (rs == 0 && rt != 0) {
+                /* OPC_BLEZC */
+                tcg_gen_brcondi_tl(TCG_COND_LE, t1, 0, l1);
+            } else if (rs != 0 && rt != 0 && rs == rt) {
+                /* OPC_BGEZC */
+                tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
+            } else {
+                /* OPC_BGEC */
+                tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
+            }
+            break;
+        case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */
+            if (rs == 0 && rt != 0) {
+                /* OPC_BGTZC */
+                tcg_gen_brcondi_tl(TCG_COND_GT, t1, 0, l1);
+            } else if (rs != 0 && rt != 0 && rs == rt) {
+                /* OPC_BLTZC */
+                tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1);
+            } else {
+                /* OPC_BLTC */
+                tcg_gen_brcond_tl(TCG_COND_LT, t0, t1, l1);
+            }
+            break;
+        case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */
+        case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */
+            if (rs >= rt) {
+                /* OPC_BOVC, OPC_BNVC */
+                TCGv t2 = tcg_temp_new();
+                TCGv t3 = tcg_temp_new();
+                TCGv t4 = tcg_temp_new();
+                TCGv input_overflow = tcg_temp_new();
+
+                gen_load_gpr(t0, rs);
+                gen_load_gpr(t1, rt);
+                tcg_gen_ext32s_tl(t2, t0);
+                tcg_gen_setcond_tl(TCG_COND_NE, input_overflow, t2, t0);
+                tcg_gen_ext32s_tl(t3, t1);
+                tcg_gen_setcond_tl(TCG_COND_NE, t4, t3, t1);
+                tcg_gen_or_tl(input_overflow, input_overflow, t4);
+
+                tcg_gen_add_tl(t4, t2, t3);
+                tcg_gen_ext32s_tl(t4, t4);
+                tcg_gen_xor_tl(t2, t2, t3);
+                tcg_gen_xor_tl(t3, t4, t3);
+                tcg_gen_andc_tl(t2, t3, t2);
+                tcg_gen_setcondi_tl(TCG_COND_LT, t4, t2, 0);
+                tcg_gen_or_tl(t4, t4, input_overflow);
+                if (opc == OPC_BOVC) {
+                    /* OPC_BOVC */
+                    tcg_gen_brcondi_tl(TCG_COND_NE, t4, 0, l1);
+                } else {
+                    /* OPC_BNVC */
+                    tcg_gen_brcondi_tl(TCG_COND_EQ, t4, 0, l1);
+                }
+                tcg_temp_free(input_overflow);
+                tcg_temp_free(t4);
+                tcg_temp_free(t3);
+                tcg_temp_free(t2);
+            } else if (rs < rt && rs == 0) {
+                /* OPC_BEQZALC, OPC_BNEZALC */
+                if (opc == OPC_BEQZALC) {
+                    /* OPC_BEQZALC */
+                    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
+                } else {
+                    /* OPC_BNEZALC */
+                    tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+                }
+            } else {
+                /* OPC_BEQC, OPC_BNEC */
+                if (opc == OPC_BEQC) {
+                    /* OPC_BEQC */
+                    tcg_gen_brcond_tl(TCG_COND_EQ, t0, t1, l1);
+                } else {
+                    /* OPC_BNEC */
+                    tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l1);
+                }
+            }
+            break;
+        case OPC_BEQZC:
+            tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
+            break;
+        case OPC_BNEZC:
+            tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1);
+            break;
+        default:
+            MIPS_INVAL("Compact conditional branch/jump");
+            generate_exception(ctx, EXCP_RI);
+            goto out;
+        }
+
+        /* Generating branch here as compact branches don't have delay slot */
+        /* TODO: implement forbidden slot */
+        gen_goto_tb(ctx, 1, ctx->pc + 4);
+        gen_set_label(l1);
+        gen_goto_tb(ctx, 0, ctx->btarget);
+        MIPS_DEBUG("Compact conditional branch");
+        ctx->bstate = BS_BRANCH;
+    }
+
+out:
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
 static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd, sa;
@@ -16063,7 +16391,16 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
         }
         break;
-    case OPC_ADDI: /* Arithmetic with immediate opcode */
+    case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC, OPC_ADDI */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_BOVC, OPC_BEQZALC, OPC_BEQC */
+            gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
+        } else {
+            /* OPC_ADDI */
+            /* Arithmetic with immediate opcode */
+            gen_arith_imm(ctx, op, rt, rs, imm);
+        }
+        break;
     case OPC_ADDIU:
          gen_arith_imm(ctx, op, rt, rs, imm);
          break;
@@ -16081,9 +16418,58 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
          gen_compute_branch(ctx, op, 4, rs, rt, offset);
          break;
-    case OPC_BEQL ... OPC_BGTZL:  /* Branch */
+    /* Branch */
+    case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC, OPC_BLEZL */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            if (rt == 0) {
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            /* OPC_BLEZC, OPC_BGEZC, OPC_BGEC */
+            gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
+        } else {
+            /* OPC_BLEZL */
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+        }
+        break;
+    case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC, OPC_BGTZL */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            if (rt == 0) {
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            /* OPC_BGTZC, OPC_BLTZC, OPC_BLTC */
+            gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
+        } else {
+            /* OPC_BGTZL */
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+        }
+        break;
+    case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC, OPC_BLEZ */
+        if (rt == 0) {
+            /* OPC_BLEZ */
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+        } else {
+            check_insn(ctx, ISA_MIPS32R6);
+            /* OPC_BLEZALC, OPC_BGEZALC, OPC_BGEUC */
+            gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
+        }
+        break;
+    case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC, OPC_BGTZ */
+        if (rt == 0) {
+            /* OPC_BGTZ */
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+        } else {
+            check_insn(ctx, ISA_MIPS32R6);
+            /* OPC_BGTZALC, OPC_BLTZALC, OPC_BLTUC */
+            gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
+        }
+        break;
+    case OPC_BEQL:
+    case OPC_BNEL:
          check_insn_opc_removed(ctx, ISA_MIPS32R6);
-    case OPC_BEQ ... OPC_BGTZ:
+    case OPC_BEQ:
+    case OPC_BNE:
          gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
          break;
     case OPC_LWL: /* Load and stores */
@@ -16146,7 +16532,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
                 gen_cp1(ctx, op1, rt, rd);
                 break;
 #endif
-            case OPC_BC1ANY2:
+            case OPC_BC1EQZ: /* OPC_BC1ANY2 */
+                if (ctx->insn_flags & ISA_MIPS32R6) {
+                    /* OPC_BC1EQZ */
+                    gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode),
+                                    rt, imm << 2);
+                } else {
+                    /* OPC_BC1ANY2 */
+                    check_cop1x(ctx);
+                    check_insn(ctx, ASE_MIPS3D);
+                    gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
+                                    (rt >> 2) & 0x7, imm << 2);
+                }
+                break;
+            case OPC_BC1NEZ:
+                check_insn(ctx, ISA_MIPS32R6);
+                gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode),
+                                rt, imm << 2);
+                break;
             case OPC_BC1ANY4:
                 check_insn_opc_removed(ctx, ISA_MIPS32R6);
                 check_cop1x(ctx);
@@ -16176,13 +16579,35 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         }
         break;
 
-    /* COP2.  */
-    case OPC_LWC2:
-    case OPC_LDC2:
-    case OPC_SWC2:
-    case OPC_SDC2:
-        /* COP2: Not implemented. */
-        generate_exception_err(ctx, EXCP_CpU, 2);
+    /* Compact branches [R6] and COP2 [non-R6] */
+    case OPC_BC: /* OPC_LWC2 */
+    case OPC_BALC: /* OPC_SWC2 */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_BC, OPC_BALC */
+            gen_compute_compact_branch(ctx, op, 0, 0,
+                                       sextract32(ctx->opcode << 2, 0, 28));
+        } else {
+            /* OPC_LWC2, OPC_SWC2 */
+            /* COP2: Not implemented. */
+            generate_exception_err(ctx, EXCP_CpU, 2);
+        }
+        break;
+    case OPC_BEQZC: /* OPC_JIC, OPC_LDC2 */
+    case OPC_BNEZC: /* OPC_JIALC, OPC_SDC2 */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            if (rs != 0) {
+                /* OPC_BEQZC, OPC_BNEZC */
+                gen_compute_compact_branch(ctx, op, rs, 0,
+                                           sextract32(ctx->opcode << 2, 0, 23));
+            } else {
+                /* OPC_JIC, OPC_JIALC */
+                gen_compute_compact_branch(ctx, op, 0, rt, imm);
+            }
+        } else {
+            /* OPC_LWC2, OPC_SWC2 */
+            /* COP2: Not implemented. */
+            generate_exception_err(ctx, EXCP_CpU, 2);
+        }
         break;
     case OPC_CP2:
         check_insn(ctx, INSN_LOONGSON2F);
@@ -16256,12 +16681,31 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         check_mips_64(ctx);
         gen_st_cond(ctx, op, rt, rs, imm);
         break;
-    case OPC_DADDI:
+    case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC, OPC_DADDI */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_BNVC, OPC_BNEZALC, OPC_BNEC */
+            gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
+        } else {
+            /* OPC_DADDI */
+            check_insn(ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_arith_imm(ctx, op, rt, rs, imm);
+        }
+        break;
     case OPC_DADDIU:
         check_insn(ctx, ISA_MIPS3);
         check_mips_64(ctx);
         gen_arith_imm(ctx, op, rt, rs, imm);
         break;
+#else
+    case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
+        } else {
+            MIPS_INVAL("major opcode");
+            generate_exception(ctx, EXCP_RI);
+        }
+        break;
 #endif
     case OPC_JALX:
         check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS);
@@ -16368,8 +16812,9 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
             ctx.bstate = BS_STOP;
             break;
         }
+
         if (is_delay) {
-            handle_delay_slot(&ctx, insn_bytes);
+            gen_branch(&ctx, insn_bytes);
         }
         ctx.pc += insn_bytes;
 
-- 
2.1.0

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

* [Qemu-devel] [PULL 14/28] target-mips: add AUI, LSA and PCREL instruction families
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (12 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 13/28] target-mips: add compact and CP1 branches Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 15/28] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag Leon Alrae
                   ` (15 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
 disas/mips.c            |  42 +++++++++-
 target-mips/translate.c | 203 ++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 228 insertions(+), 17 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 8234369..850cb65 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -407,6 +407,12 @@ struct mips_opcode
    "+3" UDI immediate bits 6-20
    "+4" UDI immediate bits 6-25
 
+   R6 immediates/displacements :
+   (adding suffix to 'o' to avoid adding new characters)
+   "+o"  9 bits immediate/displacement (shift = 7)
+   "+o1" 18 bits immediate/displacement (shift = 0)
+   "+o2" 19 bits immediate/displacement (shift = 0)
+
    Other:
    "()" parens surrounding optional value
    ","  separates operands
@@ -1217,6 +1223,17 @@ const struct mips_opcode mips_builtin_opcodes[] =
    them first.  The assemblers uses a hash table based on the
    instruction name anyhow.  */
 /* name,    args,	match,	    mask,	pinfo,          	membership */
+{"lwpc",    "s,+o2",    0xec080000, 0xfc180000, WR_d,                 0, I32R6},
+{"lwupc",   "s,+o2",    0xec100000, 0xfc180000, WR_d,                 0, I64R6},
+{"ldpc",    "s,+o1",    0xec180000, 0xfc1c0000, WR_d,                 0, I64R6},
+{"addiupc", "s,+o2",    0xec000000, 0xfc180000, WR_d,                 0, I32R6},
+{"auipc",   "s,u",      0xec1e0000, 0xfc1f0000, WR_d,                 0, I32R6},
+{"aluipc",  "s,u",      0xec1f0000, 0xfc1f0000, WR_d,                 0, I32R6},
+{"daui",    "s,t,u",    0x74000000, 0xfc000000, RD_s|WR_t,            0, I64R6},
+{"dahi",    "s,u",      0x04060000, 0xfc1f0000, RD_s,                 0, I64R6},
+{"dati",    "s,u",      0x041e0000, 0xfc1f0000, RD_s,                 0, I64R6},
+{"lsa",     "d,s,t",    0x00000005, 0xfc00073f, WR_d|RD_s|RD_t,       0, I32R6},
+{"dlsa",    "d,s,t",    0x00000015, 0xfc00073f, WR_d|RD_s|RD_t,       0, I64R6},
 {"clz",     "U,s",      0x00000050, 0xfc1f07ff, WR_d|RD_s,            0, I32R6},
 {"clo",     "U,s",      0x00000051, 0xfc1f07ff, WR_d|RD_s,            0, I32R6},
 {"dclz",    "U,s",      0x00000052, 0xfc1f07ff, WR_d|RD_s,            0, I64R6},
@@ -1822,6 +1839,7 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"lld",	    "t,o(b)",	0xd0000000, 0xfc000000, LDD|RD_b|WR_t,		0,		I3	},
 {"lld",     "t,A(b)",	0,    (int) M_LLD_AB,	INSN_MACRO,		0,		I3	},
 {"lui",     "t,u",	0x3c000000, 0xffe00000,	WR_t,			0,		I1	},
+{"aui",     "s,t,u",    0x3c000000, 0xfc000000, RD_s|WR_t,            0, I32R6},
 {"luxc1",   "D,t(b)",	0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0,		I5|I33|N55},
 {"lw",      "t,o(b)",	0x8c000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
 {"lw",      "t,A(b)",	0,    (int) M_LW_AB,	INSN_MACRO,		0,		I1	},
@@ -3645,10 +3663,28 @@ print_insn_args (const char *d,
 	      break;
 
             case 'o':
-                delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6;
-                if (delta & 0x8000) {
-                    delta |= ~0xffff;
+                switch (*(d+1)) {
+                case '1':
+                    d++;
+                    delta = l & ((1 << 18) - 1);
+                    if (delta & 0x20000) {
+                        delta |= ~0x1ffff;
+                    }
+                    break;
+                case '2':
+                    d++;
+                    delta = l & ((1 << 19) - 1);
+                    if (delta & 0x40000) {
+                        delta |= ~0x3ffff;
+                    }
+                    break;
+                default:
+                    delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6;
+                    if (delta & 0x8000) {
+                        delta |= ~0xffff;
+                    }
                 }
+
                 (*info->fprintf_func) (info->stream, "%d", delta);
                 break;
 
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 06ececb..45ff5fc 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -75,6 +75,7 @@ enum {
     OPC_BGTZ     = (0x07 << 26),
     OPC_BGTZL    = (0x17 << 26),
     OPC_JALX     = (0x1D << 26),  /* MIPS 16 only */
+    OPC_DAUI     = (0x1D << 26),
     OPC_JALXS    = OPC_JALX | 0x5,
     /* Load and stores */
     OPC_LDL      = (0x1A << 26),
@@ -141,8 +142,25 @@ enum {
     /* Cache and prefetch */
     OPC_CACHE    = (0x2F << 26),
     OPC_PREF     = (0x33 << 26),
-    /* Reserved major opcode */
-    OPC_MAJOR3B_RESERVED = (0x3B << 26),
+    /* PC-relative address computation / loads */
+    OPC_PCREL    = (0x3B << 26),
+};
+
+/* PC-relative address computation / loads  */
+#define MASK_OPC_PCREL_TOP2BITS(op)  (MASK_OP_MAJOR(op) | (op & (3 << 19)))
+#define MASK_OPC_PCREL_TOP5BITS(op)  (MASK_OP_MAJOR(op) | (op & (0x1f << 16)))
+enum {
+    /* Instructions determined by bits 19 and 20 */
+    OPC_ADDIUPC = OPC_PCREL | (0 << 19),
+    R6_OPC_LWPC = OPC_PCREL | (1 << 19),
+    OPC_LWUPC   = OPC_PCREL | (2 << 19),
+
+    /* Instructions determined by bits 16 ... 20 */
+    OPC_AUIPC   = OPC_PCREL | (0x1e << 16),
+    OPC_ALUIPC  = OPC_PCREL | (0x1f << 16),
+
+    /* Other */
+    R6_OPC_LDPC = OPC_PCREL | (6 << 18),
 };
 
 /* MIPS special opcodes */
@@ -231,7 +249,6 @@ enum {
     OPC_SPIM     = 0x0E | OPC_SPECIAL, /* unofficial */
     OPC_SYNC     = 0x0F | OPC_SPECIAL,
 
-    OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL,
     OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL,
     OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL,
     OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL,
@@ -266,6 +283,9 @@ enum {
     R6_OPC_DCLZ     = 0x12 | OPC_SPECIAL,
     R6_OPC_DCLO     = 0x13 | OPC_SPECIAL,
     R6_OPC_SDBBP    = 0x0e | OPC_SPECIAL,
+
+    OPC_LSA  = 0x05 | OPC_SPECIAL,
+    OPC_DLSA = 0x15 | OPC_SPECIAL,
 };
 
 /* Multiplication variants of the vr54xx. */
@@ -309,6 +329,9 @@ enum {
     OPC_TEQI     = (0x0C << 16) | OPC_REGIMM,
     OPC_TNEI     = (0x0E << 16) | OPC_REGIMM,
     OPC_SYNCI    = (0x1F << 16) | OPC_REGIMM,
+
+    OPC_DAHI     = (0x06 << 16) | OPC_REGIMM,
+    OPC_DATI     = (0x1e << 16) | OPC_REGIMM,
 };
 
 /* Special2 opcodes */
@@ -2162,8 +2185,15 @@ static void gen_logic_imm(DisasContext *ctx, uint32_t opc,
                    regnames[rs], uimm);
         break;
     case OPC_LUI:
-        tcg_gen_movi_tl(cpu_gpr[rt], imm << 16);
-        MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm);
+        if (rs != 0 && (ctx->insn_flags & ISA_MIPS32R6)) {
+            /* OPC_AUI */
+            tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm << 16);
+            tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]);
+            MIPS_DEBUG("aui %s, %s, %04x", regnames[rt], regnames[rs], imm);
+        } else {
+            tcg_gen_movi_tl(cpu_gpr[rt], imm << 16);
+            MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm);
+        }
         break;
 
     default:
@@ -2767,6 +2797,77 @@ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg)
     MIPS_DEBUG("%s %s", opn, regnames[reg]);
 }
 
+static inline void gen_r6_ld(target_long addr, int reg, int memidx,
+                             TCGMemOp memop)
+{
+    TCGv t0 = tcg_const_tl(addr);
+    tcg_gen_qemu_ld_tl(t0, t0, memidx, memop);
+    gen_store_gpr(t0, reg);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_pcrel(DisasContext *ctx, int rs, int16_t imm)
+{
+    target_long offset;
+    target_long addr;
+
+    switch (MASK_OPC_PCREL_TOP2BITS(ctx->opcode)) {
+    case OPC_ADDIUPC:
+        if (rs != 0) {
+            offset = sextract32(ctx->opcode << 2, 0, 21);
+            addr = addr_add(ctx, ctx->pc, offset);
+            tcg_gen_movi_tl(cpu_gpr[rs], addr);
+        }
+        break;
+    case R6_OPC_LWPC:
+        offset = sextract32(ctx->opcode << 2, 0, 21);
+        addr = addr_add(ctx, ctx->pc, offset);
+        gen_r6_ld(addr, rs, ctx->mem_idx, MO_TESL);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_LWUPC:
+        check_mips_64(ctx);
+        offset = sextract32(ctx->opcode << 2, 0, 21);
+        addr = addr_add(ctx, ctx->pc, offset);
+        gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEUL);
+        break;
+#endif
+    default:
+        switch (MASK_OPC_PCREL_TOP5BITS(ctx->opcode)) {
+        case OPC_AUIPC:
+            if (rs != 0) {
+                offset = imm << 16;
+                addr = addr_add(ctx, ctx->pc, offset);
+                tcg_gen_movi_tl(cpu_gpr[rs], addr);
+            }
+            break;
+        case OPC_ALUIPC:
+            if (rs != 0) {
+                offset = imm << 16;
+                addr = ~0xFFFF & addr_add(ctx, ctx->pc, offset);
+                tcg_gen_movi_tl(cpu_gpr[rs], addr);
+            }
+            break;
+#if defined(TARGET_MIPS64)
+        case R6_OPC_LDPC: /* bits 16 and 17 are part of immediate */
+        case R6_OPC_LDPC + (1 << 16):
+        case R6_OPC_LDPC + (2 << 16):
+        case R6_OPC_LDPC + (3 << 16):
+            check_mips_64(ctx);
+            offset = sextract32(ctx->opcode << 3, 0, 21);
+            addr = addr_add(ctx, (ctx->pc & ~0x7), offset);
+            gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEQ);
+            break;
+#endif
+        default:
+            MIPS_INVAL("OPC_PCREL");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    }
+}
+
 static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt)
 {
     const char *opn = "r6 mul/div";
@@ -15097,6 +15198,20 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 
     op1 = MASK_SPECIAL(ctx->opcode);
     switch (op1) {
+    case OPC_LSA:
+        if (rd != 0) {
+            int imm2 = extract32(ctx->opcode, 6, 3);
+            TCGv t0 = tcg_temp_new();
+            TCGv t1 = tcg_temp_new();
+            gen_load_gpr(t0, rs);
+            gen_load_gpr(t1, rt);
+            tcg_gen_shli_tl(t0, t0, imm2 + 1);
+            tcg_gen_add_tl(t0, t0, t1);
+            tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
+            tcg_temp_free(t1);
+            tcg_temp_free(t0);
+        }
+        break;
     case OPC_MULT ... OPC_DIVU:
         op2 = MASK_R6_MULDIV(ctx->opcode);
         switch (op2) {
@@ -15134,6 +15249,20 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
         generate_exception(ctx, EXCP_DBp);
         break;
 #if defined(TARGET_MIPS64)
+    case OPC_DLSA:
+        check_mips_64(ctx);
+        if (rd != 0) {
+            int imm2 = extract32(ctx->opcode, 6, 3);
+            TCGv t0 = tcg_temp_new();
+            TCGv t1 = tcg_temp_new();
+            gen_load_gpr(t0, rs);
+            gen_load_gpr(t1, rt);
+            tcg_gen_shli_tl(t0, t0, imm2 + 1);
+            tcg_gen_add_tl(cpu_gpr[rd], t0, t1);
+            tcg_temp_free(t1);
+            tcg_temp_free(t0);
+        }
+        break;
     case R6_OPC_DCLO:
     case R6_OPC_DCLZ:
         if (rt == 0 && sa == 1) {
@@ -15319,13 +15448,18 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
     case OPC_TNE:
         gen_trap(ctx, op1, rs, rt, -1);
         break;
-    case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
+    case OPC_LSA: /* OPC_PMON */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            decode_opc_special_r6(env, ctx);
+        } else {
+            /* Pmon entry point, also R4010 selsl */
 #ifdef MIPS_STRICT_STANDARD
-        MIPS_INVAL("PMON / selsl");
-        generate_exception(ctx, EXCP_RI);
+            MIPS_INVAL("PMON / selsl");
+            generate_exception(ctx, EXCP_RI);
 #else
-        gen_helper_0e0i(pmon, sa);
+            gen_helper_0e0i(pmon, sa);
 #endif
+        }
         break;
     case OPC_SYSCALL:
         generate_exception(ctx, EXCP_SYSCALL);
@@ -16297,6 +16431,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             check_dsp(ctx);
             gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2);
             break;
+#if defined(TARGET_MIPS64)
+        case OPC_DAHI:
+            check_insn(ctx, ISA_MIPS32R6);
+            check_mips_64(ctx);
+            if (rs != 0) {
+                tcg_gen_addi_tl(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 32);
+            }
+            MIPS_DEBUG("dahi %s, %04x", regnames[rs], imm);
+            break;
+        case OPC_DATI:
+            check_insn(ctx, ISA_MIPS32R6);
+            check_mips_64(ctx);
+            if (rs != 0) {
+                tcg_gen_addi_tl(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 48);
+            }
+            MIPS_DEBUG("dati %s, %04x", regnames[rs], imm);
+            break;
+#endif
         default:            /* Invalid */
             MIPS_INVAL("regimm");
             generate_exception(ctx, EXCP_RI);
@@ -16409,7 +16561,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          gen_slt_imm(ctx, op, rt, rs, imm);
          break;
     case OPC_ANDI: /* Arithmetic with immediate opcode */
-    case OPC_LUI:
+    case OPC_LUI: /* OPC_AUI */
     case OPC_ORI:
     case OPC_XORI:
          gen_logic_imm(ctx, op, rt, rs, imm);
@@ -16707,14 +16859,37 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         }
         break;
 #endif
-    case OPC_JALX:
-        check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS);
-        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
-        gen_compute_branch(ctx, op, 4, rs, rt, offset);
+    case OPC_DAUI: /* OPC_JALX */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+#if defined(TARGET_MIPS64)
+            /* OPC_DAUI */
+            check_mips_64(ctx);
+            if (rt != 0) {
+                TCGv t0 = tcg_temp_new();
+                gen_load_gpr(t0, rs);
+                tcg_gen_addi_tl(cpu_gpr[rt], t0, imm << 16);
+                tcg_temp_free(t0);
+            }
+            MIPS_DEBUG("daui %s, %s, %04x", regnames[rt], regnames[rs], imm);
+#else
+            generate_exception(ctx, EXCP_RI);
+            MIPS_INVAL("major opcode");
+#endif
+        } else {
+            /* OPC_JALX */
+            check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS);
+            offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+            gen_compute_branch(ctx, op, 4, rs, rt, offset);
+        }
         break;
     case OPC_MDMX:
         check_insn(ctx, ASE_MDMX);
         /* MDMX: Not implemented. */
+        break;
+    case OPC_PCREL:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_pcrel(ctx, rs, imm);
+        break;
     default:            /* Invalid */
         MIPS_INVAL("major opcode");
         generate_exception(ctx, EXCP_RI);
-- 
2.1.0

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

* [Qemu-devel] [PULL 15/28] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (13 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 14/28] target-mips: add AUI, LSA and PCREL instruction families Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 16/28] target-mips: add new Floating Point instructions Leon Alrae
                   ` (14 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

Add abs argument to the existing softfloat minmax() function and define
new float{32,64}_{min,max}nummag functions.

minnummag(x,y) returns x if |x| < |y|,
               returns y if |y| < |x|,
               otherwise minnum(x,y)

maxnummag(x,y) returns x if |x| > |y|,
               returns y if |y| > |x|,
               otherwise maxnum(x,y)

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 fpu/softfloat.c         | 37 +++++++++++++++++++++++++++++++------
 include/fpu/softfloat.h |  4 ++++
 2 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 9274ebf..16b21eb 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -7240,13 +7240,17 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
  * minnum() and maxnum correspond to the IEEE 754-2008 minNum()
  * and maxNum() operations. min() and max() are the typical min/max
  * semantics provided by many CPUs which predate that specification.
+ *
+ * minnummag() and maxnummag() functions correspond to minNumMag()
+ * and minNumMag() from the IEEE-754 2008.
  */
 #define MINMAX(s)                                                       \
 static inline float ## s float ## s ## _minmax(float ## s a, float ## s b,     \
-                                        int ismin, int isieee STATUS_PARAM) \
+                                               int ismin, int isieee,   \
+                                               int ismag STATUS_PARAM)  \
 {                                                                       \
     flag aSign, bSign;                                                  \
-    uint ## s ## _t av, bv;                                             \
+    uint ## s ## _t av, bv, aav, abv;                                   \
     a = float ## s ## _squash_input_denormal(a STATUS_VAR);             \
     b = float ## s ## _squash_input_denormal(b STATUS_VAR);             \
     if (float ## s ## _is_any_nan(a) ||                                 \
@@ -7266,6 +7270,17 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b,     \
     bSign = extractFloat ## s ## Sign(b);                               \
     av = float ## s ## _val(a);                                         \
     bv = float ## s ## _val(b);                                         \
+    if (ismag) {                                                        \
+        aav = float ## s ## _abs(av);                                   \
+        abv = float ## s ## _abs(bv);                                   \
+        if (aav != abv) {                                               \
+            if (ismin) {                                                \
+                return (aav < abv) ? a : b;                             \
+            } else {                                                    \
+                return (aav < abv) ? b : a;                             \
+            }                                                           \
+        }                                                               \
+    }                                                                   \
     if (aSign != bSign) {                                               \
         if (ismin) {                                                    \
             return aSign ? a : b;                                       \
@@ -7283,22 +7298,32 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b,     \
                                                                         \
 float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM)  \
 {                                                                       \
-    return float ## s ## _minmax(a, b, 1, 0 STATUS_VAR);                \
+    return float ## s ## _minmax(a, b, 1, 0, 0 STATUS_VAR);             \
 }                                                                       \
                                                                         \
 float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM)  \
 {                                                                       \
-    return float ## s ## _minmax(a, b, 0, 0 STATUS_VAR);                \
+    return float ## s ## _minmax(a, b, 0, 0, 0 STATUS_VAR);             \
 }                                                                       \
                                                                         \
 float ## s float ## s ## _minnum(float ## s a, float ## s b STATUS_PARAM) \
 {                                                                       \
-    return float ## s ## _minmax(a, b, 1, 1 STATUS_VAR);                \
+    return float ## s ## _minmax(a, b, 1, 1, 0 STATUS_VAR);             \
 }                                                                       \
                                                                         \
 float ## s float ## s ## _maxnum(float ## s a, float ## s b STATUS_PARAM) \
 {                                                                       \
-    return float ## s ## _minmax(a, b, 0, 1 STATUS_VAR);                \
+    return float ## s ## _minmax(a, b, 0, 1, 0 STATUS_VAR);             \
+}                                                                       \
+                                                                        \
+float ## s float ## s ## _minnummag(float ## s a, float ## s b STATUS_PARAM) \
+{                                                                       \
+    return float ## s ## _minmax(a, b, 1, 1, 1 STATUS_VAR);             \
+}                                                                       \
+                                                                        \
+float ## s float ## s ## _maxnummag(float ## s a, float ## s b STATUS_PARAM) \
+{                                                                       \
+    return float ## s ## _minmax(a, b, 0, 1, 1 STATUS_VAR);             \
 }
 
 MINMAX(32)
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index 77177c5..e32e25d 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -374,6 +374,8 @@ float32 float32_min(float32, float32 STATUS_PARAM);
 float32 float32_max(float32, float32 STATUS_PARAM);
 float32 float32_minnum(float32, float32 STATUS_PARAM);
 float32 float32_maxnum(float32, float32 STATUS_PARAM);
+float32 float32_minnummag(float32, float32 STATUS_PARAM);
+float32 float32_maxnummag(float32, float32 STATUS_PARAM);
 int float32_is_quiet_nan( float32 );
 int float32_is_signaling_nan( float32 );
 float32 float32_maybe_silence_nan( float32 );
@@ -484,6 +486,8 @@ float64 float64_min(float64, float64 STATUS_PARAM);
 float64 float64_max(float64, float64 STATUS_PARAM);
 float64 float64_minnum(float64, float64 STATUS_PARAM);
 float64 float64_maxnum(float64, float64 STATUS_PARAM);
+float64 float64_minnummag(float64, float64 STATUS_PARAM);
+float64 float64_maxnummag(float64, float64 STATUS_PARAM);
 int float64_is_quiet_nan( float64 a );
 int float64_is_signaling_nan( float64 );
 float64 float64_maybe_silence_nan( float64 );
-- 
2.1.0

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

* [Qemu-devel] [PULL 16/28] target-mips: add new Floating Point instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (14 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 15/28] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 17/28] target-mips: add new Floating Point Comparison instructions Leon Alrae
                   ` (13 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

In terms of encoding MIPS32R6 MIN.fmt, MAX.fmt, MINA.fmt, MAXA.fmt replaced
MIPS-3D RECIP1, RECIP2, RSQRT1, RSQRT2 instructions.

In R6 all Floating Point instructions are supposed to be IEEE-2008 compliant
i.e. FIR.HAS2008 always 1. However, QEMU softfloat for MIPS has not been
updated yet.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
 disas/mips.c            |  22 +++
 target-mips/helper.h    |  20 +++
 target-mips/op_helper.c | 104 ++++++++++++
 target-mips/translate.c | 441 +++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 543 insertions(+), 44 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 850cb65..fed2e5e 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -1263,6 +1263,28 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"cache",   "k,o(b)",   0x7c000025, 0xfc00007f, RD_b,                 0, I32R6},
 {"seleqz",  "d,v,t",    0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
 {"selnez",  "d,v,t",    0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t,       0, I32R6},
+{"maddf.s", "D,S,T",    0x46000018, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"maddf.d", "D,S,T",    0x46200018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"msubf.s", "D,S,T",    0x46000019, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"msubf.d", "D,S,T",    0x46200019, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"max.s",   "D,S,T",    0x4600001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"max.d",   "D,S,T",    0x4620001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"maxa.s",  "D,S,T",    0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"maxa.d",  "D,S,T",    0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"rint.s",  "D,S",      0x4600001a, 0xffff003f, WR_D|RD_S|FP_S,       0, I32R6},
+{"rint.d",  "D,S",      0x4620001a, 0xffff003f, WR_D|RD_S|FP_D,       0, I32R6},
+{"class.s", "D,S",      0x4600001b, 0xffff003f, WR_D|RD_S|FP_S,       0, I32R6},
+{"class.d", "D,S",      0x4620001b, 0xffff003f, WR_D|RD_S|FP_D,       0, I32R6},
+{"min.s",   "D,S,T",    0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"min.d",   "D,S,T",    0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"mina.s",  "D,S,T",    0x4600001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"mina.d",  "D,S,T",    0x4620001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"sel.s",   "D,S,T",    0x46000010, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"sel.d",   "D,S,T",    0x46200010, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"seleqz.s", "D,S,T",   0x46000014, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"seleqz.d", "D,S,T",   0x46200014, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"selnez.s", "D,S,T",   0x46000017, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"selnez.d", "D,S,T",   0x46200017, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
 {"align",   "d,v,t",    0x7c000220, 0xfc00073f, WR_d|RD_s|RD_t,       0, I32R6},
 {"dalign",  "d,v,t",    0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t,       0, I64R6},
 {"bitswap", "d,w",      0x7c000020, 0xffe007ff, WR_d|RD_t,            0, I32R6},
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 5511dfc..9020c7b 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -202,6 +202,25 @@ DEF_HELPER_2(float_cvtw_d, i32, env, i64)
 DEF_HELPER_3(float_addr_ps, i64, env, i64, i64)
 DEF_HELPER_3(float_mulr_ps, i64, env, i64, i64)
 
+DEF_HELPER_FLAGS_1(float_class_s, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_1(float_class_d, TCG_CALL_NO_RWG_SE, i64, i64)
+
+#define FOP_PROTO(op)                                     \
+DEF_HELPER_4(float_ ## op ## _s, i32, env, i32, i32, i32) \
+DEF_HELPER_4(float_ ## op ## _d, i64, env, i64, i64, i64)
+FOP_PROTO(maddf)
+FOP_PROTO(msubf)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op)                                \
+DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \
+DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64)
+FOP_PROTO(max)
+FOP_PROTO(maxa)
+FOP_PROTO(min)
+FOP_PROTO(mina)
+#undef FOP_PROTO
+
 #define FOP_PROTO(op)                            \
 DEF_HELPER_2(float_ ## op ## l_s, i64, env, i32) \
 DEF_HELPER_2(float_ ## op ## l_d, i64, env, i64) \
@@ -219,6 +238,7 @@ DEF_HELPER_2(float_ ## op ## _d, i64, env, i64)
 FOP_PROTO(sqrt)
 FOP_PROTO(rsqrt)
 FOP_PROTO(recip)
+FOP_PROTO(rint)
 #undef FOP_PROTO
 
 #define FOP_PROTO(op)                       \
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index c9841e2..3f449ae 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -2809,6 +2809,110 @@ FLOAT_UNOP(abs)
 FLOAT_UNOP(chs)
 #undef FLOAT_UNOP
 
+#define FLOAT_FMADDSUB(name, bits, muladd_arg)                          \
+uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
+                                          uint ## bits ## _t fs,        \
+                                          uint ## bits ## _t ft,        \
+                                          uint ## bits ## _t fd)        \
+{                                                                       \
+    uint ## bits ## _t fdret;                                           \
+                                                                        \
+    fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg,            \
+                                     &env->active_fpu.fp_status);       \
+    update_fcr31(env, GETPC());                                         \
+    return fdret;                                                       \
+}
+
+FLOAT_FMADDSUB(maddf_s, 32, 0)
+FLOAT_FMADDSUB(maddf_d, 64, 0)
+FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
+FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
+#undef FLOAT_FMADDSUB
+
+#define FLOAT_MINMAX(name, bits, minmaxfunc)                            \
+uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
+                                          uint ## bits ## _t fs,        \
+                                          uint ## bits ## _t ft)        \
+{                                                                       \
+    uint ## bits ## _t fdret;                                           \
+                                                                        \
+    fdret = float ## bits ## _ ## minmaxfunc(fs, ft,                    \
+                                           &env->active_fpu.fp_status); \
+    update_fcr31(env, GETPC());                                         \
+    return fdret;                                                       \
+}
+
+FLOAT_MINMAX(max_s, 32, maxnum)
+FLOAT_MINMAX(max_d, 64, maxnum)
+FLOAT_MINMAX(maxa_s, 32, maxnummag)
+FLOAT_MINMAX(maxa_d, 64, maxnummag)
+
+FLOAT_MINMAX(min_s, 32, minnum)
+FLOAT_MINMAX(min_d, 64, minnum)
+FLOAT_MINMAX(mina_s, 32, minnummag)
+FLOAT_MINMAX(mina_d, 64, minnummag)
+#undef FLOAT_MINMAX
+
+#define FLOAT_RINT(name, bits)                                              \
+uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,                \
+                                          uint ## bits ## _t fs)            \
+{                                                                           \
+    uint ## bits ## _t fdret;                                               \
+                                                                            \
+    fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
+    update_fcr31(env, GETPC());                                             \
+    return fdret;                                                           \
+}
+
+FLOAT_RINT(rint_s, 32)
+FLOAT_RINT(rint_d, 64)
+#undef FLOAT_RINT
+
+#define FLOAT_CLASS_SIGNALING_NAN      0x001
+#define FLOAT_CLASS_QUIET_NAN          0x002
+#define FLOAT_CLASS_NEGATIVE_INFINITY  0x004
+#define FLOAT_CLASS_NEGATIVE_NORMAL    0x008
+#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
+#define FLOAT_CLASS_NEGATIVE_ZERO      0x020
+#define FLOAT_CLASS_POSITIVE_INFINITY  0x040
+#define FLOAT_CLASS_POSITIVE_NORMAL    0x080
+#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
+#define FLOAT_CLASS_POSITIVE_ZERO      0x200
+
+#define FLOAT_CLASS(name, bits)                                      \
+uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg)    \
+{                                                                    \
+    if (float ## bits ## _is_signaling_nan(arg)) {                   \
+        return FLOAT_CLASS_SIGNALING_NAN;                            \
+    } else if (float ## bits ## _is_quiet_nan(arg)) {                \
+        return FLOAT_CLASS_QUIET_NAN;                                \
+    } else if (float ## bits ## _is_neg(arg)) {                      \
+        if (float ## bits ## _is_infinity(arg)) {                    \
+            return FLOAT_CLASS_NEGATIVE_INFINITY;                    \
+        } else if (float ## bits ## _is_zero(arg)) {                 \
+            return FLOAT_CLASS_NEGATIVE_ZERO;                        \
+        } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
+            return FLOAT_CLASS_NEGATIVE_SUBNORMAL;                   \
+        } else {                                                     \
+            return FLOAT_CLASS_NEGATIVE_NORMAL;                      \
+        }                                                            \
+    } else {                                                         \
+        if (float ## bits ## _is_infinity(arg)) {                    \
+            return FLOAT_CLASS_POSITIVE_INFINITY;                    \
+        } else if (float ## bits ## _is_zero(arg)) {                 \
+            return FLOAT_CLASS_POSITIVE_ZERO;                        \
+        } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
+            return FLOAT_CLASS_POSITIVE_SUBNORMAL;                   \
+        } else {                                                     \
+            return FLOAT_CLASS_POSITIVE_NORMAL;                      \
+        }                                                            \
+    }                                                                \
+}
+
+FLOAT_CLASS(class_s, 32)
+FLOAT_CLASS(class_d, 64)
+#undef FLOAT_CLASS
+
 /* MIPS specific unary operations */
 uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
 {
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 45ff5fc..b6713b2 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -7647,14 +7647,25 @@ enum fopcode {
     OPC_TRUNC_W_S = FOP(13, FMT_S),
     OPC_CEIL_W_S = FOP(14, FMT_S),
     OPC_FLOOR_W_S = FOP(15, FMT_S),
+    OPC_SEL_S = FOP(16, FMT_S),
     OPC_MOVCF_S = FOP(17, FMT_S),
     OPC_MOVZ_S = FOP(18, FMT_S),
     OPC_MOVN_S = FOP(19, FMT_S),
+    OPC_SELEQZ_S = FOP(20, FMT_S),
     OPC_RECIP_S = FOP(21, FMT_S),
     OPC_RSQRT_S = FOP(22, FMT_S),
+    OPC_SELNEZ_S = FOP(23, FMT_S),
+    OPC_MADDF_S = FOP(24, FMT_S),
+    OPC_MSUBF_S = FOP(25, FMT_S),
+    OPC_RINT_S = FOP(26, FMT_S),
+    OPC_CLASS_S = FOP(27, FMT_S),
+    OPC_MIN_S = FOP(28, FMT_S),
     OPC_RECIP2_S = FOP(28, FMT_S),
+    OPC_MINA_S = FOP(29, FMT_S),
     OPC_RECIP1_S = FOP(29, FMT_S),
+    OPC_MAX_S = FOP(30, FMT_S),
     OPC_RSQRT1_S = FOP(30, FMT_S),
+    OPC_MAXA_S = FOP(31, FMT_S),
     OPC_RSQRT2_S = FOP(31, FMT_S),
     OPC_CVT_D_S = FOP(33, FMT_S),
     OPC_CVT_W_S = FOP(36, FMT_S),
@@ -7693,14 +7704,25 @@ enum fopcode {
     OPC_TRUNC_W_D = FOP(13, FMT_D),
     OPC_CEIL_W_D = FOP(14, FMT_D),
     OPC_FLOOR_W_D = FOP(15, FMT_D),
+    OPC_SEL_D = FOP(16, FMT_D),
     OPC_MOVCF_D = FOP(17, FMT_D),
     OPC_MOVZ_D = FOP(18, FMT_D),
     OPC_MOVN_D = FOP(19, FMT_D),
+    OPC_SELEQZ_D = FOP(20, FMT_D),
     OPC_RECIP_D = FOP(21, FMT_D),
     OPC_RSQRT_D = FOP(22, FMT_D),
+    OPC_SELNEZ_D = FOP(23, FMT_D),
+    OPC_MADDF_D = FOP(24, FMT_D),
+    OPC_MSUBF_D = FOP(25, FMT_D),
+    OPC_RINT_D = FOP(26, FMT_D),
+    OPC_CLASS_D = FOP(27, FMT_D),
+    OPC_MIN_D = FOP(28, FMT_D),
     OPC_RECIP2_D = FOP(28, FMT_D),
+    OPC_MINA_D = FOP(29, FMT_D),
     OPC_RECIP1_D = FOP(29, FMT_D),
+    OPC_MAX_D = FOP(30, FMT_D),
     OPC_RSQRT1_D = FOP(30, FMT_D),
+    OPC_MAXA_D = FOP(31, FMT_D),
     OPC_RSQRT2_D = FOP(31, FMT_D),
     OPC_CVT_S_D = FOP(32, FMT_D),
     OPC_CVT_W_D = FOP(36, FMT_D),
@@ -7956,6 +7978,79 @@ static inline void gen_movcf_ps(DisasContext *ctx, int fs, int fd,
     gen_set_label(l2);
 }
 
+static void gen_sel_s(DisasContext *ctx, enum fopcode op1, int fd, int ft,
+                      int fs)
+{
+    TCGv_i32 t1 = tcg_const_i32(0);
+    TCGv_i32 fp0 = tcg_temp_new_i32();
+    TCGv_i32 fp1 = tcg_temp_new_i32();
+    TCGv_i32 fp2 = tcg_temp_new_i32();
+    gen_load_fpr32(fp0, fd);
+    gen_load_fpr32(fp1, ft);
+    gen_load_fpr32(fp2, fs);
+
+    switch (op1) {
+    case OPC_SEL_S:
+        tcg_gen_andi_i32(fp0, fp0, 1);
+        tcg_gen_movcond_i32(TCG_COND_NE, fp0, fp0, t1, fp1, fp2);
+        break;
+    case OPC_SELEQZ_S:
+        tcg_gen_andi_i32(fp1, fp1, 1);
+        tcg_gen_movcond_i32(TCG_COND_EQ, fp0, fp1, t1, fp2, t1);
+        break;
+    case OPC_SELNEZ_S:
+        tcg_gen_andi_i32(fp1, fp1, 1);
+        tcg_gen_movcond_i32(TCG_COND_NE, fp0, fp1, t1, fp2, t1);
+        break;
+    default:
+        MIPS_INVAL("gen_sel_s");
+        generate_exception (ctx, EXCP_RI);
+        break;
+    }
+
+    gen_store_fpr32(fp0, fd);
+    tcg_temp_free_i32(fp2);
+    tcg_temp_free_i32(fp1);
+    tcg_temp_free_i32(fp0);
+    tcg_temp_free_i32(t1);
+}
+
+static void gen_sel_d(DisasContext *ctx, enum fopcode op1, int fd, int ft,
+                      int fs)
+{
+    TCGv_i64 t1 = tcg_const_i64(0);
+    TCGv_i64 fp0 = tcg_temp_new_i64();
+    TCGv_i64 fp1 = tcg_temp_new_i64();
+    TCGv_i64 fp2 = tcg_temp_new_i64();
+    gen_load_fpr64(ctx, fp0, fd);
+    gen_load_fpr64(ctx, fp1, ft);
+    gen_load_fpr64(ctx, fp2, fs);
+
+    switch (op1) {
+    case OPC_SEL_D:
+        tcg_gen_andi_i64(fp0, fp0, 1);
+        tcg_gen_movcond_i64(TCG_COND_NE, fp0, fp0, t1, fp1, fp2);
+        break;
+    case OPC_SELEQZ_D:
+        tcg_gen_andi_i64(fp1, fp1, 1);
+        tcg_gen_movcond_i64(TCG_COND_EQ, fp0, fp1, t1, fp2, t1);
+        break;
+    case OPC_SELNEZ_D:
+        tcg_gen_andi_i64(fp1, fp1, 1);
+        tcg_gen_movcond_i64(TCG_COND_NE, fp0, fp1, t1, fp2, t1);
+        break;
+    default:
+        MIPS_INVAL("gen_sel_d");
+        generate_exception (ctx, EXCP_RI);
+        break;
+    }
+
+    gen_store_fpr64(ctx, fp0, fd);
+    tcg_temp_free_i64(fp2);
+    tcg_temp_free_i64(fp1);
+    tcg_temp_free_i64(fp0);
+    tcg_temp_free_i64(t1);
+}
 
 static void gen_farith (DisasContext *ctx, enum fopcode op1,
                         int ft, int fs, int fd, int cc)
@@ -8204,6 +8299,21 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         }
         opn = "floor.w.s";
         break;
+    case OPC_SEL_S:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_sel_s(ctx, op1, fd, ft, fs);
+        opn = "sel.s";
+        break;
+    case OPC_SELEQZ_S:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_sel_s(ctx, op1, fd, ft, fs);
+        opn = "seleqz.s";
+        break;
+    case OPC_SELNEZ_S:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_sel_s(ctx, op1, fd, ft, fs);
+        opn = "selnez.s";
+        break;
     case OPC_MOVCF_S:
         check_insn_opc_removed(ctx, ISA_MIPS32R6);
         gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
@@ -8267,59 +8377,175 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         }
         opn = "rsqrt.s";
         break;
-    case OPC_RECIP2_S:
-        check_cp1_64bitmode(ctx);
+    case OPC_MADDF_S:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
-
+            TCGv_i32 fp2 = tcg_temp_new_i32();
             gen_load_fpr32(fp0, fs);
             gen_load_fpr32(fp1, ft);
-            gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1);
+            gen_load_fpr32(fp2, fd);
+            gen_helper_float_maddf_s(fp2, cpu_env, fp0, fp1, fp2);
+            gen_store_fpr32(fp2, fd);
+            tcg_temp_free_i32(fp2);
             tcg_temp_free_i32(fp1);
-            gen_store_fpr32(fp0, fd);
             tcg_temp_free_i32(fp0);
+            opn = "maddf.s";
         }
-        opn = "recip2.s";
         break;
-    case OPC_RECIP1_S:
-        check_cp1_64bitmode(ctx);
+    case OPC_MSUBF_S:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
-
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+            TCGv_i32 fp2 = tcg_temp_new_i32();
             gen_load_fpr32(fp0, fs);
-            gen_helper_float_recip1_s(fp0, cpu_env, fp0);
-            gen_store_fpr32(fp0, fd);
+            gen_load_fpr32(fp1, ft);
+            gen_load_fpr32(fp2, fd);
+            gen_helper_float_msubf_s(fp2, cpu_env, fp0, fp1, fp2);
+            gen_store_fpr32(fp2, fd);
+            tcg_temp_free_i32(fp2);
+            tcg_temp_free_i32(fp1);
             tcg_temp_free_i32(fp0);
+            opn = "msubf.s";
         }
-        opn = "recip1.s";
         break;
-    case OPC_RSQRT1_S:
-        check_cp1_64bitmode(ctx);
+    case OPC_RINT_S:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
-
             gen_load_fpr32(fp0, fs);
-            gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0);
+            gen_helper_float_rint_s(fp0, cpu_env, fp0);
             gen_store_fpr32(fp0, fd);
             tcg_temp_free_i32(fp0);
+            opn = "rint.s";
         }
-        opn = "rsqrt1.s";
         break;
-    case OPC_RSQRT2_S:
-        check_cp1_64bitmode(ctx);
+    case OPC_CLASS_S:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(fp0, fs);
+            gen_helper_float_class_s(fp0, fp0);
+            gen_store_fpr32(fp0, fd);
+            tcg_temp_free_i32(fp0);
+            opn = "class.s";
+        }
+        break;
+    case OPC_MIN_S: /* OPC_RECIP2_S */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_MIN_S */
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+            TCGv_i32 fp2 = tcg_temp_new_i32();
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_helper_float_min_s(fp2, cpu_env, fp0, fp1);
+            gen_store_fpr32(fp2, fd);
+            tcg_temp_free_i32(fp2);
+            tcg_temp_free_i32(fp1);
+            tcg_temp_free_i32(fp0);
+            opn = "min.s";
+        } else {
+            /* OPC_RECIP2_S */
+            check_cp1_64bitmode(ctx);
+            {
+                TCGv_i32 fp0 = tcg_temp_new_i32();
+                TCGv_i32 fp1 = tcg_temp_new_i32();
+
+                gen_load_fpr32(fp0, fs);
+                gen_load_fpr32(fp1, ft);
+                gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1);
+                tcg_temp_free_i32(fp1);
+                gen_store_fpr32(fp0, fd);
+                tcg_temp_free_i32(fp0);
+            }
+            opn = "recip2.s";
+        }
+        break;
+    case OPC_MINA_S: /* OPC_RECIP1_S */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_MINA_S */
+            TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
+            TCGv_i32 fp2 = tcg_temp_new_i32();
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_helper_float_mina_s(fp2, cpu_env, fp0, fp1);
+            gen_store_fpr32(fp2, fd);
+            tcg_temp_free_i32(fp2);
+            tcg_temp_free_i32(fp1);
+            tcg_temp_free_i32(fp0);
+            opn = "mina.s";
+        } else {
+            /* OPC_RECIP1_S */
+            check_cp1_64bitmode(ctx);
+            {
+                TCGv_i32 fp0 = tcg_temp_new_i32();
 
+                gen_load_fpr32(fp0, fs);
+                gen_helper_float_recip1_s(fp0, cpu_env, fp0);
+                gen_store_fpr32(fp0, fd);
+                tcg_temp_free_i32(fp0);
+            }
+            opn = "recip1.s";
+        }
+        break;
+    case OPC_MAX_S: /* OPC_RSQRT1_S */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_MAX_S */
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
             gen_load_fpr32(fp0, fs);
             gen_load_fpr32(fp1, ft);
-            gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1);
+            gen_helper_float_max_s(fp1, cpu_env, fp0, fp1);
+            gen_store_fpr32(fp1, fd);
+            tcg_temp_free_i32(fp1);
+            tcg_temp_free_i32(fp0);
+            opn = "max.s";
+        } else {
+            /* OPC_RSQRT1_S */
+            check_cp1_64bitmode(ctx);
+            {
+                TCGv_i32 fp0 = tcg_temp_new_i32();
+
+                gen_load_fpr32(fp0, fs);
+                gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0);
+                gen_store_fpr32(fp0, fd);
+                tcg_temp_free_i32(fp0);
+            }
+            opn = "rsqrt1.s";
+        }
+        break;
+    case OPC_MAXA_S: /* OPC_RSQRT2_S */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_MAXA_S */
+            TCGv_i32 fp0 = tcg_temp_new_i32();
+            TCGv_i32 fp1 = tcg_temp_new_i32();
+            gen_load_fpr32(fp0, fs);
+            gen_load_fpr32(fp1, ft);
+            gen_helper_float_maxa_s(fp1, cpu_env, fp0, fp1);
+            gen_store_fpr32(fp1, fd);
             tcg_temp_free_i32(fp1);
-            gen_store_fpr32(fp0, fd);
             tcg_temp_free_i32(fp0);
+            opn = "maxa.s";
+        } else {
+            /* OPC_RSQRT2_S */
+            check_cp1_64bitmode(ctx);
+            {
+                TCGv_i32 fp0 = tcg_temp_new_i32();
+                TCGv_i32 fp1 = tcg_temp_new_i32();
+
+                gen_load_fpr32(fp0, fs);
+                gen_load_fpr32(fp1, ft);
+                gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1);
+                tcg_temp_free_i32(fp1);
+                gen_store_fpr32(fp0, fd);
+                tcg_temp_free_i32(fp0);
+            }
+            opn = "rsqrt2.s";
         }
-        opn = "rsqrt2.s";
         break;
     case OPC_CVT_D_S:
         check_cp1_registers(ctx, fd);
@@ -8618,6 +8844,21 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         }
         opn = "floor.w.d";
         break;
+    case OPC_SEL_D:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_sel_d(ctx, op1, fd, ft, fs);
+        opn = "sel.d";
+        break;
+    case OPC_SELEQZ_D:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_sel_d(ctx, op1, fd, ft, fs);
+        opn = "seleqz.d";
+        break;
+    case OPC_SELNEZ_D:
+        check_insn(ctx, ISA_MIPS32R6);
+        gen_sel_d(ctx, op1, fd, ft, fs);
+        opn = "selnez.d";
+        break;
     case OPC_MOVCF_D:
         check_insn_opc_removed(ctx, ISA_MIPS32R6);
         gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
@@ -8681,59 +8922,171 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         }
         opn = "rsqrt.d";
         break;
-    case OPC_RECIP2_D:
-        check_cp1_64bitmode(ctx);
+    case OPC_MADDF_D:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
-
+            TCGv_i64 fp2 = tcg_temp_new_i64();
             gen_load_fpr64(ctx, fp0, fs);
             gen_load_fpr64(ctx, fp1, ft);
-            gen_helper_float_recip2_d(fp0, cpu_env, fp0, fp1);
+            gen_load_fpr64(ctx, fp2, fd);
+            gen_helper_float_maddf_d(fp2, cpu_env, fp0, fp1, fp2);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
             tcg_temp_free_i64(fp1);
-            gen_store_fpr64(ctx, fp0, fd);
             tcg_temp_free_i64(fp0);
+            opn = "maddf.d";
         }
-        opn = "recip2.d";
         break;
-    case OPC_RECIP1_D:
-        check_cp1_64bitmode(ctx);
+    case OPC_MSUBF_D:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
-
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            TCGv_i64 fp2 = tcg_temp_new_i64();
             gen_load_fpr64(ctx, fp0, fs);
-            gen_helper_float_recip1_d(fp0, cpu_env, fp0);
-            gen_store_fpr64(ctx, fp0, fd);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_load_fpr64(ctx, fp2, fd);
+            gen_helper_float_msubf_d(fp2, cpu_env, fp0, fp1, fp2);
+            gen_store_fpr64(ctx, fp2, fd);
+            tcg_temp_free_i64(fp2);
+            tcg_temp_free_i64(fp1);
             tcg_temp_free_i64(fp0);
+            opn = "msubf.d";
         }
-        opn = "recip1.d";
         break;
-    case OPC_RSQRT1_D:
-        check_cp1_64bitmode(ctx);
+    case OPC_RINT_D:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
-
             gen_load_fpr64(ctx, fp0, fs);
-            gen_helper_float_rsqrt1_d(fp0, cpu_env, fp0);
+            gen_helper_float_rint_d(fp0, cpu_env, fp0);
             gen_store_fpr64(ctx, fp0, fd);
             tcg_temp_free_i64(fp0);
+            opn = "rint.d";
         }
-        opn = "rsqrt1.d";
         break;
-    case OPC_RSQRT2_D:
-        check_cp1_64bitmode(ctx);
+    case OPC_CLASS_D:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_helper_float_class_d(fp0, fp0);
+            gen_store_fpr64(ctx, fp0, fd);
+            tcg_temp_free_i64(fp0);
+            opn = "class.d";
+        }
+        break;
+    case OPC_MIN_D: /* OPC_RECIP2_D */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_MIN_D */
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_min_d(fp1, cpu_env, fp0, fp1);
+            gen_store_fpr64(ctx, fp1, fd);
+            tcg_temp_free_i64(fp1);
+            tcg_temp_free_i64(fp0);
+            opn = "min.d";
+        } else {
+            /* OPC_RECIP2_D */
+            check_cp1_64bitmode(ctx);
+            {
+                TCGv_i64 fp0 = tcg_temp_new_i64();
+                TCGv_i64 fp1 = tcg_temp_new_i64();
+
+                gen_load_fpr64(ctx, fp0, fs);
+                gen_load_fpr64(ctx, fp1, ft);
+                gen_helper_float_recip2_d(fp0, cpu_env, fp0, fp1);
+                tcg_temp_free_i64(fp1);
+                gen_store_fpr64(ctx, fp0, fd);
+                tcg_temp_free_i64(fp0);
+            }
+            opn = "recip2.d";
+        }
+        break;
+    case OPC_MINA_D: /* OPC_RECIP1_D */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_MINA_D */
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_mina_d(fp1, cpu_env, fp0, fp1);
+            gen_store_fpr64(ctx, fp1, fd);
+            tcg_temp_free_i64(fp1);
+            tcg_temp_free_i64(fp0);
+            opn = "mina.d";
+        } else {
+            /* OPC_RECIP1_D */
+            check_cp1_64bitmode(ctx);
+            {
+                TCGv_i64 fp0 = tcg_temp_new_i64();
+
+                gen_load_fpr64(ctx, fp0, fs);
+                gen_helper_float_recip1_d(fp0, cpu_env, fp0);
+                gen_store_fpr64(ctx, fp0, fd);
+                tcg_temp_free_i64(fp0);
+            }
+            opn = "recip1.d";
+        }
+        break;
+    case OPC_MAX_D: /*  OPC_RSQRT1_D */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_MAX_D */
+            TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
+            gen_load_fpr64(ctx, fp0, fs);
+            gen_load_fpr64(ctx, fp1, ft);
+            gen_helper_float_max_d(fp1, cpu_env, fp0, fp1);
+            gen_store_fpr64(ctx, fp1, fd);
+            tcg_temp_free_i64(fp1);
+            tcg_temp_free_i64(fp0);
+            opn = "max.d";
+        } else {
+            /* OPC_RSQRT1_D */
+            check_cp1_64bitmode(ctx);
+            {
+                TCGv_i64 fp0 = tcg_temp_new_i64();
 
+                gen_load_fpr64(ctx, fp0, fs);
+                gen_helper_float_rsqrt1_d(fp0, cpu_env, fp0);
+                gen_store_fpr64(ctx, fp0, fd);
+                tcg_temp_free_i64(fp0);
+            }
+            opn = "rsqrt1.d";
+        }
+        break;
+    case OPC_MAXA_D: /* OPC_RSQRT2_D */
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            /* OPC_MAXA_D */
+            TCGv_i64 fp0 = tcg_temp_new_i64();
+            TCGv_i64 fp1 = tcg_temp_new_i64();
             gen_load_fpr64(ctx, fp0, fs);
             gen_load_fpr64(ctx, fp1, ft);
-            gen_helper_float_rsqrt2_d(fp0, cpu_env, fp0, fp1);
+            gen_helper_float_maxa_d(fp1, cpu_env, fp0, fp1);
+            gen_store_fpr64(ctx, fp1, fd);
             tcg_temp_free_i64(fp1);
-            gen_store_fpr64(ctx, fp0, fd);
             tcg_temp_free_i64(fp0);
+            opn = "maxa.d";
+        } else {
+            /* OPC_RSQRT2_D */
+            check_cp1_64bitmode(ctx);
+            {
+                TCGv_i64 fp0 = tcg_temp_new_i64();
+                TCGv_i64 fp1 = tcg_temp_new_i64();
+
+                gen_load_fpr64(ctx, fp0, fs);
+                gen_load_fpr64(ctx, fp1, ft);
+                gen_helper_float_rsqrt2_d(fp0, cpu_env, fp0, fp1);
+                tcg_temp_free_i64(fp1);
+                gen_store_fpr64(ctx, fp0, fd);
+                tcg_temp_free_i64(fp0);
+            }
+            opn = "rsqrt2.d";
         }
-        opn = "rsqrt2.d";
         break;
     case OPC_CMP_F_D:
     case OPC_CMP_UN_D:
-- 
2.1.0

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

* [Qemu-devel] [PULL 17/28] target-mips: add new Floating Point Comparison instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (15 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 16/28] target-mips: add new Floating Point instructions Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 18/28] target-mips: do not allow Status.FR=0 mode in 64-bit FPU Leon Alrae
                   ` (12 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yongbok Kim

From: Yongbok Kim <yongbok.kim@imgtec.com>

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 disas/mips.c            |  44 +++++++++++
 target-mips/helper.h    |  27 +++++++
 target-mips/op_helper.c | 111 ++++++++++++++++++++++++++
 target-mips/translate.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 386 insertions(+), 2 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index fed2e5e..5ebb5fd 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -1317,6 +1317,50 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"bc1nez",  "T,p",      0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D,   0, I32R6},
 {"bc2eqz",  "E,p",      0x49200000, 0xffe00000, CBD|RD_C2,            0, I32R6},
 {"bc2nez",  "E,p",      0x49a00000, 0xffe00000, CBD|RD_C2,            0, I32R6},
+{"cmp.af.s",   "D,S,T", 0x46800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.un.s",   "D,S,T", 0x46800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.eq.s",   "D,S,T", 0x46800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.ueq.s",  "D,S,T", 0x46800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.lt.s",   "D,S,T", 0x46800004, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.ult.s",  "D,S,T", 0x46800005, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.le.s",   "D,S,T", 0x46800006, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.ule.s",  "D,S,T", 0x46800007, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.saf.s",  "D,S,T", 0x46800008, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.sun.s",  "D,S,T", 0x46800009, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.seq.s",  "D,S,T", 0x4680000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.sueq.s", "D,S,T", 0x4680000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.slt.s",  "D,S,T", 0x4680000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.sult.s", "D,S,T", 0x4680000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.sle.s",  "D,S,T", 0x4680000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.sule.s", "D,S,T", 0x4680000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.or.s",   "D,S,T", 0x46800011, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.une.s",  "D,S,T", 0x46800012, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.ne.s",   "D,S,T", 0x46800013, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.sor.s",  "D,S,T", 0x46800019, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.sune.s", "D,S,T", 0x4680001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.sne.s",  "D,S,T", 0x4680001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S,  0, I32R6},
+{"cmp.af.d",   "D,S,T", 0x46a00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.un.d",   "D,S,T", 0x46a00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.eq.d",   "D,S,T", 0x46a00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.ueq.d",  "D,S,T", 0x46a00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.lt.d",   "D,S,T", 0x46a00004, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.ult.d",  "D,S,T", 0x46a00005, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.le.d",   "D,S,T", 0x46a00006, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.ule.d",  "D,S,T", 0x46a00007, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.saf.d",  "D,S,T", 0x46a00008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.sun.d",  "D,S,T", 0x46a00009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.seq.d",  "D,S,T", 0x46a0000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.sueq.d", "D,S,T", 0x46a0000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.slt.d",  "D,S,T", 0x46a0000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.sult.d", "D,S,T", 0x46a0000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.sle.d",  "D,S,T", 0x46a0000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.sule.d", "D,S,T", 0x46a0000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.or.d",   "D,S,T", 0x46a00011, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.une.d",  "D,S,T", 0x46a00012, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.ne.d",   "D,S,T", 0x46a00013, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.sor.d",  "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
+{"cmp.sne.d",  "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D,  0, I32R6},
 {"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	0,		I4|I32|G3	},
 {"prefx",   "h,t(b)",	0x4c00000f, 0xfc0007ff, RD_b|RD_t,		0,		I4|I33	},
 {"nop",     "",         0x00000000, 0xffffffff, 0,              	INSN2_ALIAS,	I1      }, /* sll */
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 9020c7b..a127db5 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -304,6 +304,33 @@ FOP_PROTO(le)
 FOP_PROTO(ngt)
 #undef FOP_PROTO
 
+#define FOP_PROTO(op) \
+DEF_HELPER_3(r6_cmp_d_ ## op, i64, env, i64, i64) \
+DEF_HELPER_3(r6_cmp_s_ ## op, i32, env, i32, i32)
+FOP_PROTO(af)
+FOP_PROTO(un)
+FOP_PROTO(eq)
+FOP_PROTO(ueq)
+FOP_PROTO(lt)
+FOP_PROTO(ult)
+FOP_PROTO(le)
+FOP_PROTO(ule)
+FOP_PROTO(saf)
+FOP_PROTO(sun)
+FOP_PROTO(seq)
+FOP_PROTO(sueq)
+FOP_PROTO(slt)
+FOP_PROTO(sult)
+FOP_PROTO(sle)
+FOP_PROTO(sule)
+FOP_PROTO(or)
+FOP_PROTO(une)
+FOP_PROTO(ne)
+FOP_PROTO(sor)
+FOP_PROTO(sune)
+FOP_PROTO(sne)
+#undef FOP_PROTO
+
 /* Special functions */
 #ifndef CONFIG_USER_ONLY
 DEF_HELPER_1(tlbwi, void, env)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 3f449ae..c48ee7f 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -3388,3 +3388,114 @@ FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
                  float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
 FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+
+/* R6 compare operations */
+#define FOP_CONDN_D(op, cond)                                       \
+uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0,  \
+                         uint64_t fdt1)                             \
+{                                                                   \
+    uint64_t c;                                                     \
+    c = cond;                                                       \
+    update_fcr31(env, GETPC());                                     \
+    if (c) {                                                        \
+        return -1;                                                  \
+    } else {                                                        \
+        return 0;                                                   \
+    }                                                               \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float64_unordered_quiet() is still called. */
+FOP_CONDN_D(af,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_CONDN_D(un,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
+FOP_CONDN_D(eq,  (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+                  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(lt,  (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+                  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(le,  (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+                  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float64_unordered() is still called. */
+FOP_CONDN_D(saf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_CONDN_D(sun,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
+FOP_CONDN_D(seq,  (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(slt,  (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sle,  (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(or,   (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(une,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(ne,   (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sor,  (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
+FOP_CONDN_D(sne,  (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
+                   || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
+
+#define FOP_CONDN_S(op, cond)                                       \
+uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0,  \
+                         uint32_t fst1)                             \
+{                                                                   \
+    uint64_t c;                                                     \
+    c = cond;                                                       \
+    update_fcr31(env, GETPC());                                     \
+    if (c) {                                                        \
+        return -1;                                                  \
+    } else {                                                        \
+        return 0;                                                   \
+    }                                                               \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float32_unordered_quiet() is still called. */
+FOP_CONDN_S(af,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_CONDN_S(un,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
+FOP_CONDN_S(eq,   (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(ueq,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(lt,   (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(ult,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(le,   (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(ule,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float32_unordered() is still called. */
+FOP_CONDN_S(saf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_CONDN_S(sun,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
+FOP_CONDN_S(seq,  (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(slt,  (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sle,  (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(or,   (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(une,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(ne,   (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sor,  (float32_le(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
+FOP_CONDN_S(sne,  (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
+                   || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
diff --git a/target-mips/translate.c b/target-mips/translate.c
index b6713b2..6f57171 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1622,6 +1622,98 @@ FOP_CONDS(abs, 1, s, FMT_S, 32)
 FOP_CONDS(, 0, ps, FMT_PS, 64)
 FOP_CONDS(abs, 1, ps, FMT_PS, 64)
 #undef FOP_CONDS
+
+#define FOP_CONDNS(fmt, ifmt, bits, STORE)                              \
+static inline void gen_r6_cmp_ ## fmt(DisasContext * ctx, int n,        \
+                                      int ft, int fs, int fd)           \
+{                                                                       \
+    TCGv_i ## bits fp0 = tcg_temp_new_i ## bits();                      \
+    TCGv_i ## bits fp1 = tcg_temp_new_i ## bits();                      \
+    switch (ifmt) {                                                     \
+    case FMT_D:                                                         \
+        check_cp1_registers(ctx, fs | ft | fd);                         \
+        break;                                                          \
+    }                                                                   \
+    gen_ldcmp_fpr ## bits(ctx, fp0, fs);                                \
+    gen_ldcmp_fpr ## bits(ctx, fp1, ft);                                \
+    switch (n) {                                                        \
+    case  0:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _af(fp0, cpu_env, fp0, fp1);       \
+        break;                                                          \
+    case  1:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _un(fp0, cpu_env, fp0, fp1);       \
+        break;                                                          \
+    case  2:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _eq(fp0, cpu_env, fp0, fp1);       \
+        break;                                                          \
+    case  3:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _ueq(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case  4:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _lt(fp0, cpu_env, fp0, fp1);       \
+        break;                                                          \
+    case  5:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _ult(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case  6:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _le(fp0, cpu_env, fp0, fp1);       \
+        break;                                                          \
+    case  7:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _ule(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case  8:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _saf(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case  9:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _sun(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case 10:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _seq(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case 11:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _sueq(fp0, cpu_env, fp0, fp1);     \
+        break;                                                          \
+    case 12:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _slt(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case 13:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _sult(fp0, cpu_env, fp0, fp1);     \
+        break;                                                          \
+    case 14:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _sle(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case 15:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _sule(fp0, cpu_env, fp0, fp1);     \
+        break;                                                          \
+    case 17:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _or(fp0, cpu_env, fp0, fp1);       \
+        break;                                                          \
+    case 18:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _une(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case 19:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _ne(fp0, cpu_env, fp0, fp1);       \
+        break;                                                          \
+    case 25:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _sor(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    case 26:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _sune(fp0, cpu_env, fp0, fp1);     \
+        break;                                                          \
+    case 27:                                                            \
+        gen_helper_r6_cmp_ ## fmt ## _sne(fp0, cpu_env, fp0, fp1);      \
+        break;                                                          \
+    default:                                                            \
+        abort();                                                        \
+    }                                                                   \
+    STORE;                                                              \
+    tcg_temp_free_i ## bits (fp0);                                      \
+    tcg_temp_free_i ## bits (fp1);                                      \
+}
+
+FOP_CONDNS(d, FMT_D, 64, gen_store_fpr64(ctx, fp0, fd))
+FOP_CONDNS(s, FMT_S, 32, gen_store_fpr32(fp0, fd))
+#undef FOP_CONDNS
 #undef gen_ldcmp_fpr32
 #undef gen_ldcmp_fpr64
 
@@ -7792,6 +7884,53 @@ enum fopcode {
     OPC_CMP_NGT_PS = FOP (63, FMT_PS),
 };
 
+enum r6_f_cmp_op {
+    R6_OPC_CMP_AF_S   = FOP(0, FMT_W),
+    R6_OPC_CMP_UN_S   = FOP(1, FMT_W),
+    R6_OPC_CMP_EQ_S   = FOP(2, FMT_W),
+    R6_OPC_CMP_UEQ_S  = FOP(3, FMT_W),
+    R6_OPC_CMP_LT_S   = FOP(4, FMT_W),
+    R6_OPC_CMP_ULT_S  = FOP(5, FMT_W),
+    R6_OPC_CMP_LE_S   = FOP(6, FMT_W),
+    R6_OPC_CMP_ULE_S  = FOP(7, FMT_W),
+    R6_OPC_CMP_SAF_S  = FOP(8, FMT_W),
+    R6_OPC_CMP_SUN_S  = FOP(9, FMT_W),
+    R6_OPC_CMP_SEQ_S  = FOP(10, FMT_W),
+    R6_OPC_CMP_SEUQ_S = FOP(11, FMT_W),
+    R6_OPC_CMP_SLT_S  = FOP(12, FMT_W),
+    R6_OPC_CMP_SULT_S = FOP(13, FMT_W),
+    R6_OPC_CMP_SLE_S  = FOP(14, FMT_W),
+    R6_OPC_CMP_SULE_S = FOP(15, FMT_W),
+    R6_OPC_CMP_OR_S   = FOP(17, FMT_W),
+    R6_OPC_CMP_UNE_S  = FOP(18, FMT_W),
+    R6_OPC_CMP_NE_S   = FOP(19, FMT_W),
+    R6_OPC_CMP_SOR_S  = FOP(25, FMT_W),
+    R6_OPC_CMP_SUNE_S = FOP(26, FMT_W),
+    R6_OPC_CMP_SNE_S  = FOP(27, FMT_W),
+
+    R6_OPC_CMP_AF_D   = FOP(0, FMT_L),
+    R6_OPC_CMP_UN_D   = FOP(1, FMT_L),
+    R6_OPC_CMP_EQ_D   = FOP(2, FMT_L),
+    R6_OPC_CMP_UEQ_D  = FOP(3, FMT_L),
+    R6_OPC_CMP_LT_D   = FOP(4, FMT_L),
+    R6_OPC_CMP_ULT_D  = FOP(5, FMT_L),
+    R6_OPC_CMP_LE_D   = FOP(6, FMT_L),
+    R6_OPC_CMP_ULE_D  = FOP(7, FMT_L),
+    R6_OPC_CMP_SAF_D  = FOP(8, FMT_L),
+    R6_OPC_CMP_SUN_D  = FOP(9, FMT_L),
+    R6_OPC_CMP_SEQ_D  = FOP(10, FMT_L),
+    R6_OPC_CMP_SEUQ_D = FOP(11, FMT_L),
+    R6_OPC_CMP_SLT_D  = FOP(12, FMT_L),
+    R6_OPC_CMP_SULT_D = FOP(13, FMT_L),
+    R6_OPC_CMP_SLE_D  = FOP(14, FMT_L),
+    R6_OPC_CMP_SULE_D = FOP(15, FMT_L),
+    R6_OPC_CMP_OR_D   = FOP(17, FMT_L),
+    R6_OPC_CMP_UNE_D  = FOP(18, FMT_L),
+    R6_OPC_CMP_NE_D   = FOP(19, FMT_L),
+    R6_OPC_CMP_SOR_D  = FOP(25, FMT_L),
+    R6_OPC_CMP_SUNE_D = FOP(26, FMT_L),
+    R6_OPC_CMP_SNE_D  = FOP(27, FMT_L),
+};
 static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
 {
     const char *opn = "cp1 move";
@@ -17069,11 +17208,74 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
                 check_insn_opc_removed(ctx, ISA_MIPS32R6);
             case OPC_S_FMT:
             case OPC_D_FMT:
-            case OPC_W_FMT:
-            case OPC_L_FMT:
                 gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
                            (imm >> 8) & 0x7);
                 break;
+            case OPC_W_FMT:
+            case OPC_L_FMT:
+            {
+                int r6_op = ctx->opcode & FOP(0x3f, 0x1f);
+                if (ctx->insn_flags & ISA_MIPS32R6) {
+                    switch (r6_op) {
+                    case R6_OPC_CMP_AF_S:
+                    case R6_OPC_CMP_UN_S:
+                    case R6_OPC_CMP_EQ_S:
+                    case R6_OPC_CMP_UEQ_S:
+                    case R6_OPC_CMP_LT_S:
+                    case R6_OPC_CMP_ULT_S:
+                    case R6_OPC_CMP_LE_S:
+                    case R6_OPC_CMP_ULE_S:
+                    case R6_OPC_CMP_SAF_S:
+                    case R6_OPC_CMP_SUN_S:
+                    case R6_OPC_CMP_SEQ_S:
+                    case R6_OPC_CMP_SEUQ_S:
+                    case R6_OPC_CMP_SLT_S:
+                    case R6_OPC_CMP_SULT_S:
+                    case R6_OPC_CMP_SLE_S:
+                    case R6_OPC_CMP_SULE_S:
+                    case R6_OPC_CMP_OR_S:
+                    case R6_OPC_CMP_UNE_S:
+                    case R6_OPC_CMP_NE_S:
+                    case R6_OPC_CMP_SOR_S:
+                    case R6_OPC_CMP_SUNE_S:
+                    case R6_OPC_CMP_SNE_S:
+                        gen_r6_cmp_s(ctx, ctx->opcode & 0x1f, rt, rd, sa);
+                        break;
+                    case R6_OPC_CMP_AF_D:
+                    case R6_OPC_CMP_UN_D:
+                    case R6_OPC_CMP_EQ_D:
+                    case R6_OPC_CMP_UEQ_D:
+                    case R6_OPC_CMP_LT_D:
+                    case R6_OPC_CMP_ULT_D:
+                    case R6_OPC_CMP_LE_D:
+                    case R6_OPC_CMP_ULE_D:
+                    case R6_OPC_CMP_SAF_D:
+                    case R6_OPC_CMP_SUN_D:
+                    case R6_OPC_CMP_SEQ_D:
+                    case R6_OPC_CMP_SEUQ_D:
+                    case R6_OPC_CMP_SLT_D:
+                    case R6_OPC_CMP_SULT_D:
+                    case R6_OPC_CMP_SLE_D:
+                    case R6_OPC_CMP_SULE_D:
+                    case R6_OPC_CMP_OR_D:
+                    case R6_OPC_CMP_UNE_D:
+                    case R6_OPC_CMP_NE_D:
+                    case R6_OPC_CMP_SOR_D:
+                    case R6_OPC_CMP_SUNE_D:
+                    case R6_OPC_CMP_SNE_D:
+                        gen_r6_cmp_d(ctx, ctx->opcode & 0x1f, rt, rd, sa);
+                        break;
+                    default:
+                        gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
+                                                       (imm >> 8) & 0x7);
+                        break;
+                    }
+                } else {
+                    gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
+                               (imm >> 8) & 0x7);
+                }
+                break;
+            }
             default:
                 MIPS_INVAL("cp1");
                 generate_exception (ctx, EXCP_RI);
-- 
2.1.0

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

* [Qemu-devel] [PULL 18/28] target-mips: do not allow Status.FR=0 mode in 64-bit FPU
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (16 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 17/28] target-mips: add new Floating Point Comparison instructions Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 19/28] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions Leon Alrae
                   ` (11 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

Status.FR bit must be ignored on write and read as 1 when an implementation of
Release 6 of the Architecture in which a 64-bit floating point unit is
implemented.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
 target-mips/translate.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 6f57171..8088781 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -17951,6 +17951,12 @@ void cpu_state_reset(CPUMIPSState *env)
         }
     }
 #endif
+    if ((env->insn_flags & ISA_MIPS32R6) &&
+        (env->active_fpu.fcr0 & (1 << FCR0_F64))) {
+        /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */
+        env->CP0_Status |= (1 << CP0St_FR);
+    }
+
     compute_hflags(env);
     cs->exception_index = EXCP_NONE;
 }
-- 
2.1.0

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

* [Qemu-devel] [PULL 19/28] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (17 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 18/28] target-mips: do not allow Status.FR=0 mode in 64-bit FPU Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 20/28] mips_malta: update malta's pseudo-bootloader - replace JR with JALR Leon Alrae
                   ` (10 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yongbok Kim

From: Yongbok Kim <yongbok.kim@imgtec.com>

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 disas/mips.c            |  2 ++
 target-mips/translate.c | 18 ++++++++++++++++--
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 5ebb5fd..7297825 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -1313,6 +1313,8 @@ const struct mips_opcode mips_builtin_opcodes[] =
 {"bgtzalc", "s,t,p",    0x1c000000, 0xffe00000, CBD|RD_s|RD_t,        0, I32R6},
 {"bltzalc", "s,t,p",    0x1c000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
 {"bltuc",   "s,t,p",    0x1c000000, 0xfc000000, CBD|RD_s|RD_t,        0, I32R6},
+{"nal",     "p",        0x04100000, 0xffff0000, WR_31,                0, I32R6},
+{"bal",     "p",        0x04110000, 0xffff0000, UBD|WR_31,            0, I32R6},
 {"bc1eqz",  "T,p",      0x45200000, 0xffe00000, CBD|RD_T|FP_S|FP_D,   0, I32R6},
 {"bc1nez",  "T,p",      0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D,   0, I32R6},
 {"bc2eqz",  "E,p",      0x49200000, 0xffe00000, CBD|RD_C2,            0, I32R6},
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 8088781..57c2d41 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -15851,6 +15851,9 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
         gen_muldiv(ctx, op1, 0, rs, rt);
         break;
 #endif
+    case OPC_JR:
+        gen_compute_branch(ctx, op1, 4, rs, rd, sa);
+        break;
     case OPC_SPIM:
 #ifdef MIPS_STRICT_STANDARD
         MIPS_INVAL("SPIM");
@@ -15933,7 +15936,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
     case OPC_XOR:
         gen_logic(ctx, op1, rd, rs, rt);
         break;
-    case OPC_JR ... OPC_JALR:
+    case OPC_JALR:
         gen_compute_branch(ctx, op1, 4, rs, rd, sa);
         break;
     case OPC_TGE ... OPC_TEQ: /* Traps */
@@ -16903,9 +16906,20 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             check_insn_opc_removed(ctx, ISA_MIPS32R6);
         case OPC_BLTZ:
         case OPC_BGEZ:
+            gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
+            break;
         case OPC_BLTZAL:
         case OPC_BGEZAL:
-            gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
+            if (ctx->insn_flags & ISA_MIPS32R6) {
+                if (rs == 0) {
+                    /* OPC_NAL, OPC_BAL */
+                    gen_compute_branch(ctx, op1, 4, 0, -1, imm << 2);
+                } else {
+                    generate_exception(ctx, EXCP_RI);
+                }
+            } else {
+                gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
+            }
             break;
         case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
         case OPC_TNEI:
-- 
2.1.0

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

* [Qemu-devel] [PULL 20/28] mips_malta: update malta's pseudo-bootloader - replace JR with JALR
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (18 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 19/28] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 21/28] target-mips: define a new generic CPU supporting MIPS64 Release 6 ISA Leon Alrae
                   ` (9 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

JR has been removed in R6 and now this instruction will cause Reserved
Instruction Exception. Therefore use JALR with rd=0 which is equivalent to JR.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 hw/mips/mips_malta.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index b20807c..e8e075c 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -697,12 +697,12 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
     /* Jump to kernel code */
     stl_p(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
     stl_p(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
-    stl_p(p++, 0x03e00008);                                      /* jr ra */
+    stl_p(p++, 0x03e00009);                                      /* jalr ra */
     stl_p(p++, 0x00000000);                                      /* nop */
 
     /* YAMON subroutines */
     p = (uint32_t *) (base + 0x800);
-    stl_p(p++, 0x03e00008);                                     /* jr ra */
+    stl_p(p++, 0x03e00009);                                     /* jalr ra */
     stl_p(p++, 0x24020000);                                     /* li v0,0 */
     /* 808 YAMON print */
     stl_p(p++, 0x03e06821);                                     /* move t5,ra */
@@ -716,7 +716,7 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
     stl_p(p++, 0x00000000);                                     /* nop */
     stl_p(p++, 0x08000205);                                     /* j 814 */
     stl_p(p++, 0x00000000);                                     /* nop */
-    stl_p(p++, 0x01a00008);                                     /* jr t5 */
+    stl_p(p++, 0x01a00009);                                     /* jalr t5 */
     stl_p(p++, 0x01602021);                                     /* move a0,t3 */
     /* 0x83c YAMON print_count */
     stl_p(p++, 0x03e06821);                                     /* move t5,ra */
@@ -730,7 +730,7 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
     stl_p(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
     stl_p(p++, 0x1580fffa);                                     /* bnez t4,84c */
     stl_p(p++, 0x00000000);                                     /* nop */
-    stl_p(p++, 0x01a00008);                                     /* jr t5 */
+    stl_p(p++, 0x01a00009);                                     /* jalr t5 */
     stl_p(p++, 0x01602021);                                     /* move a0,t3 */
     /* 0x870 */
     stl_p(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
@@ -740,7 +740,7 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
     stl_p(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
     stl_p(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
     stl_p(p++, 0x00000000);                                     /* nop */
-    stl_p(p++, 0x03e00008);                                     /* jr ra */
+    stl_p(p++, 0x03e00009);                                     /* jalr ra */
     stl_p(p++, 0xa1040000);                                     /* sb a0,0(t0) */
 
 }
-- 
2.1.0

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

* [Qemu-devel] [PULL 21/28] target-mips: define a new generic CPU supporting MIPS64 Release 6 ISA
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (19 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 20/28] mips_malta: update malta's pseudo-bootloader - replace JR with JALR Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 22/28] target-mips/translate.c: Update OPC_SYNCI Leon Alrae
                   ` (8 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
 target-mips/translate_init.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 29dc2ef..67b7837 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -516,6 +516,36 @@ static const mips_def_t mips_defs[] =
         .mmu_type = MMU_TYPE_R4000,
     },
     {
+        /* A generic CPU supporting MIPS64 Release 6 ISA.
+           FIXME: It does not support all the MIPS64R6 features yet.
+                  Eventually this should be replaced by a real CPU model. */
+        .name = "MIPS64R6-generic",
+        .CP0_PRid = 0x00010000,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AR) | (0x2 << CP0C0_AT) |
+                       (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
+                       (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
+                       (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
+                       (0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_LLAddr_rw_bitmask = 0,
+        .CP0_LLAddr_shift = 0,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x30D8FFFF,
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) |
+                    (0x0 << FCR0_REV),
+        .SEGBITS = 42,
+        /* The architectural limit is 59, but we have hardcoded 36 bit
+           in some places...
+        .PABITS = 59, */ /* the architectural limit */
+        .PABITS = 36,
+        .insn_flags = CPU_MIPS64R6,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
         .name = "Loongson-2E",
         .CP0_PRid = 0x6302,
         /*64KB I-cache and d-cache. 4 way with 32 bit cache line size*/
-- 
2.1.0

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

* [Qemu-devel] [PULL 22/28] target-mips/translate.c: Update OPC_SYNCI
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (20 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 21/28] target-mips: define a new generic CPU supporting MIPS64 Release 6 ISA Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 23/28] target-mips: fix broken MIPS16 and microMIPS Leon Alrae
                   ` (7 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Dongxue Zhang

From: Dongxue Zhang <elta.era@gmail.com>

Update OPC_SYNCI with BS_STOP, in order to handle the instructions which saved
in the same TB of the store instruction.

Signed-off-by: Dongxue Zhang <elta.era@gmail.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
[leon.alrae@imgtec.com: update microMIPS SYNCI as well]
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/translate.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 57c2d41..7b9e8cd 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -13190,6 +13190,9 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
             gen_logic_imm(ctx, OPC_LUI, rs, -1, imm);
             break;
         case SYNCI:
+            /* Break the TB to be able to sync copied instructions
+               immediately */
+            ctx->bstate = BS_STOP;
             break;
         case BC2F:
         case BC2T:
@@ -16928,7 +16931,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
         case OPC_SYNCI:
             check_insn(ctx, ISA_MIPS32R2);
-            /* Treat as NOP. */
+            /* Break the TB to be able to sync copied instructions
+               immediately */
+            ctx->bstate = BS_STOP;
             break;
         case OPC_BPOSGE32:    /* MIPS DSP branch */
 #if defined(TARGET_MIPS64)
-- 
2.1.0

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

* [Qemu-devel] [PULL 23/28] target-mips: fix broken MIPS16 and microMIPS
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (21 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 22/28] target-mips/translate.c: Update OPC_SYNCI Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 24/28] target-mips/dsp_helper.c: Remove unused function get_DSPControl_24() Leon Alrae
                   ` (6 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Yongbok Kim

From: Yongbok Kim <yongbok.kim@imgtec.com>

Commit 240ce26a broke MIPS16 and microMIPS support as it didn't
care those branches and jumps don't have delay slot in
MIPS16 and microMIPS.

This patch introduces a new argument delayslot_size to the
gen_compute_branch() indicating size of delay slot {0, 2, 4}.
And the information is used to call handle_delay_slot() forcingly
when no delay slot is required.

There are some microMIPS branch and jump instructions that requires
exact size of instruction in the delay slot. For indicating
these instructions, MIPS_HFLAG_BDS_STRICT flag is introduced.

Those fictional branch opcodes defined to support MIPS16 and
microMIPS are no longer needed.

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Tested-by: Jonas Gorski <jogo@openwrt.org>
Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
[leon.alrae@imgtec.com: cosmetic changes]
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/cpu.h       |  13 ++-
 target-mips/translate.c | 298 +++++++++++++++++++-----------------------------
 2 files changed, 123 insertions(+), 188 deletions(-)

diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 51a8331..26e7894 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -431,7 +431,7 @@ struct CPUMIPSState {
     int error_code;
     uint32_t hflags;    /* CPU State */
     /* TMASK defines different execution modes */
-#define MIPS_HFLAG_TMASK  0xC07FF
+#define MIPS_HFLAG_TMASK  0x1807FF
 #define MIPS_HFLAG_MODE   0x00007 /* execution modes                    */
     /* The KSU flags must be the lowest bits in hflags. The flag order
        must be the same as defined for CP0 Status. This allows to use
@@ -463,17 +463,18 @@ struct CPUMIPSState {
 #define MIPS_HFLAG_BL     0x01800 /* Likely branch                      */
 #define MIPS_HFLAG_BR     0x02000 /* branch to register (can't link TB) */
     /* Extra flags about the current pending branch.  */
-#define MIPS_HFLAG_BMASK_EXT 0x3C000
+#define MIPS_HFLAG_BMASK_EXT 0x7C000
 #define MIPS_HFLAG_B16    0x04000 /* branch instruction was 16 bits     */
 #define MIPS_HFLAG_BDS16  0x08000 /* branch requires 16-bit delay slot  */
 #define MIPS_HFLAG_BDS32  0x10000 /* branch requires 32-bit delay slot  */
-#define MIPS_HFLAG_BX     0x20000 /* branch exchanges execution mode    */
+#define MIPS_HFLAG_BDS_STRICT  0x20000 /* Strict delay slot size */
+#define MIPS_HFLAG_BX     0x40000 /* branch exchanges execution mode    */
 #define MIPS_HFLAG_BMASK  (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT)
     /* MIPS DSP resources access. */
-#define MIPS_HFLAG_DSP   0x40000  /* Enable access to MIPS DSP resources. */
-#define MIPS_HFLAG_DSPR2 0x80000  /* Enable access to MIPS DSPR2 resources. */
+#define MIPS_HFLAG_DSP   0x080000  /* Enable access to MIPS DSP resources. */
+#define MIPS_HFLAG_DSPR2 0x100000  /* Enable access to MIPS DSPR2 resources. */
     /* Extra flag about HWREna register. */
-#define MIPS_HFLAG_HWRENA_ULR 0x100000 /* ULR bit from HWREna is set. */
+#define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */
     target_ulong btarget;        /* Jump / branch target               */
     target_ulong bcond;          /* Branch condition (if needed)       */
 
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 7b9e8cd..8b62e66 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -65,7 +65,6 @@ enum {
     /* Jump and branches */
     OPC_J        = (0x02 << 26),
     OPC_JAL      = (0x03 << 26),
-    OPC_JALS     = OPC_JAL | 0x5,
     OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
     OPC_BEQL     = (0x14 << 26),
     OPC_BNE      = (0x05 << 26),
@@ -74,9 +73,8 @@ enum {
     OPC_BLEZL    = (0x16 << 26),
     OPC_BGTZ     = (0x07 << 26),
     OPC_BGTZL    = (0x17 << 26),
-    OPC_JALX     = (0x1D << 26),  /* MIPS 16 only */
+    OPC_JALX     = (0x1D << 26),
     OPC_DAUI     = (0x1D << 26),
-    OPC_JALXS    = OPC_JALX | 0x5,
     /* Load and stores */
     OPC_LDL      = (0x1A << 26),
     OPC_LDR      = (0x1B << 26),
@@ -219,8 +217,6 @@ enum {
     /* Jumps */
     OPC_JR       = 0x08 | OPC_SPECIAL, /* Also JR.HB */
     OPC_JALR     = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
-    OPC_JALRC    = OPC_JALR | (0x5 << 6),
-    OPC_JALRS    = 0x10 | OPC_SPECIAL | (0x5 << 6),
     /* Traps */
     OPC_TGE      = 0x30 | OPC_SPECIAL,
     OPC_TGEU     = 0x31 | OPC_SPECIAL,
@@ -317,10 +313,8 @@ enum {
     OPC_BGEZ     = (0x01 << 16) | OPC_REGIMM,
     OPC_BGEZL    = (0x03 << 16) | OPC_REGIMM,
     OPC_BLTZAL   = (0x10 << 16) | OPC_REGIMM,
-    OPC_BLTZALS  = OPC_BLTZAL | 0x5, /* microMIPS */
     OPC_BLTZALL  = (0x12 << 16) | OPC_REGIMM,
     OPC_BGEZAL   = (0x11 << 16) | OPC_REGIMM,
-    OPC_BGEZALS  = OPC_BGEZAL | 0x5, /* microMIPS */
     OPC_BGEZALL  = (0x13 << 16) | OPC_REGIMM,
     OPC_TGEI     = (0x08 << 16) | OPC_REGIMM,
     OPC_TGEIU    = (0x09 << 16) | OPC_REGIMM,
@@ -4137,7 +4131,8 @@ 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)
+                                int rs, int rt, int32_t offset,
+                                int delayslot_size)
 {
     target_ulong btgt = -1;
     int blink = 0;
@@ -4169,7 +4164,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
         break;
     case OPC_BGEZ:
     case OPC_BGEZAL:
-    case OPC_BGEZALS:
     case OPC_BGEZALL:
     case OPC_BGEZL:
     case OPC_BGTZ:
@@ -4178,7 +4172,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
     case OPC_BLEZL:
     case OPC_BLTZ:
     case OPC_BLTZAL:
-    case OPC_BLTZALS:
     case OPC_BLTZALL:
     case OPC_BLTZL:
         /* Compare to zero */
@@ -4201,15 +4194,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
     case OPC_J:
     case OPC_JAL:
     case OPC_JALX:
-    case OPC_JALS:
-    case OPC_JALXS:
         /* Jump to immediate */
         btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
         break;
     case OPC_JR:
     case OPC_JALR:
-    case OPC_JALRC:
-    case OPC_JALRS:
         /* Jump to register */
         if (offset != 0 && offset != 16) {
             /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
@@ -4238,12 +4227,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("balways");
             break;
-        case OPC_BGEZALS:
         case OPC_BGEZAL:  /* 0 >= 0          */
         case OPC_BGEZALL: /* 0 >= 0 likely   */
-            ctx->hflags |= (opc == OPC_BGEZALS
-                            ? MIPS_HFLAG_BDS16
-                            : MIPS_HFLAG_BDS32);
             /* Always take and link */
             blink = 31;
             ctx->hflags |= MIPS_HFLAG_B;
@@ -4255,15 +4240,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             /* Treat as NOP. */
             MIPS_DEBUG("bnever (NOP)");
             goto out;
-        case OPC_BLTZALS:
         case OPC_BLTZAL:  /* 0 < 0           */
-            ctx->hflags |= (opc == OPC_BLTZALS
-                            ? MIPS_HFLAG_BDS16
-                            : MIPS_HFLAG_BDS32);
             /* Handle as an unconditional branch to get correct delay
                slot checking.  */
             blink = 31;
-            btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8);
+            btgt = ctx->pc + insn_bytes + delayslot_size;
             ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("bnever and link");
             break;
@@ -4284,33 +4265,21 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
             break;
-        case OPC_JALXS:
         case OPC_JALX:
             ctx->hflags |= MIPS_HFLAG_BX;
             /* Fallthrough */
-        case OPC_JALS:
         case OPC_JAL:
             blink = 31;
             ctx->hflags |= MIPS_HFLAG_B;
-            ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS)
-                            ? MIPS_HFLAG_BDS16
-                            : MIPS_HFLAG_BDS32);
             MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
             break;
         case OPC_JR:
             ctx->hflags |= MIPS_HFLAG_BR;
-            if (insn_bytes == 4)
-                ctx->hflags |= MIPS_HFLAG_BDS32;
             MIPS_DEBUG("jr %s", regnames[rs]);
             break;
-        case OPC_JALRS:
         case OPC_JALR:
-        case OPC_JALRC:
             blink = rt;
             ctx->hflags |= MIPS_HFLAG_BR;
-            ctx->hflags |= (opc == OPC_JALRS
-                            ? MIPS_HFLAG_BDS16
-                            : MIPS_HFLAG_BDS32);
             MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
             break;
         default:
@@ -4348,11 +4317,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
             MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
             goto likely;
-        case OPC_BGEZALS:
         case OPC_BGEZAL:
-            ctx->hflags |= (opc == OPC_BGEZALS
-                            ? MIPS_HFLAG_BDS16
-                            : MIPS_HFLAG_BDS32);
             tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
             MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt);
             blink = 31;
@@ -4396,11 +4361,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
             MIPS_DEBUG("bposge64 " TARGET_FMT_lx, btgt);
             goto not_likely;
 #endif
-        case OPC_BLTZALS:
         case OPC_BLTZAL:
-            ctx->hflags |= (opc == OPC_BLTZALS
-                            ? MIPS_HFLAG_BDS16
-                            : MIPS_HFLAG_BDS32);
             tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
             blink = 31;
             MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt);
@@ -4424,13 +4385,20 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
                blink, ctx->hflags, btgt);
 
     ctx->btarget = btgt;
+
+    switch (delayslot_size) {
+    case 2:
+        ctx->hflags |= MIPS_HFLAG_BDS16;
+        break;
+    case 4:
+        ctx->hflags |= MIPS_HFLAG_BDS32;
+        break;
+    }
+
     if (blink > 0) {
-        int post_delay = insn_bytes;
+        int post_delay = insn_bytes + delayslot_size;
         int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16);
 
-        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);
     }
 
@@ -7664,7 +7632,7 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op,
     MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
                ctx->hflags, btarget);
     ctx->btarget = btarget;
-
+    ctx->hflags |= MIPS_HFLAG_BDS32;
  out:
     tcg_temp_free_i32(t0);
 }
@@ -10666,15 +10634,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
         gen_addiupc(ctx, rx, imm, 0, 1);
         break;
     case M16_OPC_B:
-        gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1);
+        gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1, 0);
         /* 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);
+        gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1, 0);
         /* 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);
+        gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1, 0);
         /* No delay slot, so just process as a normal instruction */
         break;
     case M16_OPC_SHIFT:
@@ -10732,10 +10700,10 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
     case M16_OPC_I8:
         switch (funct) {
         case I8_BTEQZ:
-            gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1);
+            gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1, 0);
             break;
         case I8_BTNEZ:
-            gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1);
+            gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1, 0);
             break;
         case I8_SWRASP:
             gen_st(ctx, OPC_SW, 31, 29, imm);
@@ -10863,7 +10831,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
     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);
+        gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset, 0);
         /* No delay slot, so just process as a normal instruction */
         break;
     case M16_OPC_JAL:
@@ -10871,16 +10839,18 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
         offset = (((ctx->opcode & 0x1f) << 21)
                   | ((ctx->opcode >> 5) & 0x1f) << 16
                   | offset) << 2;
-        op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS;
-        gen_compute_branch(ctx, op, 4, rx, ry, offset);
+        op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL;
+        gen_compute_branch(ctx, op, 4, rx, ry, offset, 2);
         n_bytes = 4;
         break;
     case M16_OPC_BEQZ:
-        gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
+        gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0,
+                           ((int8_t)ctx->opcode) << 1, 0);
         /* 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);
+        gen_compute_branch(ctx, OPC_BNE, 2, rx, 0,
+                           ((int8_t)ctx->opcode) << 1, 0);
         /* No delay slot, so just process as a normal instruction */
         break;
     case M16_OPC_SHIFT:
@@ -10953,11 +10923,11 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
             switch (funct) {
             case I8_BTEQZ:
                 gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0,
-                                   ((int8_t)ctx->opcode) << 1);
+                                   ((int8_t)ctx->opcode) << 1, 0);
                 break;
             case I8_BTNEZ:
                 gen_compute_branch(ctx, OPC_BNE, 2, 24, 0,
-                                   ((int8_t)ctx->opcode) << 1);
+                                   ((int8_t)ctx->opcode) << 1, 0);
                 break;
             case I8_SWRASP:
                 gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
@@ -11106,12 +11076,13 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
                 int ra = (ctx->opcode >> 5) & 0x1;
 
                 if (link) {
-                    op = nd ? OPC_JALRC : OPC_JALRS;
+                    op = OPC_JALR;
                 } else {
                     op = OPC_JR;
                 }
 
-                gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0);
+                gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0,
+                                   (nd ? 0 : 2));
             }
             break;
         case RR_SDBBP:
@@ -11869,7 +11840,6 @@ static void gen_pool16c_insn(DisasContext *ctx)
 {
     int rd = mmreg((ctx->opcode >> 3) & 0x7);
     int rs = mmreg(ctx->opcode & 0x7);
-    int opc;
 
     switch (((ctx->opcode) >> 4) & 0x3f) {
     case NOT16 + 0:
@@ -11925,32 +11895,27 @@ static void gen_pool16c_insn(DisasContext *ctx)
         {
             int reg = ctx->opcode & 0x1f;
 
-            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
+            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 4);
         }
         break;
     case JRC16 + 0:
     case JRC16 + 1:
         {
             int reg = ctx->opcode & 0x1f;
-
-            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
+            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0);
             /* Let normal delay slot handling in our caller take us
                to the branch target.  */
         }
         break;
     case JALR16 + 0:
     case JALR16 + 1:
-        opc = OPC_JALR;
-        goto do_jalr;
+        gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4);
+        ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
+        break;
     case JALR16S + 0:
     case JALR16S + 1:
-        opc = OPC_JALRS;
-    do_jalr:
-        {
-            int reg = ctx->opcode & 0x1f;
-
-            gen_compute_branch(ctx, opc, 2, reg, 31, 0);
-        }
+        gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2);
+        ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
         break;
     case MFHI16 + 0:
     case MFHI16 + 1:
@@ -11978,8 +11943,7 @@ static void gen_pool16c_insn(DisasContext *ctx)
     case JRADDIUSP + 1:
         {
             int imm = ZIMM(ctx->opcode, 0, 5);
-
-            gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0);
+            gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0);
             gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2);
             /* Let normal delay slot handling in our caller take us
                to the branch target.  */
@@ -12236,11 +12200,13 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs)
         switch (minor) {
         case JALR:
         case JALR_HB:
-            gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0);
+            gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4);
+            ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
             break;
         case JALRS:
         case JALRS_HB:
-            gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0);
+            gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2);
+            ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
             break;
         default:
             goto pool32axf_invalid;
@@ -13130,30 +13096,32 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
         minor = (ctx->opcode >> 21) & 0x1f;
         switch (minor) {
         case BLTZ:
-            mips32_op = OPC_BLTZ;
-            goto do_branch;
+            gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4);
+            break;
         case BLTZAL:
-            mips32_op = OPC_BLTZAL;
-            goto do_branch;
+            gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4);
+            ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
+            break;
         case BLTZALS:
-            mips32_op = OPC_BLTZALS;
-            goto do_branch;
+            gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2);
+            ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
+            break;
         case BGEZ:
-            mips32_op = OPC_BGEZ;
-            goto do_branch;
+            gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4);
+            break;
         case BGEZAL:
-            mips32_op = OPC_BGEZAL;
-            goto do_branch;
+            gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4);
+            ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
+            break;
         case BGEZALS:
-            mips32_op = OPC_BGEZALS;
-            goto do_branch;
+            gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2);
+            ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
+            break;
         case BLEZ:
-            mips32_op = OPC_BLEZ;
-            goto do_branch;
+            gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4);
+            break;
         case BGTZ:
-            mips32_op = OPC_BGTZ;
-        do_branch:
-            gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1);
+            gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4);
             break;
 
             /* Traps */
@@ -13181,7 +13149,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
         case BNEZC:
         case BEQZC:
             gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ,
-                               4, rs, 0, imm << 1);
+                               4, rs, 0, imm << 1, 0);
             /* Compact branches don't have a delay slot, so just let
                the normal delay slot handling take us to the branch
                target. */
@@ -13322,25 +13290,28 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
         break;
     case JALX32:
         offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
-        gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset);
+        gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4);
+        ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
         break;
     case JALS32:
         offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1;
-        gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset);
+        gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2);
+        ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
         break;
     case BEQ32:
-        gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1);
+        gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4);
         break;
     case BNE32:
-        gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1);
+        gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4);
         break;
     case J32:
         gen_compute_branch(ctx, OPC_J, 4, rt, rs,
-                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
+                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4);
         break;
     case JAL32:
         gen_compute_branch(ctx, OPC_JAL, 4, rt, rs,
-                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
+                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4);
+        ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
         break;
         /* Floating point (COP1) */
     case LWC132:
@@ -13424,84 +13395,41 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx)
 
     op = (ctx->opcode >> 10) & 0x3f;
     /* Enforce properly-sized instructions in a delay slot */
-    if (ctx->hflags & MIPS_HFLAG_BMASK) {
-        int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT;
-
-        switch (op) {
-        case POOL32A:
-        case POOL32B:
-        case POOL32I:
-        case POOL32C:
-        case ADDI32:
-        case ADDIU32:
-        case ORI32:
-        case XORI32:
-        case SLTI32:
-        case SLTIU32:
-        case ANDI32:
-        case JALX32:
-        case LBU32:
-        case LHU32:
-        case POOL32F:
-        case JALS32:
-        case BEQ32:
-        case BNE32:
-        case J32:
-        case JAL32:
-        case SB32:
-        case SH32:
-        case POOL32S:
-        case ADDIUPC:
-        case SWC132:
-        case SDC132:
-        case SD32:
-        case SW32:
-        case LB32:
-        case LH32:
-        case DADDIU32:
-        case LWC132:
-        case LDC132:
-        case LD32:
-        case LW32:
-            if (bits & MIPS_HFLAG_BDS16) {
+    if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) {
+        switch (op & 0x7) { /* MSB-3..MSB-5 */
+        case 0:
+        /* POOL32A, POOL32B, POOL32I, POOL32C */
+        case 4:
+        /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */
+        case 5:
+        /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */
+        case 6:
+        /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */
+        case 7:
+        /* LB32, LH32, LWC132, LDC132, LW32 */
+            if (ctx->hflags & MIPS_HFLAG_BDS16) {
                 generate_exception(ctx, EXCP_RI);
                 /* Just stop translation; the user is confused.  */
                 ctx->bstate = BS_STOP;
                 return 2;
             }
             break;
-        case POOL16A:
-        case POOL16B:
-        case POOL16C:
-        case LWGP16:
-        case POOL16F:
-        case LBU16:
-        case LHU16:
-        case LWSP16:
-        case LW16:
-        case SB16:
-        case SH16:
-        case SWSP16:
-        case SW16:
-        case MOVE16:
-        case ANDI16:
-        case POOL16D:
-        case POOL16E:
-        case BEQZ16:
-        case BNEZ16:
-        case B16:
-        case LI16:
-            if (bits & MIPS_HFLAG_BDS32) {
+        case 1:
+        /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */
+        case 2:
+        /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */
+        case 3:
+        /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */
+            if (ctx->hflags & MIPS_HFLAG_BDS32) {
                 generate_exception(ctx, EXCP_RI);
                 /* Just stop translation; the user is confused.  */
                 ctx->bstate = BS_STOP;
                 return 2;
             }
             break;
-        default:
-            break;
         }
     }
+
     switch (op) {
     case POOL16A:
         {
@@ -13682,13 +13610,13 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx)
         break;
     case B16:
         gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0,
-                           SIMM(ctx->opcode, 0, 10) << 1);
+                           SIMM(ctx->opcode, 0, 10) << 1, 4);
         break;
     case BNEZ16:
     case BEQZ16:
         gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2,
                            mmreg(uMIPS_RD(ctx->opcode)),
-                           0, SIMM(ctx->opcode, 0, 7) << 1);
+                           0, SIMM(ctx->opcode, 0, 7) << 1, 4);
         break;
     case LI16:
         {
@@ -15855,7 +15783,7 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
         break;
 #endif
     case OPC_JR:
-        gen_compute_branch(ctx, op1, 4, rs, rd, sa);
+        gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4);
         break;
     case OPC_SPIM:
 #ifdef MIPS_STRICT_STANDARD
@@ -15940,7 +15868,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
         gen_logic(ctx, op1, rd, rs, rt);
         break;
     case OPC_JALR:
-        gen_compute_branch(ctx, op1, 4, rs, rd, sa);
+        gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4);
         break;
     case OPC_TGE ... OPC_TEQ: /* Traps */
     case OPC_TNE:
@@ -16909,19 +16837,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             check_insn_opc_removed(ctx, ISA_MIPS32R6);
         case OPC_BLTZ:
         case OPC_BGEZ:
-            gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
+            gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2, 4);
             break;
         case OPC_BLTZAL:
         case OPC_BGEZAL:
             if (ctx->insn_flags & ISA_MIPS32R6) {
                 if (rs == 0) {
                     /* OPC_NAL, OPC_BAL */
-                    gen_compute_branch(ctx, op1, 4, 0, -1, imm << 2);
+                    gen_compute_branch(ctx, op1, 4, 0, -1, imm << 2, 4);
                 } else {
                     generate_exception(ctx, EXCP_RI);
                 }
             } else {
-                gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
+                gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2, 4);
             }
             break;
         case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
@@ -16940,7 +16868,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         case OPC_BPOSGE64:
 #endif
             check_dsp(ctx);
-            gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2);
+            gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2, 4);
             break;
 #if defined(TARGET_MIPS64)
         case OPC_DAHI:
@@ -17079,7 +17007,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          break;
     case OPC_J ... OPC_JAL: /* Jump */
          offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
-         gen_compute_branch(ctx, op, 4, rs, rt, offset);
+         gen_compute_branch(ctx, op, 4, rs, rt, offset, 4);
          break;
     /* Branch */
     case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC, OPC_BLEZL */
@@ -17092,7 +17020,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
         } else {
             /* OPC_BLEZL */
-            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
         }
         break;
     case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC, OPC_BGTZL */
@@ -17105,13 +17033,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
         } else {
             /* OPC_BGTZL */
-            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
         }
         break;
     case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC, OPC_BLEZ */
         if (rt == 0) {
             /* OPC_BLEZ */
-            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
         } else {
             check_insn(ctx, ISA_MIPS32R6);
             /* OPC_BLEZALC, OPC_BGEZALC, OPC_BGEUC */
@@ -17121,7 +17049,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
     case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC, OPC_BGTZ */
         if (rt == 0) {
             /* OPC_BGTZ */
-            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+            gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
         } else {
             check_insn(ctx, ISA_MIPS32R6);
             /* OPC_BGTZALC, OPC_BLTZALC, OPC_BLTUC */
@@ -17133,7 +17061,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          check_insn_opc_removed(ctx, ISA_MIPS32R6);
     case OPC_BEQ:
     case OPC_BNE:
-         gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+         gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
          break;
     case OPC_LWL: /* Load and stores */
     case OPC_LWR:
@@ -17453,7 +17381,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             /* OPC_JALX */
             check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS);
             offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
-            gen_compute_branch(ctx, op, 4, rs, rt, offset);
+            gen_compute_branch(ctx, op, 4, rs, rt, offset, 4);
         }
         break;
     case OPC_MDMX:
@@ -17562,6 +17490,12 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
             break;
         }
 
+        if (ctx.hflags & MIPS_HFLAG_BMASK) {
+            if (!(ctx.hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32))) {
+                is_delay = 1;
+                /* force to generate branch as no delay slot is required */
+            }
+        }
         if (is_delay) {
             gen_branch(&ctx, insn_bytes);
         }
-- 
2.1.0

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

* [Qemu-devel] [PULL 24/28] target-mips/dsp_helper.c: Remove unused function get_DSPControl_24()
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (22 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 23/28] target-mips: fix broken MIPS16 and microMIPS Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 25/28] target-mips/op_helper.c: Remove unused do_lbu() function Leon Alrae
                   ` (5 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

From: Peter Maydell <peter.maydell@linaro.org>

The function get_DSPControl_24() is unused; remove it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/dsp_helper.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
index 94083fb..2ea94a7 100644
--- a/target-mips/dsp_helper.c
+++ b/target-mips/dsp_helper.c
@@ -76,15 +76,6 @@ static inline void set_DSPControl_24(uint32_t flag, int len, CPUMIPSState *env)
   env->active_tc.DSPControl |= (target_ulong)flag << 24;
 }
 
-static inline uint32_t get_DSPControl_24(int len, CPUMIPSState *env)
-{
-  uint32_t filter;
-
-  filter = (0x01 << len) - 1;
-
-  return (env->active_tc.DSPControl >> 24) & filter;
-}
-
 static inline void set_DSPControl_pos(uint32_t pos, CPUMIPSState *env)
 {
     target_ulong dspc;
-- 
2.1.0

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

* [Qemu-devel] [PULL 25/28] target-mips/op_helper.c: Remove unused do_lbu() function
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (23 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 24/28] target-mips/dsp_helper.c: Remove unused function get_DSPControl_24() Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 26/28] target-mips/translate.c: Add ifdef guard around check_mips64() Leon Alrae
                   ` (4 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

From: Peter Maydell <peter.maydell@linaro.org>

The do_lbu() function defined by the expansion of HELPER_LD() is
never used, so don't define it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/op_helper.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index c48ee7f..5204ed8 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -90,7 +90,6 @@ static inline type do_##name(CPUMIPSState *env, target_ulong addr,      \
     }                                                                   \
 }
 #endif
-HELPER_LD(lbu, ldub, uint8_t)
 HELPER_LD(lw, ldl, int32_t)
 #ifdef TARGET_MIPS64
 HELPER_LD(ld, ldq, int64_t)
-- 
2.1.0

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

* [Qemu-devel] [PULL 26/28] target-mips/translate.c: Add ifdef guard around check_mips64()
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (24 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 25/28] target-mips/op_helper.c: Remove unused do_lbu() function Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 27/28] target-mips/dsp_helper.c: Add ifdef guards around various functions Leon Alrae
                   ` (3 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

From: Peter Maydell <peter.maydell@linaro.org>

The function check_mips64() is only used if TARGET_MIPS64 is defined;
add an ifdef guard to its definition to avoid warnings about it being
unused in other configurations.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 8b62e66..c23cb94 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1548,6 +1548,7 @@ static inline void check_insn_opc_removed(DisasContext *ctx, int flags)
     }
 }
 
+#ifdef TARGET_MIPS64
 /* This code generates a "reserved instruction" exception if 64-bit
    instructions are not enabled. */
 static inline void check_mips_64(DisasContext *ctx)
@@ -1555,6 +1556,7 @@ static inline void check_mips_64(DisasContext *ctx)
     if (unlikely(!(ctx->hflags & MIPS_HFLAG_64)))
         generate_exception(ctx, EXCP_RI);
 }
+#endif
 
 /* Define small wrappers for gen_load_fpr* so that we have a uniform
    calling interface for 32 and 64-bit FPRs.  No sense in changing
-- 
2.1.0

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

* [Qemu-devel] [PULL 27/28] target-mips/dsp_helper.c: Add ifdef guards around various functions
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (25 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 26/28] target-mips/translate.c: Add ifdef guard around check_mips64() Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-15  9:54 ` [Qemu-devel] [PULL 28/28] target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX Leon Alrae
                   ` (2 subsequent siblings)
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

From: Peter Maydell <peter.maydell@linaro.org>

Add ifdef TARGET_MIPS64 guards around various functions that are only
called from helpers for TARGET_MIPS64 CPUs; this avoids compiler
warnings when building other configs.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/dsp_helper.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
index 2ea94a7..349f2a0 100644
--- a/target-mips/dsp_helper.c
+++ b/target-mips/dsp_helper.c
@@ -274,6 +274,7 @@ static inline int32_t mipsdsp_sat32_acc_q31(int32_t acc, int32_t a,
     return result;
 }
 
+#ifdef TARGET_MIPS64
 /* a[0] is LO, a[1] is HI. */
 static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret,
                                              int32_t ac,
@@ -327,6 +328,7 @@ static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
         set_DSPControl_overflow_flag(1, 16 + ac, env);
     }
 }
+#endif
 
 static inline int32_t mipsdsp_mul_i16_i16(int16_t a, int16_t b,
                                           CPUMIPSState *env)
@@ -348,10 +350,12 @@ static inline int32_t mipsdsp_mul_u16_u16(int32_t a, int32_t b)
     return a * b;
 }
 
+#ifdef TARGET_MIPS64
 static inline int32_t mipsdsp_mul_i32_i32(int32_t a, int32_t b)
 {
     return a * b;
 }
+#endif
 
 static inline int32_t mipsdsp_sat16_mul_i16_i16(int16_t a, int16_t b,
                                                 CPUMIPSState *env)
@@ -408,10 +412,12 @@ static inline int16_t mipsdsp_rashift16(int16_t a, target_ulong mov)
     return a >> mov;
 }
 
+#ifdef TARGET_MIPS64
 static inline int32_t mipsdsp_rashift32(int32_t a, target_ulong mov)
 {
     return a >> mov;
 }
+#endif
 
 static inline int16_t mipsdsp_rshift1_add_q16(int16_t a, int16_t b)
 {
@@ -470,6 +476,7 @@ static inline uint8_t mipsdsp_rrshift1_add_u8(uint8_t a, uint8_t b)
     return (temp >> 1) & 0x00FF;
 }
 
+#ifdef TARGET_MIPS64
 static inline uint8_t mipsdsp_rshift1_sub_u8(uint8_t a, uint8_t b)
 {
     uint16_t temp;
@@ -487,6 +494,7 @@ static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b)
 
     return (temp >> 1) & 0x00FF;
 }
+#endif
 
 /*  128 bits long. p[0] is LO, p[1] is HI. */
 static inline void mipsdsp_rndrashift_short_acc(int64_t *p,
@@ -502,6 +510,7 @@ static inline void mipsdsp_rndrashift_short_acc(int64_t *p,
     p[1] = (acc >> 63) & 0x01;
 }
 
+#ifdef TARGET_MIPS64
 /* 128 bits long. p[0] is LO, p[1] is HI */
 static inline void mipsdsp_rashift_acc(uint64_t *p,
                                        uint32_t ac,
@@ -549,6 +558,7 @@ static inline void mipsdsp_rndrashift_acc(uint64_t *p,
         }
     }
 }
+#endif
 
 static inline int32_t mipsdsp_mul_q15_q15(int32_t ac, uint16_t a, uint16_t b,
                                           CPUMIPSState *env)
@@ -599,10 +609,12 @@ static inline uint16_t mipsdsp_mul_u8_u16(uint8_t a, uint16_t b,
     return tempI & 0x0000FFFF;
 }
 
+#ifdef TARGET_MIPS64
 static inline uint64_t mipsdsp_mul_u32_u32(uint32_t a, uint32_t b)
 {
     return (uint64_t)a * (uint64_t)b;
 }
+#endif
 
 static inline int16_t mipsdsp_rndq15_mul_q15_q15(uint16_t a, uint16_t b,
                                                  CPUMIPSState *env)
@@ -708,7 +720,7 @@ static inline uint16_t mipsdsp_lshift16(uint16_t a, uint8_t s,
     return a << s;
 }
 
-
+#ifdef TARGET_MIPS64
 static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s,
                                         CPUMIPSState *env)
 {
@@ -725,6 +737,7 @@ static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s,
         return a << s;
     }
 }
+#endif
 
 static inline uint16_t mipsdsp_sat16_lshift(uint16_t a, uint8_t s,
                                             CPUMIPSState *env)
@@ -964,6 +977,7 @@ static inline uint8_t mipsdsp_satu8_sub(uint8_t a, uint8_t b, CPUMIPSState *env)
     return temp & 0x00FF;
 }
 
+#ifdef TARGET_MIPS64
 static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env)
 {
     int32_t temp;
@@ -988,6 +1002,7 @@ static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env)
 
     return temp;
 }
+#endif
 
 static inline int32_t mipsdsp_cmp_eq(int32_t a, int32_t b)
 {
-- 
2.1.0

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

* [Qemu-devel] [PULL 28/28] target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (26 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 27/28] target-mips/dsp_helper.c: Add ifdef guards around various functions Leon Alrae
@ 2014-10-15  9:54 ` Leon Alrae
  2014-10-16  9:49 ` [Qemu-devel] [PULL 00/28] target-mips queue Peter Maydell
  2014-10-22 12:08 ` Peter Maydell
  29 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-15  9:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

From: Peter Maydell <peter.maydell@linaro.org>

Remove the functions gen_load_ACX and gen_store_ACX, which appear to have
been unused since they were first introduced many years ago. These functions
were the only places using the cpu_ACX[] array of TCG globals, so remove
that and its accompanying regnames_ACX[] as well.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/translate.c | 20 +-------------------
 1 file changed, 1 insertion(+), 19 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index c23cb94..446eb8a 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1104,7 +1104,7 @@ enum {
 /* global register indices */
 static TCGv_ptr cpu_env;
 static TCGv cpu_gpr[32], cpu_PC;
-static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], cpu_ACX[MIPS_DSP_ACC];
+static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC];
 static TCGv cpu_dspctrl, btarget, bcond;
 static TCGv_i32 hflags;
 static TCGv_i32 fpu_fcr0, fpu_fcr31;
@@ -1195,10 +1195,6 @@ static const char * const regnames_LO[] = {
     "LO0", "LO1", "LO2", "LO3",
 };
 
-static const char * const regnames_ACX[] = {
-    "ACX0", "ACX1", "ACX2", "ACX3",
-};
-
 static const char * const fregnames[] = {
     "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
     "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
@@ -1241,17 +1237,6 @@ static inline void gen_store_gpr (TCGv t, int reg)
         tcg_gen_mov_tl(cpu_gpr[reg], t);
 }
 
-/* Moves to/from ACX register.  */
-static inline void gen_load_ACX (TCGv t, int reg)
-{
-    tcg_gen_mov_tl(t, cpu_ACX[reg]);
-}
-
-static inline void gen_store_ACX (TCGv t, int reg)
-{
-    tcg_gen_mov_tl(cpu_ACX[reg], t);
-}
-
 /* Moves to/from shadow registers. */
 static inline void gen_load_srsgpr (int from, int to)
 {
@@ -17716,9 +17701,6 @@ void mips_tcg_init(void)
         cpu_LO[i] = tcg_global_mem_new(TCG_AREG0,
                                        offsetof(CPUMIPSState, active_tc.LO[i]),
                                        regnames_LO[i]);
-        cpu_ACX[i] = tcg_global_mem_new(TCG_AREG0,
-                                        offsetof(CPUMIPSState, active_tc.ACX[i]),
-                                        regnames_ACX[i]);
     }
     cpu_dspctrl = tcg_global_mem_new(TCG_AREG0,
                                      offsetof(CPUMIPSState, active_tc.DSPControl),
-- 
2.1.0

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

* Re: [Qemu-devel] [PULL 00/28] target-mips queue
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (27 preceding siblings ...)
  2014-10-15  9:54 ` [Qemu-devel] [PULL 28/28] target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX Leon Alrae
@ 2014-10-16  9:49 ` Peter Maydell
  2014-10-16  9:59   ` Leon Alrae
  2014-10-22 12:08 ` Peter Maydell
  29 siblings, 1 reply; 34+ messages in thread
From: Peter Maydell @ 2014-10-16  9:49 UTC (permalink / raw)
  To: Leon Alrae; +Cc: QEMU Developers, Aurelien Jarno

On 15 October 2014 11:53, Leon Alrae <leon.alrae@imgtec.com> wrote:
> Hi,
>
> This pull request has been assembled from pending target-mips patches which
> look good to me and received in my opinion sufficient review comments. They
> were tested mainly in context of MIPS. Please have a look and pull.

Thanks for putting this together; I'll look it over shortly.

One question for now:

> Leon Alrae (17):
>   softfloat: add functions corresponding to IEEE-2008 min/maxNumMag

Can you confirm that you're happy for your softfloat changes
to be licensed under both of the softfloat-2a and softfloat-2b
licenses, please?

(We're trying to relicense those files right now, so any new
changes need to be dual-license.)

PS: do you happen to be at KVM Forum today?

-- PMM

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

* Re: [Qemu-devel] [PULL 00/28] target-mips queue
  2014-10-16  9:49 ` [Qemu-devel] [PULL 00/28] target-mips queue Peter Maydell
@ 2014-10-16  9:59   ` Leon Alrae
  0 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-16  9:59 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers, Aurelien Jarno

On 16/10/2014 10:49, Peter Maydell wrote:
> 
> One question for now:
> 
>> Leon Alrae (17):
>>   softfloat: add functions corresponding to IEEE-2008 min/maxNumMag
> 
> Can you confirm that you're happy for your softfloat changes
> to be licensed under both of the softfloat-2a and softfloat-2b
> licenses, please?

Yes, I'm happy with my softfloat changes to be licensed under softfloat
2a and 2b licenses.

> PS: do you happen to be at KVM Forum today?

No, I won't be there unfortunately.

Regards,
Leon

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

* Re: [Qemu-devel] [PULL 00/28] target-mips queue
  2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
                   ` (28 preceding siblings ...)
  2014-10-16  9:49 ` [Qemu-devel] [PULL 00/28] target-mips queue Peter Maydell
@ 2014-10-22 12:08 ` Peter Maydell
  2014-10-22 12:22   ` Peter Maydell
  29 siblings, 1 reply; 34+ messages in thread
From: Peter Maydell @ 2014-10-22 12:08 UTC (permalink / raw)
  To: Leon Alrae; +Cc: QEMU Developers, Aurelien Jarno

On 15 October 2014 10:53, Leon Alrae <leon.alrae@imgtec.com> wrote:
> Hi,
>
> This pull request has been assembled from pending target-mips patches which
> look good to me and received in my opinion sufficient review comments. They
> were tested mainly in context of MIPS. Please have a look and pull.

These all look good -- I have applied the pull request to master.

Thanks for stepping up to do this submaintainer work.

-- PMM

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

* Re: [Qemu-devel] [PULL 00/28] target-mips queue
  2014-10-22 12:08 ` Peter Maydell
@ 2014-10-22 12:22   ` Peter Maydell
  2014-10-22 12:32     ` Leon Alrae
  0 siblings, 1 reply; 34+ messages in thread
From: Peter Maydell @ 2014-10-22 12:22 UTC (permalink / raw)
  To: Leon Alrae; +Cc: QEMU Developers, Aurelien Jarno

On 22 October 2014 13:08, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 15 October 2014 10:53, Leon Alrae <leon.alrae@imgtec.com> wrote:
>> Hi,
>>
>> This pull request has been assembled from pending target-mips patches which
>> look good to me and received in my opinion sufficient review comments. They
>> were tested mainly in context of MIPS. Please have a look and pull.
>
> These all look good -- I have applied the pull request to master.

...but after I did that I noticed these which you should probably
send a patch to fix:
target-mips/op_helper.c: In function ‘bitswap’:
target-mips/op_helper.c:270: warning: integer constant is too large
for ‘long’ type
target-mips/op_helper.c:271: warning: integer constant is too large
for ‘long’ type
target-mips/op_helper.c:272: warning: integer constant is too large
for ‘long’ type
target-mips/op_helper.c:273: warning: integer constant is too large
for ‘long’ type
target-mips/op_helper.c:274: warning: integer constant is too large
for ‘long’ type
target-mips/op_helper.c:275: warning: integer constant is too large
for ‘long’ type

64 bit literal constants need to be suffixed with "ULL", like:
 0x5555555555555555ULL
or some of our compilers complain. I think this is the Windows
build, which we don't currently have set to warnings-as-errors
due to other longstanding warnings.

thanks
-- PMM

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

* Re: [Qemu-devel] [PULL 00/28] target-mips queue
  2014-10-22 12:22   ` Peter Maydell
@ 2014-10-22 12:32     ` Leon Alrae
  0 siblings, 0 replies; 34+ messages in thread
From: Leon Alrae @ 2014-10-22 12:32 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers, Aurelien Jarno

On 22/10/2014 13:22, Peter Maydell wrote:
> On 22 October 2014 13:08, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 15 October 2014 10:53, Leon Alrae <leon.alrae@imgtec.com> wrote:
>>> Hi,
>>>
>>> This pull request has been assembled from pending target-mips patches which
>>> look good to me and received in my opinion sufficient review comments. They
>>> were tested mainly in context of MIPS. Please have a look and pull.
>>
>> These all look good -- I have applied the pull request to master.
> 
> ...but after I did that I noticed these which you should probably
> send a patch to fix:
> target-mips/op_helper.c: In function ‘bitswap’:
> target-mips/op_helper.c:270: warning: integer constant is too large
> for ‘long’ type
> target-mips/op_helper.c:271: warning: integer constant is too large
> for ‘long’ type
> target-mips/op_helper.c:272: warning: integer constant is too large
> for ‘long’ type
> target-mips/op_helper.c:273: warning: integer constant is too large
> for ‘long’ type
> target-mips/op_helper.c:274: warning: integer constant is too large
> for ‘long’ type
> target-mips/op_helper.c:275: warning: integer constant is too large
> for ‘long’ type
> 
> 64 bit literal constants need to be suffixed with "ULL", like:
>  0x5555555555555555ULL
> or some of our compilers complain. I think this is the Windows
> build, which we don't currently have set to warnings-as-errors
> due to other longstanding warnings.

Sorry for that, I will send the patch shortly.

Leon

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

end of thread, other threads:[~2014-10-22 12:32 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-15  9:53 [Qemu-devel] [PULL 00/28] target-mips queue Leon Alrae
2014-10-15  9:53 ` [Qemu-devel] [PULL 01/28] target-mips: define ISA_MIPS64R6 Leon Alrae
2014-10-15  9:53 ` [Qemu-devel] [PULL 02/28] target-mips: signal RI Exception on instructions removed in R6 Leon Alrae
2014-10-15  9:53 ` [Qemu-devel] [PULL 03/28] target-mips: add SELEQZ and SELNEZ instructions Leon Alrae
2014-10-15  9:53 ` [Qemu-devel] [PULL 04/28] target-mips: move LL and SC instructions Leon Alrae
2014-10-15  9:53 ` [Qemu-devel] [PULL 05/28] target-mips: extract decode_opc_special* from decode_opc Leon Alrae
2014-10-15  9:53 ` [Qemu-devel] [PULL 06/28] target-mips: split decode_opc_special* into *_r6 and *_legacy Leon Alrae
2014-10-15  9:53 ` [Qemu-devel] [PULL 07/28] target-mips: signal RI Exception on DSP and Loongson instructions Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 08/28] target-mips: move PREF, CACHE, LLD and SCD instructions Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 09/28] target-mips: redefine Integer Multiply and Divide instructions Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 10/28] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6 Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 11/28] target-mips: Status.UX/SX/KX enable 32-bit address wrapping Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 12/28] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 13/28] target-mips: add compact and CP1 branches Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 14/28] target-mips: add AUI, LSA and PCREL instruction families Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 15/28] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 16/28] target-mips: add new Floating Point instructions Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 17/28] target-mips: add new Floating Point Comparison instructions Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 18/28] target-mips: do not allow Status.FR=0 mode in 64-bit FPU Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 19/28] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 20/28] mips_malta: update malta's pseudo-bootloader - replace JR with JALR Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 21/28] target-mips: define a new generic CPU supporting MIPS64 Release 6 ISA Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 22/28] target-mips/translate.c: Update OPC_SYNCI Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 23/28] target-mips: fix broken MIPS16 and microMIPS Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 24/28] target-mips/dsp_helper.c: Remove unused function get_DSPControl_24() Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 25/28] target-mips/op_helper.c: Remove unused do_lbu() function Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 26/28] target-mips/translate.c: Add ifdef guard around check_mips64() Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 27/28] target-mips/dsp_helper.c: Add ifdef guards around various functions Leon Alrae
2014-10-15  9:54 ` [Qemu-devel] [PULL 28/28] target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX Leon Alrae
2014-10-16  9:49 ` [Qemu-devel] [PULL 00/28] target-mips queue Peter Maydell
2014-10-16  9:59   ` Leon Alrae
2014-10-22 12:08 ` Peter Maydell
2014-10-22 12:22   ` Peter Maydell
2014-10-22 12:32     ` Leon Alrae

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