File: /usr/src/linux/arch/ppc/xmon/ppc-dis.c

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