All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support
@ 2014-06-11 15:19 Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 01/22] target-mips: define ISA_MIPS64R6 Leon Alrae
                   ` (21 more replies)
  0 siblings, 22 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

The following patchset implements MIPS64 Release 6 Instruction Set.
New instructions are added and also there is a number of instructions which
are deleted or moved (the encodings have changed).

The MIPS64 Release 6 documentation is available:
http://www.imgtec.com/mips/architectures/mips64.asp

The following patch series is focusing on instruction set changes only.
There is also a new generic cpu supporting R6.

Please note that even though the new Floating Point instructions were added,
softfloat for MIPS has not been updated yet (in R6 MIPS FPU is updated to
IEEE2008). Also, current patchset does not include MIPS64 Privileged Resource
Architecture modifications. All those changes will follow the current patchset
soon.

v2:
* addressed all comments so far from Richard and Aurelien. More detailed
  changelog included in the separate patches.
* added missing zero register case for LSA, ALIGN and BITSWAP instructions

Leon Alrae (18):
  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 Addressing and PC-relative instructions
  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: use pointers referring to appropriate decoding function
  target-mips: define a new generic CPU supporting MIPS64R6

Yongbok Kim (4):
  target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  target-mips: add Compact Branches
  target-mips: add new Floating Point Comparison instructions
  target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions

 disas/mips.c                 |  211 +++-
 fpu/softfloat.c              |   37 +-
 hw/mips/mips_malta.c         |   10 +-
 include/fpu/softfloat.h      |    4 +
 target-mips/cpu.h            |   23 +-
 target-mips/helper.h         |   53 +
 target-mips/mips-defs.h      |   28 +-
 target-mips/op_helper.c      |  243 +++
 target-mips/translate.c      | 3833 +++++++++++++++++++++++++++++++-----------
 target-mips/translate_init.c |   29 +
 10 files changed, 3459 insertions(+), 1012 deletions(-)

-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 01/22] target-mips: define ISA_MIPS64R6
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 21:06   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 02/22] target-mips: signal RI Exception on instructions removed in R6 Leon Alrae
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
v2:
* move new CPU definition to a separate patch
---
 target-mips/mips-defs.h |   28 +++++++++++++++++++---------
 1 files 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.
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 02/22] target-mips: signal RI Exception on instructions removed in R6
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 01/22] target-mips: define ISA_MIPS64R6 Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 03/22] target-mips: add SELEQZ and SELNEZ instructions Leon Alrae
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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 files changed, 56 insertions(+), 8 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 76deb7b..dbb3746 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1430,6 +1430,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)
@@ -7667,10 +7677,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;
@@ -7687,6 +7699,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;
@@ -7820,6 +7833,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();
@@ -7852,6 +7866,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];
@@ -8076,10 +8091,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;
@@ -8096,6 +8113,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;
@@ -8205,6 +8223,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];
@@ -8305,6 +8324,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();
@@ -14455,6 +14475,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);
@@ -14515,10 +14536,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 */
@@ -14551,6 +14574,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 (env->CP0_Config1 & (1 << CP0C1_FP)) {
                 check_cp1_enabled(ctx);
@@ -14653,10 +14677,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:
@@ -15271,12 +15297,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:
@@ -15401,16 +15435,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:
@@ -15457,18 +15499,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;
@@ -15497,6 +15542,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         break;
 
     case OPC_CP3:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         if (env->CP0_Config1 & (1 << CP0C1_FP)) {
             check_cp1_enabled(ctx);
             op1 = MASK_CP3(ctx->opcode);
@@ -15539,8 +15585,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);
@@ -15548,6 +15595,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);
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 03/22] target-mips: add SELEQZ and SELNEZ instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 01/22] target-mips: define ISA_MIPS64R6 Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 02/22] target-mips: signal RI Exception on instructions removed in R6 Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 04/22] target-mips: move LL and SC instructions Leon Alrae
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
v2:
* correct conditions to match instruction name
---
 disas/mips.c            |    8 ++++++++
 target-mips/translate.c |   16 ++++++++++++++++
 2 files changed, 24 insertions(+), 0 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 dbb3746..4eb8a61 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -189,6 +189,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 */
@@ -2406,6 +2409,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);
@@ -14480,6 +14491,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;
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 04/22] target-mips: move LL and SC instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (2 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 03/22] target-mips: add SELEQZ and SELNEZ instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 05/22] target-mips: extract decode_opc_special* from decode_opc Leon Alrae
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
 disas/mips.c            |    9 ++++++++-
 target-mips/translate.c |   29 +++++++++++++++++++++++++++--
 2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index b950e53..f41b89d 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, 0xfc00003f, LDD|RD_b|WR_t,        0, I32R6},
+{"sc",      "t,o(b)",   0x7c000026, 0xfc00003f, 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 4eb8a61..75b28e2 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -345,6 +345,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 */
@@ -1771,6 +1775,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);
@@ -1864,6 +1869,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";
@@ -14753,6 +14759,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);
@@ -15057,6 +15067,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:
@@ -15072,7 +15095,8 @@ 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_opc_removed(ctx, ISA_MIPS32R6);
             check_insn(ctx, INSN_LOONGSON2E);
             gen_loongson_integer(ctx, op1, rd, rs, rt);
             break;
@@ -15458,10 +15482,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:
@@ -15472,6 +15496,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:
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 05/22] target-mips: extract decode_opc_special* from decode_opc
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (3 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 04/22] target-mips: move LL and SC instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 06/22] target-mips: split decode_opc_special* into *_r6 and *_legacy Leon Alrae
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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 | 1676 ++++++++++++++++++++++++-----------------------
 1 files changed, 858 insertions(+), 818 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 75b28e2..c67e92d 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -14431,909 +14431,948 @@ 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 (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;
+    case OPC_MOVCI:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        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;
 
 #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_opc_removed(ctx, ISA_MIPS32R6);
+        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_opc_removed(ctx, ISA_MIPS32R6);
-            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);
-                    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);
+            gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0);
             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) {
@@ -15394,6 +15433,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);
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 06/22] target-mips: split decode_opc_special* into *_r6 and *_legacy
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (4 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 05/22] target-mips: extract decode_opc_special* from decode_opc Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 21:06   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 07/22] target-mips: signal RI Exception on DSP and Loongson instructions Leon Alrae
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
v2:
* imm contains shifted value
---
 target-mips/translate.c |  227 +++++++++++++++++++++++++++++++++--------------
 1 files changed, 159 insertions(+), 68 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index c67e92d..87bb6f7 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -14431,6 +14431,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;
@@ -14463,18 +14527,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;
@@ -14529,16 +14581,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");
@@ -14568,18 +14610,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 (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;
-
 #if defined(TARGET_MIPS64)
         /* MIPS64 specific opcodes */
     case OPC_DSLL:
@@ -14661,14 +14691,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;
@@ -14681,14 +14726,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);
@@ -14732,30 +14793,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("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("special2");
+        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);
@@ -15060,19 +15169,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:
@@ -15086,13 +15182,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_opc_removed(ctx, ISA_MIPS32R6);
-        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) {
@@ -15322,9 +15411,11 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
         break;
 #endif
     default:            /* Invalid */
-        MIPS_INVAL("special3");
-        generate_exception(ctx, EXCP_RI);
-        break;
+        if (ctx->insn_flags & ISA_MIPS32R6) {
+            decode_opc_special3_r6(env, ctx);
+        } else {
+            decode_opc_special3_legacy(env, ctx);
+        }
     }
 }
 
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 07/22] target-mips: signal RI Exception on DSP and Loongson instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (5 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 06/22] target-mips: split decode_opc_special* into *_r6 and *_legacy Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 08/22] target-mips: move PREF, CACHE, LLD and SCD instructions Leon Alrae
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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 files changed, 98 insertions(+), 97 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 87bb6f7..e16620a 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -14732,6 +14732,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);
@@ -14741,11 +14761,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);
@@ -14767,15 +14786,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:
@@ -14783,15 +14793,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) {
@@ -14829,80 +14830,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:
@@ -15170,17 +15106,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);
@@ -15411,6 +15341,77 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
         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:            /* Invalid */
         if (ctx->insn_flags & ISA_MIPS32R6) {
             decode_opc_special3_r6(env, ctx);
         } else {
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 08/22] target-mips: move PREF, CACHE, LLD and SCD instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (6 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 07/22] target-mips: signal RI Exception on DSP and Loongson instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 09/22] target-mips: redefine Integer Multiply and Divide instructions Leon Alrae
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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

diff --git a/disas/mips.c b/disas/mips.c
index f41b89d..67da1f0 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, 0xfc00003f, LDD|RD_b|WR_t,        0, I32R6},
 {"sc",      "t,o(b)",   0x7c000026, 0xfc00003f, LDD|RD_b|WR_t,        0, I32R6},
+{"lld",     "t,o(b)",   0x7c000037, 0xfc00003f, LDD|RD_b|WR_t,        0, I64R6},
+{"scd",     "t,o(b)",   0x7c000027, 0xfc00003f, LDD|RD_b|WR_t,        0, I64R6},
+{"pref",    "h,o(b)",   0x7c000035, 0xfc00003f, RD_b,                 0, I32R6},
+{"cache",   "k,o(b)",   0x7c000025, 0xfc00003f, 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 e16620a..5d5a0f2 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -347,8 +347,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 */
@@ -1641,6 +1645,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);
@@ -1863,6 +1868,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";
@@ -14815,12 +14821,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);
@@ -15632,11 +15656,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;
@@ -15759,9 +15785,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);
@@ -15775,6 +15801,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);
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 09/22] target-mips: redefine Integer Multiply and Divide instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (7 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 08/22] target-mips: move PREF, CACHE, LLD and SCD instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 21:06   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 10/22] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6 Leon Alrae
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
v2:
* use tcg_gen_mul_* for cases where the high part is discarded
---
 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 67da1f0..db8d9ee 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, 0xfc00003f, LDD|RD_b|WR_t,        0, I32R6},
 {"sc",      "t,o(b)",   0x7c000026, 0xfc00003f, LDD|RD_b|WR_t,        0, I32R6},
 {"lld",     "t,o(b)",   0x7c000037, 0xfc00003f, LDD|RD_b|WR_t,        0, I64R6},
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 5d5a0f2..68834a7 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -153,6 +153,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,
@@ -210,6 +211,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))
 
@@ -2687,6 +2712,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)
 {
@@ -14440,7 +14697,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;
@@ -14448,10 +14705,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);
@@ -14461,12 +14759,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) {
@@ -14494,6 +14793,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);
@@ -14566,20 +14886,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;
@@ -14691,11 +14997,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) {
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 10/22] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (8 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 09/22] target-mips: redefine Integer Multiply and Divide instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 11/22] target-mips: Status.UX/SX/KX enable 32-bit address wrapping Leon Alrae
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
v2:
* check_insn_opc_removed() moved to decode_opc_special2_legacy()
---
 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 db8d9ee..8cb9032 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, 0xfc0007ff, WR_d|RD_s,            0, I32R6},
+{"clo",     "U,s",      0x00000051, 0xfc0007ff, WR_d|RD_s,            0, I32R6},
+{"dclz",    "U,s",      0x00000052, 0xfc0007ff, WR_d|RD_s,            0, I64R6},
+{"dclo",    "U,s",      0x00000053, 0xfc0007ff, 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 68834a7..8472fae 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -233,6 +233,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. */
@@ -3259,19 +3265,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;
@@ -14696,12 +14706,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) {
@@ -14728,7 +14739,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) {
@@ -14814,6 +14849,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);
@@ -14908,16 +14953,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;
@@ -15007,24 +15042,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;
@@ -15048,34 +15072,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);
@@ -15100,13 +15096,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;
     }
 }
 
@@ -15785,7 +15788,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);
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 11/22] target-mips: Status.UX/SX/KX enable 32-bit address wrapping
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (9 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 10/22] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6 Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 21:06   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Leon Alrae
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
v2:
* set hflag indicating 32-bit wrapping in compute_hflags
---
 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 a9b2c7a..85ff529 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -448,7 +448,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
@@ -722,7 +722,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)) {
@@ -734,8 +734,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 8472fae..363b178 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1379,11 +1379,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
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (10 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 11/22] target-mips: Status.UX/SX/KX enable 32-bit address wrapping Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 16:39   ` Richard Henderson
  2014-06-19 21:06   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches Leon Alrae
                   ` (9 subsequent siblings)
  21 siblings, 2 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
v2:
* have separate bitswap and dbitswap helpers and use common function
* use TCG_CALL_NO_RWG_SE flag for bitswap and dbitswap helpers
* remove useless shift in ALIGN and DALIGN
* improve ALIGN implementation by merging rt and rs into 64-bit register
* add missing zero register case
---
 disas/mips.c            |    4 ++
 target-mips/helper.h    |    5 ++
 target-mips/op_helper.c |   24 +++++++++
 target-mips/translate.c |  122 ++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 143 insertions(+), 12 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 8cb9032..127a7d5 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, 0xfc00003f, 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 4704216..34e9823 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -265,6 +265,30 @@ 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 363b178..270e7d3 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -390,17 +390,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 */
@@ -15111,12 +15117,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);
@@ -15137,6 +15145,44 @@ 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;
+        }
+        op2 = MASK_BSHFL(ctx->opcode);
+        switch (op2) {
+        case OPC_ALIGN ... OPC_ALIGN_END:
+            sa &= 3;
+            TCGv t0 = tcg_temp_new();
+            gen_load_gpr(t0, rt);
+            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);
+            }
+            tcg_temp_free(t0);
+            break;
+        case OPC_BITSWAP:
+            if (rt == 0) {
+                tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            } else {
+                gen_helper_bitswap(cpu_gpr[rd], cpu_gpr[rt]);
+            }
+            break;
+        }
+        break;
 #if defined(TARGET_MIPS64)
     case R6_OPC_SCD:
         gen_st_cond(ctx, op1, rt, rs, imm);
@@ -15144,6 +15190,39 @@ 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:
+        if (rd == 0) {
+            /* Treat as NOP. */
+            break;
+        }
+        op2 = MASK_DBSHFL(ctx->opcode);
+        switch (op2) {
+        case OPC_DALIGN ... OPC_DALIGN_END:
+            sa &= 7;
+            check_mips_64(ctx);
+            TCGv t0 = tcg_temp_new();
+            gen_load_gpr(t0, rt);
+            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);
+            }
+            tcg_temp_free(t0);
+            break;
+        case OPC_DBITSWAP:
+            if (rt == 0) {
+                tcg_gen_movi_tl(cpu_gpr[rd], 0);
+            } else {
+                gen_helper_dbitswap(cpu_gpr[rd], cpu_gpr[rt]);
+            }
+            break;
+        }
+        break;
 #endif
     default:            /* Invalid */
         MIPS_INVAL("special3_r6");
@@ -15689,9 +15768,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:
@@ -15701,10 +15789,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:
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (11 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-11 16:52   ` Richard Henderson
  2014-06-19 21:06   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions Leon Alrae
                   ` (8 subsequent siblings)
  21 siblings, 2 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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.

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
v2:
* rename "handle_delay_slot" to "gen_branch"
* Compact branches generate branch straightaway
* improve BOVC/BNVC, BC1EQZ, BC1NEZ implementation
---
 disas/mips.c            |   67 +++++++-
 target-mips/cpu.h       |    5 +-
 target-mips/translate.c |  481 +++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 534 insertions(+), 19 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index 127a7d5..bee39d8 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/cpu.h b/target-mips/cpu.h
index 85ff529..d1e932e 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -466,10 +466,13 @@ struct CPUMIPSState {
 #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_BMASK  (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT)
+#define MIPS_HFLAG_BMASK  (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT | \
+                           MIPS_HFLAG_CB)
     /* 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_CB    0x100000  /* Compact branch */
     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 270e7d3..1226f97 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -107,6 +107,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 */
@@ -895,6 +920,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)
@@ -929,6 +956,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))
@@ -1391,6 +1420,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)))
@@ -3907,7 +3950,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
 
     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);
+        if (ctx->hflags & MIPS_HFLAG_CB) {
+            LOG_DISAS("Branch in forbidden slot at PC 0x" TARGET_FMT_lx "\n",
+                      ctx->pc);
+        } else {
+            LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n",
+                      ctx->pc);
+        }
 #endif
         generate_exception(ctx, EXCP_RI);
         goto out;
@@ -7390,6 +7439,45 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op,
     tcg_temp_free_i32(t0);
 }
 
+/* R6 CP1 Branches (before delay slot) */
+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();
+    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:
+        tcg_gen_mov_i64(t0, t0);
+        opn = "bc1nez";
+        ctx->hflags |= MIPS_HFLAG_BC;
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
+    tcg_gen_trunc_i64_tl(bcond, t0);
+    tcg_temp_free_i64(t0);
+
+    (void)opn; /* avoid a compiler warning */
+    MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
+               ctx->hflags, btarget);
+    ctx->btarget = btarget;
+}
+
 /* Coprocessor 1 (FPU) */
 
 #define FOP(func, fmt) (((fmt) << 21) | (func))
@@ -9387,7 +9475,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;
@@ -14706,6 +14794,252 @@ 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)
+{
+    target_ulong btgt = -1;
+    int blink = 0;
+    int bcond_compute = 0;
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+#ifdef MIPS_DEBUG_DISAS
+        if (ctx->hflags & MIPS_HFLAG_CB) {
+            LOG_DISAS("Branch in forbidden slot at PC 0x" TARGET_FMT_lx "\n",
+                      ctx->pc);
+        } else {
+            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 */
+    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;
+        btgt = addr_add(ctx, ctx->pc + 4, offset);
+        if (rs <= rt && rs == 0) {
+            /* OPC_BEQZALC, OPC_BNEZALC */
+            blink = 31;
+        }
+        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;
+        btgt = 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 */
+            blink = 31;
+        }
+        gen_load_gpr(t0, rs);
+        gen_load_gpr(t1, rt);
+        bcond_compute = 1;
+        btgt = addr_add(ctx, ctx->pc + 4, offset);
+        break;
+    case OPC_BC:
+    case OPC_BALC:
+        btgt = 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;
+            btgt = 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("branch/jump");
+        generate_exception(ctx, EXCP_RI);
+        goto out;
+    }
+
+    ctx->hflags |= MIPS_HFLAG_CB;
+
+    if (bcond_compute == 0) {
+        /* No condition to be computed */
+        switch (opc) {
+        /* compact branches */
+        case OPC_JIALC:
+            blink = 31;
+            /* Fallthrough */
+        case OPC_JIC:
+            ctx->hflags |= MIPS_HFLAG_BR;
+            break;
+        case OPC_BALC:
+            blink = 31;
+            /* Fallthrough */
+        case OPC_BC:
+            ctx->hflags |= MIPS_HFLAG_B;
+            /* Always take and link */
+            break;
+        default:
+            MIPS_INVAL("branch/jump");
+            generate_exception(ctx, EXCP_RI);
+            goto out;
+        }
+    } else {
+        ctx->hflags |= MIPS_HFLAG_BC;
+
+        switch (opc) {
+        case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */
+            if (rs == 0 && rt != 0) {
+                /* OPC_BLEZALC */
+                tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t1, 0);
+            } else if (rs != 0 && rt != 0 && rs == rt) {
+                /* OPC_BGEZALC */
+                tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t1, 0);
+            } else {
+                /* OPC_BGEUC */
+                tcg_gen_setcond_tl(TCG_COND_GEU, bcond, t0, t1);
+            }
+            break;
+        case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */
+            if (rs == 0 && rt != 0) {
+                /* OPC_BGTZALC */
+                tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t1, 0);
+            } else if (rs != 0 && rt != 0 && rs == rt) {
+                /* OPC_BLTZALC */
+                tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t1, 0);
+            } else {
+                /* OPC_BLTUC */
+                tcg_gen_setcond_tl(TCG_COND_LTU, bcond, t0, t1);
+            }
+            break;
+        case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */
+            if (rs == 0 && rt != 0) {
+                /* OPC_BLEZC */
+                tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t1, 0);
+            } else if (rs != 0 && rt != 0 && rs == rt) {
+                /* OPC_BGEZC */
+                tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t1, 0);
+            } else {
+                /* OPC_BGEC */
+                tcg_gen_setcond_tl(TCG_COND_GE, bcond, t0, t1);
+            }
+            break;
+        case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */
+            if (rs == 0 && rt != 0) {
+                /* OPC_BGTZC */
+                tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t1, 0);
+            } else if (rs != 0 && rt != 0 && rs == rt) {
+                /* OPC_BLTZC */
+                tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t1, 0);
+            } else {
+                /* OPC_BLTC */
+                tcg_gen_setcond_tl(TCG_COND_LT, bcond, t0, t1);
+            }
+            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);
+                if (opc == OPC_BOVC) {
+                    /* OPC_BOVC */
+                    tcg_gen_or_tl(bcond, t4, input_overflow);
+                } else {
+                    /* OPC_BNVC */
+                    tcg_gen_or_tl(t4, t4, input_overflow);
+                    tcg_gen_xori_tl(bcond, t4, 1);
+                }
+                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_setcondi_tl(TCG_COND_EQ, bcond, t1, 0);
+                } else {
+                    /* OPC_BNEZALC */
+                    tcg_gen_setcondi_tl(TCG_COND_NE, bcond, t1, 0);
+                }
+            } else {
+                /* OPC_BEQC, OPC_BNEC */
+                if (opc == OPC_BEQC) {
+                    /* OPC_BEQC */
+                    tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
+                } else {
+                    /* OPC_BNEC */
+                    tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
+                }
+            }
+            break;
+        case OPC_BEQZC:
+            tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, t0, 0);
+            break;
+        case OPC_BNEZC:
+            tcg_gen_setcondi_tl(TCG_COND_NE, bcond, t0, 0);
+            break;
+        default:
+            MIPS_INVAL("conditional branch/jump");
+            generate_exception(ctx, EXCP_RI);
+            goto out;
+        }
+    }
+    MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx,
+                   blink, ctx->hflags, btgt);
+
+    ctx->btarget = btgt;
+    if (blink > 0) {
+        tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + 4);
+    }
+
+    /* Compact branches don't have delay slot, thus generating branch here */
+    /* TODO: implement forbidden slot */
+    gen_branch(ctx, 4);
+
+out:
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
 static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd, sa;
@@ -16011,7 +16345,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;
@@ -16029,9 +16372,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 */
@@ -16094,7 +16486,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);
@@ -16124,13 +16533,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,
+                                   SIMM((ctx->opcode & 0x3FFFFFF) << 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,
+                                   SIMM((ctx->opcode & 0x1FFFFF) << 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);
@@ -16204,12 +16635,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);
@@ -16314,8 +16764,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;
 
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (12 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-20 20:50   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 15/22] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag Leon Alrae
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 disas/mips.c            |   42 +++++++++-
 target-mips/translate.c |  198 ++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 227 insertions(+), 13 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index bee39d8..e041858 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, I32R6},
+{"ldpc",    "s,+o1",    0xec180000, 0xfc1a0000, WR_d,                 0, I32R6},
+{"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, 0xfc0007ff, WR_d|RD_s,            0, I32R6},
 {"clo",     "U,s",      0x00000051, 0xfc0007ff, WR_d|RD_s,            0, I32R6},
 {"dclz",    "U,s",      0x00000052, 0xfc0007ff, 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 1226f97..a3cbe48 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -71,6 +71,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),
@@ -137,8 +138,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 */
@@ -264,6 +282,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. */
@@ -307,6 +328,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 */
@@ -2158,8 +2182,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:
@@ -2763,6 +2794,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 = ((int32_t)ctx->opcode << 13) >> 11;
+            addr = addr_add(ctx, ctx->pc, offset);
+            tcg_gen_movi_tl(cpu_gpr[rs], addr);
+        }
+        break;
+    case R6_OPC_LWPC:
+        offset = ((int32_t)ctx->opcode << 13) >> 11;
+        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 = ((int32_t)ctx->opcode << 13) >> 11;
+        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 18 and 19 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 = (((int32_t)ctx->opcode << 14)) >> 11;
+            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";
@@ -15052,6 +15154,21 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 
     op1 = MASK_SPECIAL(ctx->opcode);
     switch (op1) {
+    case OPC_LSA:
+        {
+            int imm2 = (ctx->opcode >> 6) & 0x3;
+            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(t0, t0);
+            gen_store_gpr(t0, rd);
+            tcg_temp_free(t1);
+            tcg_temp_free(t0);
+        }
+        break;
     case OPC_MULT ... OPC_DIVU:
         op2 = MASK_R6_MULDIV(ctx->opcode);
         switch (op2) {
@@ -15089,6 +15206,21 @@ 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);
+        {
+            int imm2 = (ctx->opcode >> 6) & 0x3;
+            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);
+            gen_store_gpr(t0, rd);
+            tcg_temp_free(t1);
+            tcg_temp_free(t0);
+        }
+        break;
     case R6_OPC_DCLO:
     case R6_OPC_DCLZ:
         if (rt == 0 && sa == 1) {
@@ -15274,13 +15406,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);
 #else
         gen_helper_0e0i(pmon, sa);
 #endif
+        }
         break;
     case OPC_SYSCALL:
         generate_exception(ctx, EXCP_SYSCALL);
@@ -16251,6 +16388,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_i64(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_i64(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);
@@ -16363,7 +16518,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);
@@ -16661,14 +16816,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_i64 t0 = tcg_temp_new_i64();
+                gen_load_gpr(t0, rs);
+                tcg_gen_addi_i64(cpu_gpr[rt], t0, imm << 16);
+                tcg_temp_free_i64(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);
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 15/22] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (13 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 21:27   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 16/22] target-mips: add new Floating Point instructions Leon Alrae
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
 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 e00a6fb..7ba2de4 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)                                                       \
 INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b,     \
-                                        int ismin, int isieee STATUS_PARAM) \
+                                        int ismin, int isieee,          \
+                                        int abs 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 @@ 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 (abs) {                                                          \
+        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 @@ 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 4b3090c..feb73b7 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -375,6 +375,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 );
@@ -485,6 +487,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 );
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 16/22] target-mips: add new Floating Point instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (14 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 15/22] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-20 21:14   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 17/22] target-mips: add new Floating Point Comparison instructions Leon Alrae
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
 disas/mips.c            |   22 +++
 target-mips/helper.h    |   21 +++
 target-mips/op_helper.c |  108 +++++++++++
 target-mips/translate.c |  449 ++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 552 insertions(+), 48 deletions(-)

diff --git a/disas/mips.c b/disas/mips.c
index e041858..6196d2e 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, 0xfc00003f, 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, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"maddf.d", "D,S,T",    0x46200018, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"msubf.s", "D,S,T",    0x46000019, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"msubf.d", "D,S,T",    0x46200019, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"max.s",   "D,S,T",    0x4600001e, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"max.d",   "D,S,T",    0x4620001e, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"maxa.s",  "D,S,T",    0x4600001f, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"maxa.d",  "D,S,T",    0x4620001f, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"rint.s",  "D,S",      0x4600001a, 0xffe0001f, WR_D|RD_S|FP_S,       0, I32R6},
+{"rint.d",  "D,S",      0x4620001a, 0xffe0001f, WR_D|RD_S|FP_D,       0, I32R6},
+{"class.s", "D,S",      0x4600001b, 0xffe0001f, WR_D|RD_S|FP_S,       0, I32R6},
+{"class.d", "D,S",      0x4620001b, 0xffe0001f, WR_D|RD_S|FP_D,       0, I32R6},
+{"min.s",   "D,S,T",    0x4600001c, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"min.d",   "D,S,T",    0x4620001c, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"mina.s",  "D,S,T",    0x4600001d, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"mina.d",  "D,S,T",    0x4620001d, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"sel.s",   "D,S,T",    0x46000010, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"sel.d",   "D,S,T",    0x46200010, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"seleqz.s", "D,S,T",   0x46000014, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"seleqz.d", "D,S,T",   0x46200014, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
+{"selnez.s", "D,S,T",   0x46000017, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
+{"selnez.d", "D,S,T",   0x46200017, 0xffe0001f, 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..8bb3af7 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -202,6 +202,27 @@ 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_1(float_class_s, i32, i32)
+DEF_HELPER_1(float_class_d, i64, i64)
+
+DEF_HELPER_2(float_rint_s, i32, env, i32)
+DEF_HELPER_2(float_rint_d, i64, env, i64)
+
+DEF_HELPER_4(float_maddf_s, i32, env, i32, i32, i32)
+DEF_HELPER_4(float_maddf_d, i64, env, i64, i64, i64)
+
+DEF_HELPER_4(float_msubf_s, i32, env, i32, i32, i32)
+DEF_HELPER_4(float_msubf_d, i64, env, i64, i64, i64)
+
+#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) \
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 34e9823..fd2cfb9 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -2787,6 +2787,114 @@ 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_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
+
+uint32_t helper_float_rint_s(CPUMIPSState *env, uint32_t fs)
+{
+    uint32_t fd;
+
+    fd = float32_round_to_int(fs, &env->active_fpu.fp_status);
+    update_fcr31(env, GETPC());
+    return fd;
+}
+
+uint64_t helper_float_rint_d(CPUMIPSState *env, uint64_t fs)
+{
+    uint64_t fd;
+
+    fd = float64_round_to_int(fs, &env->active_fpu.fp_status);
+    update_fcr31(env, GETPC());
+    return fd;
+}
+
+
 /* 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 a3cbe48..a686b4a 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -7601,14 +7601,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),
@@ -7647,14 +7658,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),
@@ -7910,6 +7932,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);
+        return;
+    }
+
+    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_NE, fp0, fp1, t1, t1, fp2);
+        break;
+    case OPC_SELNEZ_D:
+        tcg_gen_andi_i64(fp1, fp1, 1);
+        tcg_gen_movcond_i64(TCG_COND_EQ, fp0, fp1, t1, t1, fp2);
+        break;
+    default:
+        MIPS_INVAL("gen_sel_d");
+        generate_exception (ctx, EXCP_RI);
+        return;
+    }
+
+    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)
@@ -8158,6 +8253,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);
@@ -8221,59 +8331,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);
+    break;
+    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_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";
+        }
+    break;
+    case OPC_RINT_S:
+        check_insn(ctx, ISA_MIPS32R6);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
-
             gen_load_fpr32(fp0, fs);
-            gen_helper_float_recip1_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 = "recip1.s";
-        break;
-    case OPC_RSQRT1_S:
-        check_cp1_64bitmode(ctx);
+    break;
+    case OPC_CLASS_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_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";
         }
-        opn = "rsqrt1.s";
         break;
-    case OPC_RSQRT2_S:
-        check_cp1_64bitmode(ctx);
-        {
+    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);
@@ -8572,6 +8798,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);
@@ -8635,59 +8876,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);
+    break;
+    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_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";
+        }
+    break;
+    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_rint_d(fp0, cpu_env, fp0);
             gen_store_fpr64(ctx, fp0, fd);
             tcg_temp_free_i64(fp0);
+            opn = "rint.d";
         }
-        opn = "recip1.d";
-        break;
-    case OPC_RSQRT1_D:
-        check_cp1_64bitmode(ctx);
+    break;
+    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_rsqrt1_d(fp0, cpu_env, fp0);
+            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";
         }
-        opn = "rsqrt1.d";
         break;
-    case OPC_RSQRT2_D:
-        check_cp1_64bitmode(ctx);
-        {
+    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.s";
+        } 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:
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 17/22] target-mips: add new Floating Point Comparison instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (15 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 16/22] target-mips: add new Floating Point instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-20 21:36   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 18/22] target-mips: do not allow Status.FR=0 mode in 64-bit FPU Leon Alrae
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
 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 6196d2e..dd2473e 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 8bb3af7..8af957f 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -305,6 +305,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 fd2cfb9..4cd63d1 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -3370,3 +3370,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 a686b4a..4c75006 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1619,6 +1619,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
 
@@ -7746,6 +7838,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";
@@ -17026,11 +17165,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);
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 18/22] target-mips: do not allow Status.FR=0 mode in 64-bit FPU
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (16 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 17/22] target-mips: add new Floating Point Comparison instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 21:27   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 19/22] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions Leon Alrae
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
 target-mips/translate.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 4c75006..e635999 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -17899,6 +17899,13 @@ 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);
+        env->CP0_Status_rw_bitmask &= ~(1 << CP0St_FR);
+    }
+
     compute_hflags(env);
     cs->exception_index = EXCP_NONE;
 }
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 19/22] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (17 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 18/22] target-mips: do not allow Status.FR=0 mode in 64-bit FPU Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 22:22   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 20/22] mips_malta: update malta's pseudo-bootloader - replace JR with JALR Leon Alrae
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
 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 dd2473e..e3e253f 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 e635999..de35b77 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -15809,6 +15809,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");
@@ -15891,7 +15894,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 */
@@ -16860,9 +16863,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:
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 20/22] mips_malta: update malta's pseudo-bootloader - replace JR with JALR
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (18 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 19/22] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 21:27   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 21/22] target-mips: use pointers referring to appropriate decoding function Leon Alrae
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 22/22] target-mips: define a new generic CPU supporting MIPS64R6 Leon Alrae
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

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>
---
 hw/mips/mips_malta.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index f4a7d47..72071c0 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -694,12 +694,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 */
@@ -713,7 +713,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 */
@@ -727,7 +727,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 */
@@ -737,7 +737,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) */
 
 }
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 21/22] target-mips: use pointers referring to appropriate decoding function
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (19 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 20/22] mips_malta: update malta's pseudo-bootloader - replace JR with JALR Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 22:18   ` Aurelien Jarno
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 22/22] target-mips: define a new generic CPU supporting MIPS64R6 Leon Alrae
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

After selecting CPU in QEMU the base ISA will not change. Therefore
introducing *_arch function pointers that are set in cpu_state_reset to
point at the appropriate SPECIAL and SPECIAL3 decoding functions, and avoid
unnecessary 'if' statements.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/translate.c |   32 +++++++++++++++++++++-----------
 1 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index de35b77..7ff7829 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -15634,6 +15634,13 @@ out:
     tcg_temp_free(t1);
 }
 
+/* Some instructions from MIPS32R6 and pre-MIPS32R6 have identical encoding.
+
+   decode_opc_*_arch are pointing at the appropriate decoding functions
+   depending on a base ISA supported by selected MIPS CPU. */
+static void (*decode_opc_special_arch) (CPUMIPSState*, DisasContext*);
+static void (*decode_opc_special3_arch) (CPUMIPSState*, DisasContext*);
+
 static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 {
     int rs, rt, rd, sa;
@@ -16002,11 +16009,8 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
         break;
 #endif
     default:
-        if (ctx->insn_flags & ISA_MIPS32R6) {
-            decode_opc_special_r6(env, ctx);
-        } else {
-            decode_opc_special_legacy(env, ctx);
-        }
+        decode_opc_special_arch(env, ctx);
+        break;
     }
 }
 
@@ -16799,12 +16803,9 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
             tcg_temp_free(t0);
         }
         break;
-    default:            /* Invalid */
-        if (ctx->insn_flags & ISA_MIPS32R6) {
-            decode_opc_special3_r6(env, ctx);
-        } else {
-            decode_opc_special3_legacy(env, ctx);
-        }
+    default:
+        decode_opc_special3_arch(env, ctx);
+        break;
     }
 }
 
@@ -17831,6 +17832,15 @@ void cpu_state_reset(CPUMIPSState *env)
     env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
     env->insn_flags = env->cpu_model->insn_flags;
 
+    /* Select decoding functions appropriate for supported ISA */
+    if (env->insn_flags & ISA_MIPS32R6) {
+        decode_opc_special_arch = decode_opc_special_r6;
+        decode_opc_special3_arch = decode_opc_special3_r6;
+    } else {
+        decode_opc_special_arch = decode_opc_special_legacy;
+        decode_opc_special3_arch = decode_opc_special3_legacy;
+    }
+
 #if defined(CONFIG_USER_ONLY)
     env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
 # ifdef TARGET_MIPS64
-- 
1.7.5.4

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

* [Qemu-devel] [PATCH v2 22/22] target-mips: define a new generic CPU supporting MIPS64R6
  2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
                   ` (20 preceding siblings ...)
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 21/22] target-mips: use pointers referring to appropriate decoding function Leon Alrae
@ 2014-06-11 15:19 ` Leon Alrae
  2014-06-19 22:16   ` Aurelien Jarno
  21 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-11 15:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: yongbok.kim, cristian.cuna, leon.alrae, aurelien, rth

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/translate_init.c |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 29dc2ef..0adbb19 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -516,6 +516,35 @@ static const mips_def_t mips_defs[] =
         .mmu_type = MMU_TYPE_R4000,
     },
     {
+        /* A generic CPU providing MIPS64 Release 6 features.
+           FIXME: 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*/
-- 
1.7.5.4

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

* Re: [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Leon Alrae
@ 2014-06-11 16:39   ` Richard Henderson
  2014-06-12  8:35     ` Leon Alrae
  2014-06-19 21:06   ` Aurelien Jarno
  1 sibling, 1 reply; 50+ messages in thread
From: Richard Henderson @ 2014-06-11 16:39 UTC (permalink / raw)
  To: Leon Alrae, qemu-devel; +Cc: yongbok.kim, cristian.cuna, aurelien

On 06/11/2014 08:19 AM, Leon Alrae wrote:
> * add missing zero register case

What missing zero register case?

> +        if (rd == 0) {
> +            /* Treat as NOP. */
> +            break;
> +        }

This is normally handled by gen_store_gpr...

> +            if (rt == 0) {
> +                tcg_gen_movi_tl(cpu_gpr[rd], 0);
> +            } else {
> +                gen_helper_dbitswap(cpu_gpr[rd], cpu_gpr[rt]);
> +            }
> +            break;

... and this is normally handed by gen_load_gpr.

Open-coding these tests just clutters the code, making it harder to read.  C.f.
the 1500 lines removed during a cleanup of target-alpha for exactly this sort
of thing.


r~

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

* Re: [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches Leon Alrae
@ 2014-06-11 16:52   ` Richard Henderson
  2014-06-24 14:03     ` Leon Alrae
  2014-06-19 21:06   ` Aurelien Jarno
  1 sibling, 1 reply; 50+ messages in thread
From: Richard Henderson @ 2014-06-11 16:52 UTC (permalink / raw)
  To: Leon Alrae, qemu-devel; +Cc: yongbok.kim, cristian.cuna, aurelien

On 06/11/2014 08:19 AM, Leon Alrae wrote:
> +        case OPC_BEQZC:
> +            tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, t0, 0);
> +            break;
...
> +    /* Compact branches don't have delay slot, thus generating branch here */
> +    /* TODO: implement forbidden slot */
> +    gen_branch(ctx, 4);

This is not what I meant by generating a branch directly.

I meant generating

  tcg_gen_brcondi(TCG_COND_EQ, t0, 0, label)

instead of computing setcond into bcond and then branching off a comparison
against bcond.

Consider creating some sort of structure that defines a condition for the
translator, much like target-s390x does with struct DisasCompare or target-i386
does with struct CCPrepare.

That lets "old" branches set up a condition based off bcond, and your new
branches set up a condition based off the general registers (or brand new temps
in the case of BOVC/BNVC).

The ability to select the TCG compare op also allows you to avoid things like
the xor at the end of your BNVC computation.


r~

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

* Re: [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  2014-06-11 16:39   ` Richard Henderson
@ 2014-06-12  8:35     ` Leon Alrae
  2014-06-12 14:34       ` Richard Henderson
  0 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-12  8:35 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: yongbok.kim, cristian.cuna, aurelien

On 11/06/2014 17:39, Richard Henderson wrote:
> On 06/11/2014 08:19 AM, Leon Alrae wrote:
>> * add missing zero register case
> 
> What missing zero register case?
> 
>> +        if (rd == 0) {
>> +            /* Treat as NOP. */
>> +            break;
>> +        }
> 
> This is normally handled by gen_store_gpr...
> 
>> +            if (rt == 0) {
>> +                tcg_gen_movi_tl(cpu_gpr[rd], 0);
>> +            } else {
>> +                gen_helper_dbitswap(cpu_gpr[rd], cpu_gpr[rt]);
>> +            }
>> +            break;
> 
> ... and this is normally handed by gen_load_gpr.
> 
> Open-coding these tests just clutters the code, making it harder to read.  C.f.
> the 1500 lines removed during a cleanup of target-alpha for exactly this sort
> of thing.

Yes, it clutters the code a bit. However, by looking at the other
instructions I got the impression that preferable approach is to avoid
generating unnecessary code if we can. This seems to be sensible so I'm
trying to stick to it. So in bitswap example I think there is no point
in calling the helper if we know that the result will be 0.

Regards,
Leon

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

* Re: [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  2014-06-12  8:35     ` Leon Alrae
@ 2014-06-12 14:34       ` Richard Henderson
  0 siblings, 0 replies; 50+ messages in thread
From: Richard Henderson @ 2014-06-12 14:34 UTC (permalink / raw)
  To: Leon Alrae, qemu-devel; +Cc: yongbok.kim, cristian.cuna, aurelien

On 06/12/2014 01:35 AM, Leon Alrae wrote:
> Yes, it clutters the code a bit. However, by looking at the other
> instructions I got the impression that preferable approach is to avoid
> generating unnecessary code if we can. This seems to be sensible so I'm
> trying to stick to it. So in bitswap example I think there is no point
> in calling the helper if we know that the result will be 0.

On the other hand, for certain values of never that exclude conformance testing
software, one will never see r0 as input to bswap.  So it's still a useless
optimization.


r~

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

* Re: [Qemu-devel] [PATCH v2 01/22] target-mips: define ISA_MIPS64R6
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 01/22] target-mips: define ISA_MIPS64R6 Leon Alrae
@ 2014-06-19 21:06   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:06 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:31PM +0100, Leon Alrae wrote:
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
> v2:
> * move new CPU definition to a separate patch
> ---
>  target-mips/mips-defs.h |   28 +++++++++++++++++++---------
>  1 files 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.

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>


-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 06/22] target-mips: split decode_opc_special* into *_r6 and *_legacy
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 06/22] target-mips: split decode_opc_special* into *_r6 and *_legacy Leon Alrae
@ 2014-06-19 21:06   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:06 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:36PM +0100, Leon Alrae wrote:
> 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>
> ---
> v2:
> * imm contains shifted value
> ---
>  target-mips/translate.c |  227 +++++++++++++++++++++++++++++++++--------------
>  1 files changed, 159 insertions(+), 68 deletions(-)
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index c67e92d..87bb6f7 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -14431,6 +14431,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;
> @@ -14463,18 +14527,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;
> @@ -14529,16 +14581,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");
> @@ -14568,18 +14610,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 (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;
> -
>  #if defined(TARGET_MIPS64)
>          /* MIPS64 specific opcodes */
>      case OPC_DSLL:
> @@ -14661,14 +14691,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;
> @@ -14681,14 +14726,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);
> @@ -14732,30 +14793,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("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("special2");
> +        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);
> @@ -15060,19 +15169,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:
> @@ -15086,13 +15182,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_opc_removed(ctx, ISA_MIPS32R6);
> -        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) {
> @@ -15322,9 +15411,11 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
>          break;
>  #endif
>      default:            /* Invalid */
> -        MIPS_INVAL("special3");
> -        generate_exception(ctx, EXCP_RI);
> -        break;
> +        if (ctx->insn_flags & ISA_MIPS32R6) {
> +            decode_opc_special3_r6(env, ctx);
> +        } else {
> +            decode_opc_special3_legacy(env, ctx);
> +        }
>      }
>  }
>  

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 09/22] target-mips: redefine Integer Multiply and Divide instructions
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 09/22] target-mips: redefine Integer Multiply and Divide instructions Leon Alrae
@ 2014-06-19 21:06   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:06 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:39PM +0100, Leon Alrae wrote:
> 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>
> ---
> v2:
> * use tcg_gen_mul_* for cases where the high part is discarded
> ---
>  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 67da1f0..db8d9ee 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, 0xfc00003f, LDD|RD_b|WR_t,        0, I32R6},
>  {"sc",      "t,o(b)",   0x7c000026, 0xfc00003f, LDD|RD_b|WR_t,        0, I32R6},
>  {"lld",     "t,o(b)",   0x7c000037, 0xfc00003f, LDD|RD_b|WR_t,        0, I64R6},
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index 5d5a0f2..68834a7 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -153,6 +153,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,
> @@ -210,6 +211,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))
>  
> @@ -2687,6 +2712,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);
> +        }

So you ended-up with the same code for MUL and MULU, which is not
surprising as these instructions are doing the same despite a different
description in the manual. The point is that a n x n => n multiplication
is neither signed nor unsigned. The signedness comes into account when
using n x n => 2n multiplications.

This is basically the same issue as MULT.G vs MULTU.G and DMULT.G vs
DMULTU.G for the Loongson 2 instructions.

I leave you choose if you want to merge the two opcodes or not.

> +        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;

Same comment here for DMUL vs DMULU.

> +    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)
>  {
> @@ -14440,7 +14697,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;
> @@ -14448,10 +14705,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);
> @@ -14461,12 +14759,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) {
> @@ -14494,6 +14793,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);
> @@ -14566,20 +14886,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;
> @@ -14691,11 +14997,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) {

Besides the small nitpicks above (which are more CPU issues than code
issue):

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>


-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 11/22] target-mips: Status.UX/SX/KX enable 32-bit address wrapping
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 11/22] target-mips: Status.UX/SX/KX enable 32-bit address wrapping Leon Alrae
@ 2014-06-19 21:06   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:06 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:41PM +0100, Leon Alrae wrote:
> 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>
> ---
> v2:
> * set hflag indicating 32-bit wrapping in compute_hflags
> ---
>  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 a9b2c7a..85ff529 100644
> --- a/target-mips/cpu.h
> +++ b/target-mips/cpu.h
> @@ -448,7 +448,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
> @@ -722,7 +722,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)) {
> @@ -734,8 +734,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 8472fae..363b178 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -1379,11 +1379,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

Thanks for the changes (and the improvement of the existing code).

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>


-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Leon Alrae
  2014-06-11 16:39   ` Richard Henderson
@ 2014-06-19 21:06   ` Aurelien Jarno
  1 sibling, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:06 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:42PM +0100, Leon Alrae wrote:
> 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>
> ---
> v2:
> * have separate bitswap and dbitswap helpers and use common function
> * use TCG_CALL_NO_RWG_SE flag for bitswap and dbitswap helpers
> * remove useless shift in ALIGN and DALIGN
> * improve ALIGN implementation by merging rt and rs into 64-bit register
> * add missing zero register case
> ---
>  disas/mips.c            |    4 ++
>  target-mips/helper.h    |    5 ++
>  target-mips/op_helper.c |   24 +++++++++
>  target-mips/translate.c |  122 ++++++++++++++++++++++++++++++++++++++++++-----
>  4 files changed, 143 insertions(+), 12 deletions(-)
> 
> diff --git a/disas/mips.c b/disas/mips.c
> index 8cb9032..127a7d5 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, 0xfc00003f, 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 4704216..34e9823 100644
> --- a/target-mips/op_helper.c
> +++ b/target-mips/op_helper.c
> @@ -265,6 +265,30 @@ 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 363b178..270e7d3 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -390,17 +390,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 */
> @@ -15111,12 +15117,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);
> @@ -15137,6 +15145,44 @@ 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;
> +        }
> +        op2 = MASK_BSHFL(ctx->opcode);
> +        switch (op2) {
> +        case OPC_ALIGN ... OPC_ALIGN_END:
> +            sa &= 3;
> +            TCGv t0 = tcg_temp_new();
> +            gen_load_gpr(t0, rt);
> +            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);
> +            }
> +            tcg_temp_free(t0);
> +            break;
> +        case OPC_BITSWAP:
> +            if (rt == 0) {
> +                tcg_gen_movi_tl(cpu_gpr[rd], 0);
> +            } else {
> +                gen_helper_bitswap(cpu_gpr[rd], cpu_gpr[rt]);
> +            }
> +            break;
> +        }
> +        break;
>  #if defined(TARGET_MIPS64)
>      case R6_OPC_SCD:
>          gen_st_cond(ctx, op1, rt, rs, imm);
> @@ -15144,6 +15190,39 @@ 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:
> +        if (rd == 0) {
> +            /* Treat as NOP. */
> +            break;
> +        }

This optimisation is fine, otherwise we'll end up writing in the
wrong register.

> +        op2 = MASK_DBSHFL(ctx->opcode);
> +        switch (op2) {
> +        case OPC_DALIGN ... OPC_DALIGN_END:
> +            sa &= 7;
> +            check_mips_64(ctx);
> +            TCGv t0 = tcg_temp_new();
> +            gen_load_gpr(t0, rt);
> +            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);
> +            }
> +            tcg_temp_free(t0);
> +            break;
> +        case OPC_DBITSWAP:
> +            if (rt == 0) {
> +                tcg_gen_movi_tl(cpu_gpr[rd], 0);
> +            } else {
> +                gen_helper_dbitswap(cpu_gpr[rd], cpu_gpr[rt]);
> +            }
> +            break;

As Richard said, this is not really useful if it is not common to call
the instruction that way.

It's true we have existing code like that, but it is usually either
needed for correctness (in the shift cases), or for performances (to
avoid doing additions for MOV/MOVI, or to skip the usual forms of NOP).

> +        }
> +        break;
>  #endif
>      default:            /* Invalid */
>          MIPS_INVAL("special3_r6");
> @@ -15689,9 +15768,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:
> @@ -15701,10 +15789,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:

Besides the above nitpicks:

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches Leon Alrae
  2014-06-11 16:52   ` Richard Henderson
@ 2014-06-19 21:06   ` Aurelien Jarno
  1 sibling, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:06 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:43PM +0100, Leon Alrae wrote:
> 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.
> 
> Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
> v2:
> * rename "handle_delay_slot" to "gen_branch"
> * Compact branches generate branch straightaway
> * improve BOVC/BNVC, BC1EQZ, BC1NEZ implementation
> ---
>  disas/mips.c            |   67 +++++++-
>  target-mips/cpu.h       |    5 +-
>  target-mips/translate.c |  481 +++++++++++++++++++++++++++++++++++++++++++++--
>  3 files changed, 534 insertions(+), 19 deletions(-)
> 
> diff --git a/disas/mips.c b/disas/mips.c
> index 127a7d5..bee39d8 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/cpu.h b/target-mips/cpu.h
> index 85ff529..d1e932e 100644
> --- a/target-mips/cpu.h
> +++ b/target-mips/cpu.h
> @@ -466,10 +466,13 @@ struct CPUMIPSState {
>  #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_BMASK  (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT)
> +#define MIPS_HFLAG_BMASK  (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT | \
> +                           MIPS_HFLAG_CB)
>      /* 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_CB    0x100000  /* Compact branch */
>      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 270e7d3..1226f97 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -107,6 +107,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 */
> @@ -895,6 +920,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)
> @@ -929,6 +956,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))
> @@ -1391,6 +1420,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)))
> @@ -3907,7 +3950,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
>  
>      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);
> +        if (ctx->hflags & MIPS_HFLAG_CB) {
> +            LOG_DISAS("Branch in forbidden slot at PC 0x" TARGET_FMT_lx "\n",
> +                      ctx->pc);
> +        } else {
> +            LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n",
> +                      ctx->pc);
> +        }
>  #endif
>          generate_exception(ctx, EXCP_RI);
>          goto out;
> @@ -7390,6 +7439,45 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op,
>      tcg_temp_free_i32(t0);
>  }
>  
> +/* R6 CP1 Branches (before delay slot) */
> +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();
> +    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:
> +        tcg_gen_mov_i64(t0, t0);

I suggested that, though it's basically useless. This could simply be
removed.

> +        opn = "bc1nez";
> +        ctx->hflags |= MIPS_HFLAG_BC;
> +        break;
> +    default:
> +        MIPS_INVAL(opn);
> +        generate_exception(ctx, EXCP_RI);
> +        return;
> +    }
> +
> +    tcg_gen_trunc_i64_tl(bcond, t0);
> +    tcg_temp_free_i64(t0);
> +
> +    (void)opn; /* avoid a compiler warning */
> +    MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
> +               ctx->hflags, btarget);
> +    ctx->btarget = btarget;
> +}
> +
>  /* Coprocessor 1 (FPU) */
>  
>  #define FOP(func, fmt) (((fmt) << 21) | (func))
> @@ -9387,7 +9475,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;
> @@ -14706,6 +14794,252 @@ 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)
> +{
> +    target_ulong btgt = -1;
> +    int blink = 0;
> +    int bcond_compute = 0;
> +    TCGv t0 = tcg_temp_new();
> +    TCGv t1 = tcg_temp_new();
> +
> +    if (ctx->hflags & MIPS_HFLAG_BMASK) {
> +#ifdef MIPS_DEBUG_DISAS
> +        if (ctx->hflags & MIPS_HFLAG_CB) {
> +            LOG_DISAS("Branch in forbidden slot at PC 0x" TARGET_FMT_lx "\n",
> +                      ctx->pc);
> +        } else {
> +            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 */
> +    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;
> +        btgt = addr_add(ctx, ctx->pc + 4, offset);
> +        if (rs <= rt && rs == 0) {
> +            /* OPC_BEQZALC, OPC_BNEZALC */
> +            blink = 31;
> +        }
> +        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;
> +        btgt = 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 */
> +            blink = 31;
> +        }
> +        gen_load_gpr(t0, rs);
> +        gen_load_gpr(t1, rt);
> +        bcond_compute = 1;
> +        btgt = addr_add(ctx, ctx->pc + 4, offset);
> +        break;
> +    case OPC_BC:
> +    case OPC_BALC:
> +        btgt = 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;
> +            btgt = 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("branch/jump");
> +        generate_exception(ctx, EXCP_RI);
> +        goto out;
> +    }
> +
> +    ctx->hflags |= MIPS_HFLAG_CB;
> +
> +    if (bcond_compute == 0) {
> +        /* No condition to be computed */
> +        switch (opc) {
> +        /* compact branches */
> +        case OPC_JIALC:
> +            blink = 31;
> +            /* Fallthrough */
> +        case OPC_JIC:
> +            ctx->hflags |= MIPS_HFLAG_BR;
> +            break;
> +        case OPC_BALC:
> +            blink = 31;
> +            /* Fallthrough */
> +        case OPC_BC:
> +            ctx->hflags |= MIPS_HFLAG_B;
> +            /* Always take and link */
> +            break;
> +        default:
> +            MIPS_INVAL("branch/jump");
> +            generate_exception(ctx, EXCP_RI);
> +            goto out;
> +        }
> +    } else {
> +        ctx->hflags |= MIPS_HFLAG_BC;
> +
> +        switch (opc) {
> +        case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */
> +            if (rs == 0 && rt != 0) {
> +                /* OPC_BLEZALC */
> +                tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t1, 0);
> +            } else if (rs != 0 && rt != 0 && rs == rt) {
> +                /* OPC_BGEZALC */
> +                tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t1, 0);
> +            } else {
> +                /* OPC_BGEUC */
> +                tcg_gen_setcond_tl(TCG_COND_GEU, bcond, t0, t1);
> +            }
> +            break;
> +        case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */
> +            if (rs == 0 && rt != 0) {
> +                /* OPC_BGTZALC */
> +                tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t1, 0);
> +            } else if (rs != 0 && rt != 0 && rs == rt) {
> +                /* OPC_BLTZALC */
> +                tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t1, 0);
> +            } else {
> +                /* OPC_BLTUC */
> +                tcg_gen_setcond_tl(TCG_COND_LTU, bcond, t0, t1);
> +            }
> +            break;
> +        case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */
> +            if (rs == 0 && rt != 0) {
> +                /* OPC_BLEZC */
> +                tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t1, 0);
> +            } else if (rs != 0 && rt != 0 && rs == rt) {
> +                /* OPC_BGEZC */
> +                tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t1, 0);
> +            } else {
> +                /* OPC_BGEC */
> +                tcg_gen_setcond_tl(TCG_COND_GE, bcond, t0, t1);
> +            }
> +            break;
> +        case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */
> +            if (rs == 0 && rt != 0) {
> +                /* OPC_BGTZC */
> +                tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t1, 0);
> +            } else if (rs != 0 && rt != 0 && rs == rt) {
> +                /* OPC_BLTZC */
> +                tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t1, 0);
> +            } else {
> +                /* OPC_BLTC */
> +                tcg_gen_setcond_tl(TCG_COND_LT, bcond, t0, t1);
> +            }
> +            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);
> +                if (opc == OPC_BOVC) {
> +                    /* OPC_BOVC */
> +                    tcg_gen_or_tl(bcond, t4, input_overflow);
> +                } else {
> +                    /* OPC_BNVC */
> +                    tcg_gen_or_tl(t4, t4, input_overflow);
> +                    tcg_gen_xori_tl(bcond, t4, 1);
> +                }
> +                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_setcondi_tl(TCG_COND_EQ, bcond, t1, 0);
> +                } else {
> +                    /* OPC_BNEZALC */
> +                    tcg_gen_setcondi_tl(TCG_COND_NE, bcond, t1, 0);
> +                }
> +            } else {
> +                /* OPC_BEQC, OPC_BNEC */
> +                if (opc == OPC_BEQC) {
> +                    /* OPC_BEQC */
> +                    tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> +                } else {
> +                    /* OPC_BNEC */
> +                    tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> +                }
> +            }
> +            break;
> +        case OPC_BEQZC:
> +            tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, t0, 0);
> +            break;
> +        case OPC_BNEZC:
> +            tcg_gen_setcondi_tl(TCG_COND_NE, bcond, t0, 0);
> +            break;
> +        default:
> +            MIPS_INVAL("conditional branch/jump");
> +            generate_exception(ctx, EXCP_RI);
> +            goto out;
> +        }
> +    }
> +    MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx,
> +                   blink, ctx->hflags, btgt);
> +
> +    ctx->btarget = btgt;
> +    if (blink > 0) {
> +        tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + 4);
> +    }
> +
> +    /* Compact branches don't have delay slot, thus generating branch here */
> +    /* TODO: implement forbidden slot */
> +    gen_branch(ctx, 4);
> +
> +out:
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +}
> +
>  static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
>  {
>      int rs, rt, rd, sa;
> @@ -16011,7 +16345,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;
> @@ -16029,9 +16372,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 */
> @@ -16094,7 +16486,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);
> @@ -16124,13 +16533,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,
> +                                   SIMM((ctx->opcode & 0x3FFFFFF) << 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,
> +                                   SIMM((ctx->opcode & 0x1FFFFF) << 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);
> @@ -16204,12 +16635,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);
> @@ -16314,8 +16764,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;
>  
> -- 
> 1.7.5.4
> 
> 

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 20/22] mips_malta: update malta's pseudo-bootloader - replace JR with JALR
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 20/22] mips_malta: update malta's pseudo-bootloader - replace JR with JALR Leon Alrae
@ 2014-06-19 21:27   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:27 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:50PM +0100, Leon Alrae wrote:
> 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>
> ---
>  hw/mips/mips_malta.c |   10 +++++-----
>  1 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
> index f4a7d47..72071c0 100644
> --- a/hw/mips/mips_malta.c
> +++ b/hw/mips/mips_malta.c
> @@ -694,12 +694,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 */
> @@ -713,7 +713,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 */
> @@ -727,7 +727,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 */
> @@ -737,7 +737,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) */
>  

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 18/22] target-mips: do not allow Status.FR=0 mode in 64-bit FPU
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 18/22] target-mips: do not allow Status.FR=0 mode in 64-bit FPU Leon Alrae
@ 2014-06-19 21:27   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:27 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:48PM +0100, Leon Alrae wrote:
> 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>
> ---
>  target-mips/translate.c |    7 +++++++
>  1 files changed, 7 insertions(+), 0 deletions(-)
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index 4c75006..e635999 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -17899,6 +17899,13 @@ 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);

This is fine

> +        env->CP0_Status_rw_bitmask &= ~(1 << CP0St_FR);

IMHO This should be done directly in the CPU definition.

> +    }
> +
>      compute_hflags(env);
>      cs->exception_index = EXCP_NONE;
>  }
> -- 
> 1.7.5.4
> 
> 

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 15/22] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 15/22] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag Leon Alrae
@ 2014-06-19 21:27   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 21:27 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:45PM +0100, Leon Alrae wrote:
> 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>
> ---
>  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 e00a6fb..7ba2de4 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)                                                       \
>  INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b,     \
> -                                        int ismin, int isieee STATUS_PARAM) \
> +                                        int ismin, int isieee,          \
> +                                        int abs STATUS_PARAM)           \

Maybe ismag instead of abs, to follow the convention of other parameters?

>  {                                                                       \
>      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 @@ 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 (abs) {                                                          \
> +        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 @@ 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 4b3090c..feb73b7 100644
> --- a/include/fpu/softfloat.h
> +++ b/include/fpu/softfloat.h
> @@ -375,6 +375,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 );
> @@ -485,6 +487,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 );

Besides the small nitpick above, this looks fine to me, so:

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 22/22] target-mips: define a new generic CPU supporting MIPS64R6
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 22/22] target-mips: define a new generic CPU supporting MIPS64R6 Leon Alrae
@ 2014-06-19 22:16   ` Aurelien Jarno
  2014-06-24 11:56     ` Leon Alrae
  0 siblings, 1 reply; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 22:16 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:52PM +0100, Leon Alrae wrote:
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
>  target-mips/translate_init.c |   29 +++++++++++++++++++++++++++++
>  1 files changed, 29 insertions(+), 0 deletions(-)
> 
> diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
> index 29dc2ef..0adbb19 100644
> --- a/target-mips/translate_init.c
> +++ b/target-mips/translate_init.c
> @@ -516,6 +516,35 @@ static const mips_def_t mips_defs[] =
>          .mmu_type = MMU_TYPE_R4000,
>      },
>      {
> +        /* A generic CPU providing MIPS64 Release 6 features.
> +           FIXME: 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*/

Sorry to say that again, but I think it should be deferred to the point
where the MIPS R6 CPU is fully functional, so probably after the
"implement features required in MIPS64 Release 6", and probably even
more, as I haven't seen any patch concerning the unaligned access
support yet.


-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 21/22] target-mips: use pointers referring to appropriate decoding function
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 21/22] target-mips: use pointers referring to appropriate decoding function Leon Alrae
@ 2014-06-19 22:18   ` Aurelien Jarno
  2014-06-20  4:09     ` Richard Henderson
  0 siblings, 1 reply; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 22:18 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:51PM +0100, Leon Alrae wrote:
> After selecting CPU in QEMU the base ISA will not change. Therefore
> introducing *_arch function pointers that are set in cpu_state_reset to
> point at the appropriate SPECIAL and SPECIAL3 decoding functions, and avoid
> unnecessary 'if' statements.
> 
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
>  target-mips/translate.c |   32 +++++++++++++++++++++-----------
>  1 files changed, 21 insertions(+), 11 deletions(-)
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index de35b77..7ff7829 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -15634,6 +15634,13 @@ out:
>      tcg_temp_free(t1);
>  }
>  
> +/* Some instructions from MIPS32R6 and pre-MIPS32R6 have identical encoding.
> +
> +   decode_opc_*_arch are pointing at the appropriate decoding functions
> +   depending on a base ISA supported by selected MIPS CPU. */
> +static void (*decode_opc_special_arch) (CPUMIPSState*, DisasContext*);
> +static void (*decode_opc_special3_arch) (CPUMIPSState*, DisasContext*);
> +
>  static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
>  {
>      int rs, rt, rd, sa;
> @@ -16002,11 +16009,8 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
>          break;
>  #endif
>      default:
> -        if (ctx->insn_flags & ISA_MIPS32R6) {
> -            decode_opc_special_r6(env, ctx);
> -        } else {
> -            decode_opc_special_legacy(env, ctx);
> -        }
> +        decode_opc_special_arch(env, ctx);
> +        break;
>      }
>  }
>  
> @@ -16799,12 +16803,9 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
>              tcg_temp_free(t0);
>          }
>          break;
> -    default:            /* Invalid */
> -        if (ctx->insn_flags & ISA_MIPS32R6) {
> -            decode_opc_special3_r6(env, ctx);
> -        } else {
> -            decode_opc_special3_legacy(env, ctx);
> -        }
> +    default:
> +        decode_opc_special3_arch(env, ctx);
> +        break;
>      }
>  }
>  
> @@ -17831,6 +17832,15 @@ void cpu_state_reset(CPUMIPSState *env)
>      env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
>      env->insn_flags = env->cpu_model->insn_flags;
>  
> +    /* Select decoding functions appropriate for supported ISA */
> +    if (env->insn_flags & ISA_MIPS32R6) {
> +        decode_opc_special_arch = decode_opc_special_r6;
> +        decode_opc_special3_arch = decode_opc_special3_r6;
> +    } else {
> +        decode_opc_special_arch = decode_opc_special_legacy;
> +        decode_opc_special3_arch = decode_opc_special3_legacy;
> +    }
> +
>  #if defined(CONFIG_USER_ONLY)
>      env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
>  # ifdef TARGET_MIPS64

I have mixed filling about that. While it clearly makes the code more
readable, I am not sure it would be any faster given that it might kill
branch prediction. Any opinion from others?

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 19/22] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 19/22] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions Leon Alrae
@ 2014-06-19 22:22   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-19 22:22 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:49PM +0100, Leon Alrae wrote:
> 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>
> ---
>  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 dd2473e..e3e253f 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 e635999..de35b77 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -15809,6 +15809,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");
> @@ -15891,7 +15894,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 */
> @@ -16860,9 +16863,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:

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 21/22] target-mips: use pointers referring to appropriate decoding function
  2014-06-19 22:18   ` Aurelien Jarno
@ 2014-06-20  4:09     ` Richard Henderson
  0 siblings, 0 replies; 50+ messages in thread
From: Richard Henderson @ 2014-06-20  4:09 UTC (permalink / raw)
  To: Aurelien Jarno, Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel

On 06/19/2014 03:18 PM, Aurelien Jarno wrote:
> I have mixed filling about that. While it clearly makes the code more
> readable, I am not sure it would be any faster given that it might kill
> branch prediction. Any opinion from others?

Given the function pointer is used only once, I don't think it's useful.  With
normal branch predictors we'll do much better with direct branches, and
probably inlining.


r~

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

* Re: [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions Leon Alrae
@ 2014-06-20 20:50   ` Aurelien Jarno
  2014-06-24  9:50     ` Leon Alrae
  0 siblings, 1 reply; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-20 20:50 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

The patch subject is a bit misleading, as it also includes the AUI family.


On Wed, Jun 11, 2014 at 04:19:44PM +0100, Leon Alrae wrote:
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
>  disas/mips.c            |   42 +++++++++-
>  target-mips/translate.c |  198 ++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 227 insertions(+), 13 deletions(-)
> 
> diff --git a/disas/mips.c b/disas/mips.c
> index bee39d8..e041858 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, I32R6},
> +{"ldpc",    "s,+o1",    0xec180000, 0xfc1a0000, WR_d,                 0, I32R6},
> +{"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, 0xfc0007ff, WR_d|RD_s,            0, I32R6},
>  {"clo",     "U,s",      0x00000051, 0xfc0007ff, WR_d|RD_s,            0, I32R6},
>  {"dclz",    "U,s",      0x00000052, 0xfc0007ff, 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 1226f97..a3cbe48 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -71,6 +71,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),
> @@ -137,8 +138,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 */
> @@ -264,6 +282,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. */
> @@ -307,6 +328,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 */
> @@ -2158,8 +2182,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:
> @@ -2763,6 +2794,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 = ((int32_t)ctx->opcode << 13) >> 11;
> +            addr = addr_add(ctx, ctx->pc, offset);
> +            tcg_gen_movi_tl(cpu_gpr[rs], addr);
> +        }
> +        break;
> +    case R6_OPC_LWPC:
> +        offset = ((int32_t)ctx->opcode << 13) >> 11;
> +        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 = ((int32_t)ctx->opcode << 13) >> 11;
> +        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 18 and 19 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 = (((int32_t)ctx->opcode << 14)) >> 11;

This will overflow the 32-bits type. I guess you want:

               offset = (((int32_t)ctx->opcode << 13)) >> 10;

I do wonder if we shouldn't use sextract32() instead of open coding that
now that it is available:

               offset = sextract32(ctx->opcode, 0, 19) << 3;

> +            addr = addr_add(ctx, (ctx->pc & ~0x7), offset);

Why do we need to mask the low 3 bits of the PC? It doesn't appear in
the manual version I have (MD00087 version 6.00).

> +            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";
> @@ -15052,6 +15154,21 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
>  
>      op1 = MASK_SPECIAL(ctx->opcode);
>      switch (op1) {
> +    case OPC_LSA:
> +        {
> +            int imm2 = (ctx->opcode >> 6) & 0x3;
> +            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(t0, t0);
> +            gen_store_gpr(t0, rd);
> +            tcg_temp_free(t1);
> +            tcg_temp_free(t0);
> +        }
> +        break;
>      case OPC_MULT ... OPC_DIVU:
>          op2 = MASK_R6_MULDIV(ctx->opcode);
>          switch (op2) {
> @@ -15089,6 +15206,21 @@ 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);
> +        {
> +            int imm2 = (ctx->opcode >> 6) & 0x3;
> +            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);
> +            gen_store_gpr(t0, rd);
> +            tcg_temp_free(t1);
> +            tcg_temp_free(t0);
> +        }
> +        break;
>      case R6_OPC_DCLO:
>      case R6_OPC_DCLZ:
>          if (rt == 0 && sa == 1) {
> @@ -15274,13 +15406,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);
>  #else
>          gen_helper_0e0i(pmon, sa);
>  #endif
> +        }
>          break;
>      case OPC_SYSCALL:
>          generate_exception(ctx, EXCP_SYSCALL);
> @@ -16251,6 +16388,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_i64(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 32);

Small nitpicking: even if it is guarded by #ifdef, in theory the _tl
type should be used there, to match the register type.

> +            }
> +            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_i64(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 48);

Ditto

> +            }
> +            MIPS_DEBUG("dati %s, %04x", regnames[rs], imm);
> +            break;
> +#endif
>          default:            /* Invalid */
>              MIPS_INVAL("regimm");
>              generate_exception(ctx, EXCP_RI);
> @@ -16363,7 +16518,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);
> @@ -16661,14 +16816,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_i64 t0 = tcg_temp_new_i64();
> +                gen_load_gpr(t0, rs);
> +                tcg_gen_addi_i64(cpu_gpr[rt], t0, imm << 16);
> +                tcg_temp_free_i64(t0);

Ditto.

> +            }
> +            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);
> -- 
> 1.7.5.4
> 
> 

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 16/22] target-mips: add new Floating Point instructions
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 16/22] target-mips: add new Floating Point instructions Leon Alrae
@ 2014-06-20 21:14   ` Aurelien Jarno
  2014-06-24 12:10     ` Leon Alrae
  0 siblings, 1 reply; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-20 21:14 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:46PM +0100, Leon Alrae wrote:
> 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.

I don't think we can "update" softfloat. The existing version has to
stay to correctly emulate the existing CPU, and unfortunately things like
the sNaN bit is not even configurable at runtime, but fixed at compile time
(in softfloat-specialize.h). How do you plan to handle that?

> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
>  disas/mips.c            |   22 +++
>  target-mips/helper.h    |   21 +++
>  target-mips/op_helper.c |  108 +++++++++++
>  target-mips/translate.c |  449 ++++++++++++++++++++++++++++++++++++++++++-----
>  4 files changed, 552 insertions(+), 48 deletions(-)
> 
> diff --git a/disas/mips.c b/disas/mips.c
> index e041858..6196d2e 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, 0xfc00003f, 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, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"maddf.d", "D,S,T",    0x46200018, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
> +{"msubf.s", "D,S,T",    0x46000019, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"msubf.d", "D,S,T",    0x46200019, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
> +{"max.s",   "D,S,T",    0x4600001e, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"max.d",   "D,S,T",    0x4620001e, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
> +{"maxa.s",  "D,S,T",    0x4600001f, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"maxa.d",  "D,S,T",    0x4620001f, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
> +{"rint.s",  "D,S",      0x4600001a, 0xffe0001f, WR_D|RD_S|FP_S,       0, I32R6},
> +{"rint.d",  "D,S",      0x4620001a, 0xffe0001f, WR_D|RD_S|FP_D,       0, I32R6},
> +{"class.s", "D,S",      0x4600001b, 0xffe0001f, WR_D|RD_S|FP_S,       0, I32R6},
> +{"class.d", "D,S",      0x4620001b, 0xffe0001f, WR_D|RD_S|FP_D,       0, I32R6},
> +{"min.s",   "D,S,T",    0x4600001c, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"min.d",   "D,S,T",    0x4620001c, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
> +{"mina.s",  "D,S,T",    0x4600001d, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"mina.d",  "D,S,T",    0x4620001d, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
> +{"sel.s",   "D,S,T",    0x46000010, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"sel.d",   "D,S,T",    0x46200010, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
> +{"seleqz.s", "D,S,T",   0x46000014, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"seleqz.d", "D,S,T",   0x46200014, 0xffe0001f, WR_D|RD_S|RD_T|FP_D,  0, I32R6},
> +{"selnez.s", "D,S,T",   0x46000017, 0xffe0001f, WR_D|RD_S|RD_T|FP_S,  0, I32R6},
> +{"selnez.d", "D,S,T",   0x46200017, 0xffe0001f, 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..8bb3af7 100644
> --- a/target-mips/helper.h
> +++ b/target-mips/helper.h
> @@ -202,6 +202,27 @@ 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_1(float_class_s, i32, i32)
> +DEF_HELPER_1(float_class_d, i64, i64)
> +
> +DEF_HELPER_2(float_rint_s, i32, env, i32)
> +DEF_HELPER_2(float_rint_d, i64, env, i64)
> +
> +DEF_HELPER_4(float_maddf_s, i32, env, i32, i32, i32)
> +DEF_HELPER_4(float_maddf_d, i64, env, i64, i64, i64)
> +
> +DEF_HELPER_4(float_msubf_s, i32, env, i32, i32, i32)
> +DEF_HELPER_4(float_msubf_d, i64, env, i64, i64, i64)
> +

Why not using FOP_PROTO here?

> +#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
> +

But using it here.

Also I guess you can reuse the existing FOP_PROTO macros.

>  #define FOP_PROTO(op)                            \
>  DEF_HELPER_2(float_ ## op ## l_s, i64, env, i32) \
>  DEF_HELPER_2(float_ ## op ## l_d, i64, env, i64) \
> diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
> index 34e9823..fd2cfb9 100644
> --- a/target-mips/op_helper.c
> +++ b/target-mips/op_helper.c
> @@ -2787,6 +2787,114 @@ 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_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
> +
> +uint32_t helper_float_rint_s(CPUMIPSState *env, uint32_t fs)
> +{
> +    uint32_t fd;
> +
> +    fd = float32_round_to_int(fs, &env->active_fpu.fp_status);
> +    update_fcr31(env, GETPC());
> +    return fd;
> +}
> +
> +uint64_t helper_float_rint_d(CPUMIPSState *env, uint64_t fs)
> +{
> +    uint64_t fd;
> +
 +    fd = float64_round_to_int(fs, &env->active_fpu.fp_status);
> +    update_fcr31(env, GETPC());
> +    return fd;
> +}
> +
> +
>  /* 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 a3cbe48..a686b4a 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -7601,14 +7601,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),
> @@ -7647,14 +7658,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),
> @@ -7910,6 +7932,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);
> +        return;
> +    }
> +
> +    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_NE, fp0, fp1, t1, t1, fp2);
> +        break;
> +    case OPC_SELNEZ_D:
> +        tcg_gen_andi_i64(fp1, fp1, 1);
> +        tcg_gen_movcond_i64(TCG_COND_EQ, fp0, fp1, t1, t1, fp2);
> +        break;
> +    default:
> +        MIPS_INVAL("gen_sel_d");
> +        generate_exception (ctx, EXCP_RI);
> +        return;
> +    }
> +
> +    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)
> @@ -8158,6 +8253,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);
> @@ -8221,59 +8331,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);
> +    break;
> +    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_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";
> +        }
> +    break;
> +    case OPC_RINT_S:
> +        check_insn(ctx, ISA_MIPS32R6);
>          {
>              TCGv_i32 fp0 = tcg_temp_new_i32();
> -
>              gen_load_fpr32(fp0, fs);
> -            gen_helper_float_recip1_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 = "recip1.s";
> -        break;
> -    case OPC_RSQRT1_S:
> -        check_cp1_64bitmode(ctx);
> +    break;
> +    case OPC_CLASS_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_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";
>          }
> -        opn = "rsqrt1.s";
>          break;
> -    case OPC_RSQRT2_S:
> -        check_cp1_64bitmode(ctx);
> -        {
> +    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);
> @@ -8572,6 +8798,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);
> @@ -8635,59 +8876,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);
> +    break;
> +    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_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";
> +        }
> +    break;
> +    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_rint_d(fp0, cpu_env, fp0);
>              gen_store_fpr64(ctx, fp0, fd);
>              tcg_temp_free_i64(fp0);
> +            opn = "rint.d";
>          }
> -        opn = "recip1.d";
> -        break;
> -    case OPC_RSQRT1_D:
> -        check_cp1_64bitmode(ctx);
> +    break;
> +    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_rsqrt1_d(fp0, cpu_env, fp0);
> +            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";
>          }
> -        opn = "rsqrt1.d";
>          break;
> -    case OPC_RSQRT2_D:
> -        check_cp1_64bitmode(ctx);
> -        {
> +    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.s";
> +        } 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:
> -- 
> 1.7.5.4
> 
> 

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 17/22] target-mips: add new Floating Point Comparison instructions
  2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 17/22] target-mips: add new Floating Point Comparison instructions Leon Alrae
@ 2014-06-20 21:36   ` Aurelien Jarno
  0 siblings, 0 replies; 50+ messages in thread
From: Aurelien Jarno @ 2014-06-20 21:36 UTC (permalink / raw)
  To: Leon Alrae; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On Wed, Jun 11, 2014 at 04:19:47PM +0100, Leon Alrae wrote:
> 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>
> ---
>  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 6196d2e..dd2473e 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 8bb3af7..8af957f 100644
> --- a/target-mips/helper.h
> +++ b/target-mips/helper.h
> @@ -305,6 +305,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 fd2cfb9..4cd63d1 100644
> --- a/target-mips/op_helper.c
> +++ b/target-mips/op_helper.c
> @@ -3370,3 +3370,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 a686b4a..4c75006 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -1619,6 +1619,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
>  
> @@ -7746,6 +7838,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";
> @@ -17026,11 +17165,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);

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                 http://www.aurel32.net

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

* Re: [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions
  2014-06-20 20:50   ` Aurelien Jarno
@ 2014-06-24  9:50     ` Leon Alrae
  2014-06-24 10:00       ` Peter Maydell
  0 siblings, 1 reply; 50+ messages in thread
From: Leon Alrae @ 2014-06-24  9:50 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On 20/06/2014 21:50, Aurelien Jarno wrote:
> The patch subject is a bit misleading, as it also includes the AUI family.

Thanks for pointing this out.

>> +#if defined(TARGET_MIPS64)
>> +        case R6_OPC_LDPC: /* bits 18 and 19 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 = (((int32_t)ctx->opcode << 14)) >> 11;
> 
> This will overflow the 32-bits type. I guess you want:
> 
>                offset = (((int32_t)ctx->opcode << 13)) >> 10;

I think original code is correct (LDPC offset's size is 18 bits so it
won't overflow). However, I just noticed that the comment is misleading
(there should be 'bits 16 and 17' instead of 'bits 18 and 19').

> I do wonder if we shouldn't use sextract32() instead of open coding that
> now that it is available:
> 
>                offset = sextract32(ctx->opcode, 0, 19) << 3;

This looks better, thanks for the suggestion (but since the offset's
size is 18, third argument will be 18, not 19).

>> +            addr = addr_add(ctx, (ctx->pc & ~0x7), offset);
> 
> Why do we need to mask the low 3 bits of the PC? It doesn't appear in
> the manual version I have (MD00087 version 6.00).


It doesn't appear in LDPC pseudo-code, but few lines below there is a
restriction: "LDPC is naturally aligned, by specification".
For load doubleword we need to make the address aligned to 8-byte boundary.

You can also refer to MIPS64 Volume-I (MD00083 version 6.01):
5.1.3.1 PC relative loads (Release 6)
"LDPC: Loads a 64-bit doubleword from a PC relative address, formed by
adding the PC, aligned to 8-bytes by masking off the low 3 bits, to a
sign-extended 18-bit immediate, shifted left by 3 bits, for a 21-bit span."

>> +#if defined(TARGET_MIPS64)
>> +        case OPC_DAHI:
>> +            check_insn(ctx, ISA_MIPS32R6);
>> +            check_mips_64(ctx);
>> +            if (rs != 0) {
>> +                tcg_gen_addi_i64(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 32);
> 
> Small nitpicking: even if it is guarded by #ifdef, in theory the _tl
> type should be used there, to match the register type.

I'll correct it.

Thanks,
Leon

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

* Re: [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions
  2014-06-24  9:50     ` Leon Alrae
@ 2014-06-24 10:00       ` Peter Maydell
  2014-06-24 14:24         ` Richard Henderson
  0 siblings, 1 reply; 50+ messages in thread
From: Peter Maydell @ 2014-06-24 10:00 UTC (permalink / raw)
  To: Leon Alrae
  Cc: yongbok.kim, cristian.cuna, QEMU Developers, Aurelien Jarno,
	Richard Henderson

On 24 June 2014 10:50, Leon Alrae <leon.alrae@imgtec.com> wrote:
> On 20/06/2014 21:50, Aurelien Jarno wrote:
>> I do wonder if we shouldn't use sextract32() instead of open coding that
>> now that it is available:
>>
>>                offset = sextract32(ctx->opcode, 0, 19) << 3;
>
> This looks better, thanks for the suggestion (but since the offset's
> size is 18, third argument will be 18, not 19).

This is undefined behaviour in C because of the shift into
the sign bit. Better to shift first and then signextend:

    offset = sextract32(ctx->opcode << 3, 0, 21);

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 22/22] target-mips: define a new generic CPU supporting MIPS64R6
  2014-06-19 22:16   ` Aurelien Jarno
@ 2014-06-24 11:56     ` Leon Alrae
  0 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-24 11:56 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On 19/06/2014 23:16, Aurelien Jarno wrote:
> On Wed, Jun 11, 2014 at 04:19:52PM +0100, Leon Alrae wrote:
>> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
>> ---
>>  target-mips/translate_init.c |   29 +++++++++++++++++++++++++++++
>>  1 files changed, 29 insertions(+), 0 deletions(-)
>>
>> diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
>> index 29dc2ef..0adbb19 100644
>> --- a/target-mips/translate_init.c
>> +++ b/target-mips/translate_init.c
>> @@ -516,6 +516,35 @@ static const mips_def_t mips_defs[] =
>>          .mmu_type = MMU_TYPE_R4000,
>>      },
>>      {
>> +        /* A generic CPU providing MIPS64 Release 6 features.
>> +           FIXME: 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*/
> 
> Sorry to say that again, but I think it should be deferred to the point
> where the MIPS R6 CPU is fully functional, so probably after the
> "implement features required in MIPS64 Release 6", and probably even
> more, as I haven't seen any patch concerning the unaligned access
> support yet.

It will take some time before MIPS R6 CPU becomes fully functional. With
the current patchset QEMU should be able to run R6 binaries in userland
emulation mode where we don't care about KScratch, TLBINV etc. Thus I
think having available MIPS R6 CPU might be handy at this point (even
though there are limitations regarding unaligned access or forbidden
slot support).

Regards,
Leon

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

* Re: [Qemu-devel] [PATCH v2 16/22] target-mips: add new Floating Point instructions
  2014-06-20 21:14   ` Aurelien Jarno
@ 2014-06-24 12:10     ` Leon Alrae
  0 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-24 12:10 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: yongbok.kim, cristian.cuna, qemu-devel, rth

On 20/06/2014 22:14, Aurelien Jarno wrote:
>> 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.
> 
> I don't think we can "update" softfloat. The existing version has to
> stay to correctly emulate the existing CPU, and unfortunately things like
> the sNaN bit is not even configurable at runtime, but fixed at compile time
> (in softfloat-specialize.h). How do you plan to handle that?

I'm aware of this. By "update" softfloat I meant making it configurable
at runtime for MIPS depending on FIR.HAS2008, FCSR.NAN2008 and
FCSR.ABS2008 flags, so legacy MIPS FPU will be still available for
existing CPUs.

>> +DEF_HELPER_1(float_class_s, i32, i32)
>> +DEF_HELPER_1(float_class_d, i64, i64)
>> +
>> +DEF_HELPER_2(float_rint_s, i32, env, i32)
>> +DEF_HELPER_2(float_rint_d, i64, env, i64)
>> +
>> +DEF_HELPER_4(float_maddf_s, i32, env, i32, i32, i32)
>> +DEF_HELPER_4(float_maddf_d, i64, env, i64, i64, i64)
>> +
>> +DEF_HELPER_4(float_msubf_s, i32, env, i32, i32, i32)
>> +DEF_HELPER_4(float_msubf_d, i64, env, i64, i64, i64)
>> +
> 
> Why not using FOP_PROTO here?
> 

I'll correct it.

Thanks,
Leon

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

* Re: [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches
  2014-06-11 16:52   ` Richard Henderson
@ 2014-06-24 14:03     ` Leon Alrae
  0 siblings, 0 replies; 50+ messages in thread
From: Leon Alrae @ 2014-06-24 14:03 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: yongbok.kim, cristian.cuna, aurelien

On 11/06/2014 17:52, Richard Henderson wrote:
> On 06/11/2014 08:19 AM, Leon Alrae wrote:
>> +        case OPC_BEQZC:
>> +            tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, t0, 0);
>> +            break;
> ...
>> +    /* Compact branches don't have delay slot, thus generating branch here */
>> +    /* TODO: implement forbidden slot */
>> +    gen_branch(ctx, 4);
> 
> This is not what I meant by generating a branch directly.
> 
> I meant generating
> 
>   tcg_gen_brcondi(TCG_COND_EQ, t0, 0, label)
> 
> instead of computing setcond into bcond and then branching off a comparison
> against bcond.

Ah, now I see.

> Consider creating some sort of structure that defines a condition for the
> translator, much like target-s390x does with struct DisasCompare or target-i386
> does with struct CCPrepare.
> 
> That lets "old" branches set up a condition based off bcond, and your new
> branches set up a condition based off the general registers (or brand new temps
> in the case of BOVC/BNVC).
> 
> The ability to select the TCG compare op also allows you to avoid things like
> the xor at the end of your BNVC computation.

My understanding is that this is a nice to have MIPS branch improvement
that can come later? I would prefer to avoid mixing this new work (which
also affects pre-R6 branches) into the current patchset. So I'm going
just to use tcg_gen_brcond in compact conditional branches directly as
you suggested initially.

Thanks,
Leon

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

* Re: [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions
  2014-06-24 10:00       ` Peter Maydell
@ 2014-06-24 14:24         ` Richard Henderson
  2014-06-24 14:54           ` Peter Maydell
  0 siblings, 1 reply; 50+ messages in thread
From: Richard Henderson @ 2014-06-24 14:24 UTC (permalink / raw)
  To: Peter Maydell, Leon Alrae
  Cc: yongbok.kim, cristian.cuna, QEMU Developers, Aurelien Jarno

On 06/24/2014 03:00 AM, Peter Maydell wrote:
> On 24 June 2014 10:50, Leon Alrae <leon.alrae@imgtec.com> wrote:
>> On 20/06/2014 21:50, Aurelien Jarno wrote:
>>> I do wonder if we shouldn't use sextract32() instead of open coding that
>>> now that it is available:
>>>
>>>                offset = sextract32(ctx->opcode, 0, 19) << 3;
>>
>> This looks better, thanks for the suggestion (but since the offset's
>> size is 18, third argument will be 18, not 19).
> 
> This is undefined behaviour in C because of the shift into
> the sign bit. Better to shift first and then signextend:
> 
>     offset = sextract32(ctx->opcode << 3, 0, 21);

Not true.  Because we know from the extract that the value has 13 copies of the
sign bit.  Shifting by 3 isn't going to cause problems.  It's shifting a
*different* bit into the sign position that's (one's compliment) undefined.


r~

PS: Honestly, all these compilers/sanitizers should grow a "No One's
Compliment" switch to disable all the stupid stuff.

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

* Re: [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions
  2014-06-24 14:24         ` Richard Henderson
@ 2014-06-24 14:54           ` Peter Maydell
  0 siblings, 0 replies; 50+ messages in thread
From: Peter Maydell @ 2014-06-24 14:54 UTC (permalink / raw)
  To: Richard Henderson
  Cc: yongbok.kim, cristian.cuna, Leon Alrae, QEMU Developers, Aurelien Jarno

On 24 June 2014 15:24, Richard Henderson <rth@twiddle.net> wrote:
> On 06/24/2014 03:00 AM, Peter Maydell wrote:
>> This is undefined behaviour in C because of the shift into
>> the sign bit. Better to shift first and then signextend:
>>
>>     offset = sextract32(ctx->opcode << 3, 0, 21);
>
> Not true.  Because we know from the extract that the value has
> 13 copies of the sign bit.  Shifting by 3 isn't going to cause
> problems.  It's shifting a *different* bit into the sign position
> that's (one's compliment) undefined.

C99 6.5.7 says that for E1 << E2, "If E1 has a signed type
and nonnegative value, and E1 * 2^E2 is representable in
the result type, then that is the resulting value; otherwise,
the behavior is undefined." As I read that, shifting
any negative value is undefined, as well as shifting
a 1 into the sign bit.

> PS: Honestly, all these compilers/sanitizers should grow a "No One's
> Compliment" switch to disable all the stupid stuff.

Heartily agreed. Unfortunately until they do, I don't trust
the compiler not to decide it can be fantastically clever
and speed up specmark by 0.00003% if it breaks the 2s
complement behaviour for signed shifts.

thanks
-- PMM

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

end of thread, other threads:[~2014-06-24 14:55 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-11 15:19 [Qemu-devel] [PATCH v2 00/22] target-mips: add MIPS64R6 Instruction Set support Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 01/22] target-mips: define ISA_MIPS64R6 Leon Alrae
2014-06-19 21:06   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 02/22] target-mips: signal RI Exception on instructions removed in R6 Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 03/22] target-mips: add SELEQZ and SELNEZ instructions Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 04/22] target-mips: move LL and SC instructions Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 05/22] target-mips: extract decode_opc_special* from decode_opc Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 06/22] target-mips: split decode_opc_special* into *_r6 and *_legacy Leon Alrae
2014-06-19 21:06   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 07/22] target-mips: signal RI Exception on DSP and Loongson instructions Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 08/22] target-mips: move PREF, CACHE, LLD and SCD instructions Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 09/22] target-mips: redefine Integer Multiply and Divide instructions Leon Alrae
2014-06-19 21:06   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 10/22] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6 Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 11/22] target-mips: Status.UX/SX/KX enable 32-bit address wrapping Leon Alrae
2014-06-19 21:06   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions Leon Alrae
2014-06-11 16:39   ` Richard Henderson
2014-06-12  8:35     ` Leon Alrae
2014-06-12 14:34       ` Richard Henderson
2014-06-19 21:06   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches Leon Alrae
2014-06-11 16:52   ` Richard Henderson
2014-06-24 14:03     ` Leon Alrae
2014-06-19 21:06   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions Leon Alrae
2014-06-20 20:50   ` Aurelien Jarno
2014-06-24  9:50     ` Leon Alrae
2014-06-24 10:00       ` Peter Maydell
2014-06-24 14:24         ` Richard Henderson
2014-06-24 14:54           ` Peter Maydell
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 15/22] softfloat: add functions corresponding to IEEE-2008 min/maxNumMag Leon Alrae
2014-06-19 21:27   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 16/22] target-mips: add new Floating Point instructions Leon Alrae
2014-06-20 21:14   ` Aurelien Jarno
2014-06-24 12:10     ` Leon Alrae
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 17/22] target-mips: add new Floating Point Comparison instructions Leon Alrae
2014-06-20 21:36   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 18/22] target-mips: do not allow Status.FR=0 mode in 64-bit FPU Leon Alrae
2014-06-19 21:27   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 19/22] target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions Leon Alrae
2014-06-19 22:22   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 20/22] mips_malta: update malta's pseudo-bootloader - replace JR with JALR Leon Alrae
2014-06-19 21:27   ` Aurelien Jarno
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 21/22] target-mips: use pointers referring to appropriate decoding function Leon Alrae
2014-06-19 22:18   ` Aurelien Jarno
2014-06-20  4:09     ` Richard Henderson
2014-06-11 15:19 ` [Qemu-devel] [PATCH v2 22/22] target-mips: define a new generic CPU supporting MIPS64R6 Leon Alrae
2014-06-19 22:16   ` Aurelien Jarno
2014-06-24 11:56     ` Leon Alrae

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