This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH] Update mtfsf and mtfsfi instructions to support new optional operands.
On Wed, May 16, 2007 at 03:43:27PM +0930, Alan Modra wrote:
> I think we ought to be doing that for all instructions having more
> than one optional operand (tlbre, tlbwe). The disassembler should
> behave similarly to the assembler, ie. on seeing the first optional
> operand, scan over all remaining operands to see whether all optional
> operands can be omitted. Then print all of them, or skip all of
> them. So I don't think you need the new PPC_OPERAND_OPTIONAL_GROUP
> flag. (If we really do need PPC_OPERAND_OPTIONAL_GROUP some time in
> the future, then we also need an assembler change..)
[snip]
> In line with the above, I think we want one boolean saying that we
> have already tested optional operands (so don't do it again), and
> another saying to skip all optional operands. Or use one 3-value
> flag.
Something like this?
Peter
* ppc-dis.c (operand_value_powerpc, skip_optional_operands): New.
(print_insn_powerpc): Use the new operand_value_powerpc and
skip_optional_operands functions to omit or print all optional
operands as a group.
* ppc-opc.c (BFF, W, XFL_L, 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 W.
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 16 May 2007 20:31:21 -0000
@@ -127,6 +127,56 @@ 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 optional operand(s) should be printed. */
+
+static int
+skip_optional_operands (const unsigned char *opindex,
+ unsigned long insn, int dialect)
+{
+ const struct powerpc_operand *operand;
+
+ for (; *opindex != 0; opindex++)
+ {
+ operand = &powerpc_operands[*opindex];
+ if ((operand->flags & PPC_OPERAND_NEXT) != 0
+ || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+ && operand_value_powerpc (operand, insn, dialect) != 0))
+ return 0;
+ }
+
+ return 1;
+}
+
/* Print a PowerPC or POWER instruction. */
static int
@@ -172,6 +222,7 @@ print_insn_powerpc (bfd_vma memaddr,
int invalid;
int need_comma;
int need_paren;
+ int skip_optional;
table_op = PPC_OP (opcode->opcode);
if (op < table_op)
@@ -205,6 +256,7 @@ print_insn_powerpc (bfd_vma memaddr,
/* Now extract and print the operands. */
need_comma = 0;
need_paren = 0;
+ skip_optional = -1;
for (opindex = opcode->operands; *opindex != 0; opindex++)
{
long value;
@@ -217,32 +269,17 @@ 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 all of the optional operands have the value zero,
+ then don't print any of them. */
+ if (skip_optional < 0
+ && (operand->flags & PPC_OPERAND_OPTIONAL) != 0)
+ skip_optional = skip_optional_operands (opindex, insn, dialect);
- /* 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 (skip_optional > 0)
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 16 May 2007 20:31:22 -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,10 @@ 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},
};
const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
@@ -1400,6 +1409,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 +1466,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 +4598,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 +4648,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, W } },
+{ "mtfsf.", XFL(63,711,1), XFL_MASK, COM, { FLM, FRB, XFL_L, W } },
{ "drdpq", XRC(63,770,0), X_MASK, POWER6, { FRT, FRB } },
{ "drdpq.", XRC(63,770,1), X_MASK, POWER6, { FRT, FRB } },