[POWERPC] Make xmon disassembly optional
[powerpc.git] / arch / powerpc / xmon / ppc-dis.c
1 /* ppc-dis.c -- Disassemble PowerPC instructions
2    Copyright 1994 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Cygnus Support
4
5 This file is part of GDB, GAS, and the GNU binutils.
6
7 GDB, GAS, and the GNU binutils are free software; you can redistribute
8 them and/or modify them under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either version
10 2, or (at your option) any later version.
11
12 GDB, GAS, and the GNU binutils are distributed in the hope that they
13 will be useful, but WITHOUT ANY WARRANTY; without even the implied
14 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15 the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "nonstdio.h"
22 #include "ansidecl.h"
23 #include "ppc.h"
24 #include "dis-asm.h"
25
26 /* Print a PowerPC or POWER instruction.  */
27
28 int
29 print_insn_powerpc (unsigned long insn, unsigned long memaddr)
30 {
31   const struct powerpc_opcode *opcode;
32   const struct powerpc_opcode *opcode_end;
33   unsigned long op;
34   int dialect;
35
36   dialect = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON
37               | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
38
39   /* Get the major opcode of the instruction.  */
40   op = PPC_OP (insn);
41
42   /* Find the first match in the opcode table.  We could speed this up
43      a bit by doing a binary search on the major opcode.  */
44   opcode_end = powerpc_opcodes + powerpc_num_opcodes;
45  again:
46   for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
47     {
48       unsigned long table_op;
49       const unsigned char *opindex;
50       const struct powerpc_operand *operand;
51       int invalid;
52       int need_comma;
53       int need_paren;
54
55       table_op = PPC_OP (opcode->opcode);
56       if (op < table_op)
57         break;
58       if (op > table_op)
59         continue;
60
61       if ((insn & opcode->mask) != opcode->opcode
62           || (opcode->flags & dialect) == 0)
63         continue;
64
65       /* Make two passes over the operands.  First see if any of them
66          have extraction functions, and, if they do, make sure the
67          instruction is valid.  */
68       invalid = 0;
69       for (opindex = opcode->operands; *opindex != 0; opindex++)
70         {
71           operand = powerpc_operands + *opindex;
72           if (operand->extract)
73             (*operand->extract) (insn, dialect, &invalid);
74         }
75       if (invalid)
76         continue;
77
78       /* The instruction is valid.  */
79       printf("%s", opcode->name);
80       if (opcode->operands[0] != 0)
81         printf("\t");
82
83       /* Now extract and print the operands.  */
84       need_comma = 0;
85       need_paren = 0;
86       for (opindex = opcode->operands; *opindex != 0; opindex++)
87         {
88           long value;
89
90           operand = powerpc_operands + *opindex;
91
92           /* Operands that are marked FAKE are simply ignored.  We
93              already made sure that the extract function considered
94              the instruction to be valid.  */
95           if ((operand->flags & PPC_OPERAND_FAKE) != 0)
96             continue;
97
98           /* Extract the value from the instruction.  */
99           if (operand->extract)
100             value = (*operand->extract) (insn, dialect, &invalid);
101           else
102             {
103               value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
104               if ((operand->flags & PPC_OPERAND_SIGNED) != 0
105                   && (value & (1 << (operand->bits - 1))) != 0)
106                 value -= 1 << operand->bits;
107             }
108
109           /* If the operand is optional, and the value is zero, don't
110              print anything.  */
111           if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
112               && (operand->flags & PPC_OPERAND_NEXT) == 0
113               && value == 0)
114             continue;
115
116           if (need_comma)
117             {
118               printf(",");
119               need_comma = 0;
120             }
121
122           /* Print the operand as directed by the flags.  */
123           if ((operand->flags & PPC_OPERAND_GPR) != 0)
124             printf("r%ld", value);
125           else if ((operand->flags & PPC_OPERAND_FPR) != 0)
126             printf("f%ld", value);
127           else if ((operand->flags & PPC_OPERAND_VR) != 0)
128             printf("v%ld", value);
129           else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
130             print_address (memaddr + value);
131           else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
132             print_address (value & 0xffffffff);
133           else if ((operand->flags & PPC_OPERAND_CR) == 0
134                    || (dialect & PPC_OPCODE_PPC) == 0)
135             printf("%ld", value);
136           else
137             {
138               if (operand->bits == 3)
139                 printf("cr%d", value);
140               else
141                 {
142                   static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
143                   int cr;
144                   int cc;
145
146                   cr = value >> 2;
147                   if (cr != 0)
148                     printf("4*cr%d+", cr);
149                   cc = value & 3;
150                   printf("%s", cbnames[cc]);
151                 }
152             }
153
154           if (need_paren)
155             {
156               printf(")");
157               need_paren = 0;
158             }
159
160           if ((operand->flags & PPC_OPERAND_PARENS) == 0)
161             need_comma = 1;
162           else
163             {
164               printf("(");
165               need_paren = 1;
166             }
167         }
168
169       /* We have found and printed an instruction; return.  */
170       return 4;
171     }
172
173   if ((dialect & PPC_OPCODE_ANY) != 0)
174     {
175       dialect = ~PPC_OPCODE_ANY;
176       goto again;
177     }
178
179   /* We could not find a match.  */
180   printf(".long 0x%lx", insn);
181
182   return 4;
183 }