This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Update mtfsf and mtfsfi instructions to support new optional operands.


The following patch adds support for new optional operands (as of POWER6)
on the mtfsf and mtfsfi instructions.  The mtfsf change was a little more
difficult, since we added two extra optional operands, so the accepted
form has either 2 operands or 4, but not three.  This lead me to invent
the PPC_OPERAND_OPTIONAL_GROUP hackery used below, so we either omit both
optional operands or print them both.  I also fixed a smallish disassembly
bug for the mtfsfi instruction, where we were printing crN for the BF
operand which happens to correspond to the FPSCR in this instruction and
not the condition registers.

Peter


include/opcode/
	* ppc.h (PPC_OPERAND_OPTIONAL_GROUP): Define.  Bump other operand defines.
opcodes/
	* ppc-dis.c (operand_value_powerpc, operand_is_optional_powerpc): New.
	(print_insn_powerpc): Use the new operand_value_powerpc and
	operand_is_optional_powerpc functions to handle grouped optional
	operands.
	* ppc-opc.c (BFF, W, XFL_L, XFL_W, XWRA_MASK): New.
	(XFL_MASK): Delete L and W bits from the mask.
	(mtfsfi, mtfsfi.): Replace use of BF with BFF.  Relpace use of XRA_MASK
	with XWRA_MASK.  Use W.
	(mtfsf, mtfsf.): Use XFL_L and XFL_W.

Index: ppc.h
===================================================================
RCS file: /cvs/src/src/include/opcode/ppc.h,v
retrieving revision 1.25
diff -u -p -r1.25 ppc.h
--- ppc.h	2 May 2007 11:24:17 -0000	1.25
+++ ppc.h	15 May 2007 20:53:42 -0000
@@ -269,33 +269,40 @@ extern const unsigned int num_powerpc_op
    print this operand out only if it is not zero.  */
 #define PPC_OPERAND_OPTIONAL (0x400)
 
+/* This flag is only used with PPC_OPERAND_OPTIONAL.  This flag is
+   used to group a set of consecutive optional operands together,
+   such that they are all omitted or printed as a group.  To be
+   omitted, all of their values must be zero, otherwise they are
+   all printed.  */
+#define PPC_OPERAND_OPTIONAL_GROUP (0x800)
+
 /* This flag is only used with PPC_OPERAND_OPTIONAL.  If this operand
    is omitted, then for the next operand use this operand value plus
    1, ignoring the next operand field for the opcode.  This wretched
    hack is needed because the Power rotate instructions can take
    either 4 or 5 operands.  The disassembler should print this operand
    out regardless of the PPC_OPERAND_OPTIONAL field.  */
-#define PPC_OPERAND_NEXT (0x800)
+#define PPC_OPERAND_NEXT (0x1000)
 
 /* This operand should be regarded as a negative number for the
    purposes of overflow checking (i.e., the normal most negative
    number is disallowed and one more than the normal most positive
    number is allowed).  This flag will only be set for a signed
    operand.  */
-#define PPC_OPERAND_NEGATIVE (0x1000)
+#define PPC_OPERAND_NEGATIVE (0x2000)
 
 /* This operand names a vector unit register.  The disassembler
    prints these with a leading 'v'.  */
-#define PPC_OPERAND_VR (0x2000)
+#define PPC_OPERAND_VR (0x4000)
 
 /* This operand is for the DS field in a DS form instruction.  */
-#define PPC_OPERAND_DS (0x4000)
+#define PPC_OPERAND_DS (0x8000)
 
 /* This operand is for the DQ field in a DQ form instruction.  */
-#define PPC_OPERAND_DQ (0x8000)
+#define PPC_OPERAND_DQ (0x10000)
 
 /* Valid range of operand is 0..n rather than 0..n-1.  */
-#define PPC_OPERAND_PLUS1 (0x10000)
+#define PPC_OPERAND_PLUS1 (0x20000)
 
 /* The POWER and PowerPC assemblers use a few macros.  We keep them
    with the operands table for simplicity.  The macro table is an
Index: ppc-dis.c
===================================================================
RCS file: /cvs/src/src/opcodes/ppc-dis.c,v
retrieving revision 1.26
diff -u -p -r1.26 ppc-dis.c
--- ppc-dis.c	20 Apr 2007 12:25:12 -0000	1.26
+++ ppc-dis.c	15 May 2007 20:54:08 -0000
@@ -20,6 +20,7 @@ along with this file; see the file COPYI
 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include <stdio.h>
+#include <assert.h>
 #include "sysdep.h"
 #include "dis-asm.h"
 #include "opcode/ppc.h"
@@ -127,6 +128,72 @@ print_insn_rs6000 (bfd_vma memaddr, stru
   return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
 }
 
+/* Extract the operand value from the PowerPC or POWER instruction.  */
+
+static long
+operand_value_powerpc (const struct powerpc_operand *operand,
+		       unsigned long insn, int dialect)
+{
+  long value;
+  int invalid;
+  /* Extract the value from the instruction.  */
+  if (operand->extract)
+    value = (*operand->extract) (insn, dialect, &invalid);
+  else
+    {
+      value = (insn >> operand->shift) & operand->bitm;
+      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+	{
+	  /* BITM is always some number of zeros followed by some
+	     number of ones, followed by some numer of zeros.  */
+	  unsigned long top = operand->bitm;
+	  /* top & -top gives the rightmost 1 bit, so this
+	     fills in any trailing zeros.  */
+	  top |= (top & -top) - 1;
+	  top &= ~(top >> 1);
+	  value = (value ^ top) - top;
+	}
+    }
+  return value;
+}
+
+/* Determine whether the current operand(s) should be printed.  */
+
+static int
+operand_is_optional_powerpc (const struct powerpc_operand *operand,
+			     const unsigned char *opindex,
+			     unsigned long insn, int dialect,
+			     int *operand_cnt)
+{
+  long value;
+
+  assert (*operand_cnt <= 0);
+
+  if ((operand->flags & PPC_OPERAND_OPTIONAL) == 0
+      || (operand->flags & PPC_OPERAND_NEXT) != 0)
+    return 0;
+
+  value = operand_value_powerpc (operand, insn, dialect);
+
+  if ((operand->flags & PPC_OPERAND_OPTIONAL_GROUP) == 0)
+    return value == 0;
+
+  /* We are at the start of an optional operand group, so scan the optional
+     group operands following this one computing up their group value.  If the
+     group value is zero, all are omitted.  Otherwise, all are printed.  */
+  *operand_cnt = 0;
+  for (opindex = opindex + 1; *opindex != 0; opindex++)
+    {
+      operand = powerpc_operands + *opindex;
+      if ((operand->flags & PPC_OPERAND_OPTIONAL_GROUP) == 0)
+	break;
+      *operand_cnt += 1;
+      value |= operand_value_powerpc (operand, insn, dialect);
+    }
+
+  return value == 0;
+}
+
 /* Print a PowerPC or POWER instruction.  */
 
 static int
@@ -172,6 +239,8 @@ print_insn_powerpc (bfd_vma memaddr,
       int invalid;
       int need_comma;
       int need_paren;
+      int is_optional;
+      int operand_cnt;
 
       table_op = PPC_OP (opcode->opcode);
       if (op < table_op)
@@ -205,6 +274,8 @@ print_insn_powerpc (bfd_vma memaddr,
       /* Now extract and print the operands.  */
       need_comma = 0;
       need_paren = 0;
+      is_optional = 0;
+      operand_cnt = 0;
       for (opindex = opcode->operands; *opindex != 0; opindex++)
 	{
 	  long value;
@@ -217,32 +288,16 @@ print_insn_powerpc (bfd_vma memaddr,
 	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
 	    continue;
 
-	  /* Extract the value from the instruction.  */
-	  if (operand->extract)
-	    value = (*operand->extract) (insn, dialect, &invalid);
-	  else
-	    {
-	      value = (insn >> operand->shift) & operand->bitm;
-	      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
-		{
-		  /* BITM is always some number of zeros followed by some
-		     number of ones, followed by some numer of zeros.  */
-		  unsigned long top = operand->bitm;
-		  /* top & -top gives the rightmost 1 bit, so this
-		     fills in any trailing zeros.  */
-		  top |= (top & -top) - 1;
-		  top &= ~(top >> 1);
-		  value = (value ^ top) - top;
-		}
-	    }
-
 	  /* If the operand is optional, and the value is zero, don't
 	     print anything.  */
-	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
-	      && (operand->flags & PPC_OPERAND_NEXT) == 0
-	      && value == 0)
+	  if (operand_cnt-- <= 0)
+	    is_optional = operand_is_optional_powerpc (operand, opindex, insn,
+						       dialect, &operand_cnt);
+	  if (is_optional)
 	    continue;
 
+	  value = operand_value_powerpc (operand, insn, dialect);
+
 	  if (need_comma)
 	    {
 	      (*info->fprintf_func) (info->stream, ",");
Index: ppc-opc.c
===================================================================
RCS file: /cvs/src/src/opcodes/ppc-opc.c,v
retrieving revision 1.95
diff -u -p -r1.95 ppc-opc.c
--- ppc-opc.c	30 Apr 2007 00:27:57 -0000	1.95
+++ ppc-opc.c	15 May 2007 20:54:09 -0000
@@ -154,9 +154,13 @@ const struct powerpc_operand powerpc_ope
 #define CRFD BF
   { 0x7, 23, NULL, NULL, PPC_OPERAND_CR },
 
+  /* The BF field in an X or XL form instruction.  */
+#define BFF BF + 1
+  { 0x7, 23, NULL, NULL, 0 },
+
   /* An optional BF field.  This is used for comparison instructions,
      in which an omitted BF field is taken as zero.  */
-#define OBF BF + 1
+#define OBF BFF + 1
   { 0x7, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
 
   /* The BFA field in an X or XL form instruction.  */
@@ -515,8 +519,9 @@ const struct powerpc_operand powerpc_ope
 #define WS EVUIMM_8 + 1
   { 0x7, 11, NULL, NULL, 0 },
 
-  /* The L field in an mtmsrd or A form instruction.  */
+  /* The L field in an mtmsrd or A form instruction or W in an X form.  */
 #define A_L WS + 1
+#define W A_L
   { 0x1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
 #define RMC A_L + 1
@@ -541,6 +546,14 @@ const struct powerpc_operand powerpc_ope
   /* The EH field in larx instruction.  */
 #define EH SH16 + 1
   { 0x1, 0, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The L field in an mtfsf or XFL form instruction.  */
+#define XFL_L EH + 1
+  { 0x1, 25, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_OPTIONAL_GROUP},
+
+  /* The W field in an mtfsf instruction.  */
+#define XFL_W XFL_L + 1
+  { 0x1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_OPTIONAL_GROUP},
 };
 
 const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
@@ -1400,6 +1413,9 @@ extract_tbr (unsigned long insn,
 /* An X_MASK with the RA field fixed.  */
 #define XRA_MASK (X_MASK | RA_MASK)
 
+/* An XRA_MASK with the W field clear.  */
+#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16))
+
 /* An X_MASK with the RB field fixed.  */
 #define XRB_MASK (X_MASK | RB_MASK)
 
@@ -1454,7 +1470,7 @@ extract_tbr (unsigned long insn,
 
 /* An XFL form instruction.  */
 #define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1))
-#define XFL_MASK (XFL (0x3f, 0x3ff, 1) | (((unsigned long)1) << 25) | (((unsigned long)1) << 16))
+#define XFL_MASK XFL (0x3f, 0x3ff, 1)
 
 /* An X form isel instruction.  */
 #define XISEL(op, xop)  (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1))
@@ -4586,8 +4602,8 @@ const struct powerpc_opcode powerpc_opco
 
 { "dcmpoq",  X(63,130),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
 
-{ "mtfsfi",  XRC(63,134,0), XRA_MASK|(3<<21)|(1<<11), COM, { BF, U } },
-{ "mtfsfi.", XRC(63,134,1), XRA_MASK|(3<<21)|(1<<11), COM, { BF, U } },
+{ "mtfsfi",  XRC(63,134,0), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } },
+{ "mtfsfi.", XRC(63,134,1), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } },
 
 { "fnabs",   XRC(63,136,0), XRA_MASK,	COM,		{ FRT, FRB } },
 { "fnabs.",  XRC(63,136,1), XRA_MASK,	COM,		{ FRT, FRB } },
@@ -4636,8 +4652,8 @@ const struct powerpc_opcode powerpc_opco
 
 { "dtstsfq", X(63,674),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
 
-{ "mtfsf",   XFL(63,711,0), XFL_MASK,	COM,		{ FLM, FRB } },
-{ "mtfsf.",  XFL(63,711,1), XFL_MASK,	COM,		{ FLM, FRB } },
+{ "mtfsf",   XFL(63,711,0), XFL_MASK,	COM,		{ FLM, FRB, XFL_L, XFL_W } },
+{ "mtfsf.",  XFL(63,711,1), XFL_MASK,	COM,		{ FLM, FRB, XFL_L, XFL_W } },
 
 { "drdpq",   XRC(63,770,0), X_MASK,	POWER6,		{ FRT, FRB } },
 { "drdpq.",  XRC(63,770,1), X_MASK,	POWER6,		{ FRT, FRB } },


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]