OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [opcodes/] [ppc-dis.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/* ppc-dis.c -- Disassemble PowerPC instructions
2
   Copyright 1994, 1995, 2000 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 <stdio.h>
22
#include "sysdep.h"
23
#include "dis-asm.h"
24
#include "opcode/ppc.h"
25
 
26
/* This file provides several disassembler functions, all of which use
27
   the disassembler interface defined in dis-asm.h.  Several functions
28
   are provided because this file handles disassembly for the PowerPC
29
   in both big and little endian mode and also for the POWER (RS/6000)
30
   chip.  */
31
 
32
static int print_insn_powerpc PARAMS ((bfd_vma, struct disassemble_info *,
33
                                       int bigendian, int dialect));
34
 
35
/* Print a big endian PowerPC instruction.  For convenience, also
36
   disassemble instructions supported by the Motorola PowerPC 601
37
   and the Altivec vector unit.  */
38
 
39
int
40
print_insn_big_powerpc (memaddr, info)
41
     bfd_vma memaddr;
42
     struct disassemble_info *info;
43
{
44
  return print_insn_powerpc (memaddr, info, 1,
45
                             PPC_OPCODE_PPC | PPC_OPCODE_601 |
46
                             PPC_OPCODE_ALTIVEC);
47
}
48
 
49
/* Print a little endian PowerPC instruction.  For convenience, also
50
   disassemble instructions supported by the Motorola PowerPC 601
51
   and the Altivec vector unit.  */
52
 
53
int
54
print_insn_little_powerpc (memaddr, info)
55
     bfd_vma memaddr;
56
     struct disassemble_info *info;
57
{
58
  return print_insn_powerpc (memaddr, info, 0,
59
                             PPC_OPCODE_PPC | PPC_OPCODE_601 |
60
                             PPC_OPCODE_ALTIVEC);
61
}
62
 
63
/* Print a POWER (RS/6000) instruction.  */
64
 
65
int
66
print_insn_rs6000 (memaddr, info)
67
     bfd_vma memaddr;
68
     struct disassemble_info *info;
69
{
70
  return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
71
}
72
 
73
/* Print a PowerPC or POWER instruction.  */
74
 
75
static int
76
print_insn_powerpc (memaddr, info, bigendian, dialect)
77
     bfd_vma memaddr;
78
     struct disassemble_info *info;
79
     int bigendian;
80
     int dialect;
81
{
82
  bfd_byte buffer[4];
83
  int status;
84
  unsigned long insn;
85
  const struct powerpc_opcode *opcode;
86
  const struct powerpc_opcode *opcode_end;
87
  unsigned long op;
88
 
89
  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
90
  if (status != 0)
91
    {
92
      (*info->memory_error_func) (status, memaddr, info);
93
      return -1;
94
    }
95
 
96
  if (bigendian)
97
    insn = bfd_getb32 (buffer);
98
  else
99
    insn = bfd_getl32 (buffer);
100
 
101
  /* Get the major opcode of the instruction.  */
102
  op = PPC_OP (insn);
103
 
104
  /* Find the first match in the opcode table.  We could speed this up
105
     a bit by doing a binary search on the major opcode.  */
106
  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
107
  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
108
    {
109
      unsigned long table_op;
110
      const unsigned char *opindex;
111
      const struct powerpc_operand *operand;
112
      int invalid;
113
      int need_comma;
114
      int need_paren;
115
 
116
      table_op = PPC_OP (opcode->opcode);
117
      if (op < table_op)
118
        break;
119
      if (op > table_op)
120
        continue;
121
 
122
      if ((insn & opcode->mask) != opcode->opcode
123
          || (opcode->flags & dialect) == 0)
124
        continue;
125
 
126
      /* Make two passes over the operands.  First see if any of them
127
         have extraction functions, and, if they do, make sure the
128
         instruction is valid.  */
129
      invalid = 0;
130
      for (opindex = opcode->operands; *opindex != 0; opindex++)
131
        {
132
          operand = powerpc_operands + *opindex;
133
          if (operand->extract)
134
            (*operand->extract) (insn, &invalid);
135
        }
136
      if (invalid)
137
        continue;
138
 
139
      /* The instruction is valid.  */
140
      (*info->fprintf_func) (info->stream, "%s", opcode->name);
141
      if (opcode->operands[0] != 0)
142
        (*info->fprintf_func) (info->stream, "\t");
143
 
144
      /* Now extract and print the operands.  */
145
      need_comma = 0;
146
      need_paren = 0;
147
      for (opindex = opcode->operands; *opindex != 0; opindex++)
148
        {
149
          long value;
150
 
151
          operand = powerpc_operands + *opindex;
152
 
153
          /* Operands that are marked FAKE are simply ignored.  We
154
             already made sure that the extract function considered
155
             the instruction to be valid.  */
156
          if ((operand->flags & PPC_OPERAND_FAKE) != 0)
157
            continue;
158
 
159
          /* Extract the value from the instruction.  */
160
          if (operand->extract)
161
            value = (*operand->extract) (insn, (int *) NULL);
162
          else
163
            {
164
              value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
165
              if ((operand->flags & PPC_OPERAND_SIGNED) != 0
166
                  && (value & (1 << (operand->bits - 1))) != 0)
167
                value -= 1 << operand->bits;
168
            }
169
 
170
          /* If the operand is optional, and the value is zero, don't
171
             print anything.  */
172
          if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
173
              && (operand->flags & PPC_OPERAND_NEXT) == 0
174
              && value == 0)
175
            continue;
176
 
177
          if (need_comma)
178
            {
179
              (*info->fprintf_func) (info->stream, ",");
180
              need_comma = 0;
181
            }
182
 
183
          /* Print the operand as directed by the flags.  */
184
          if ((operand->flags & PPC_OPERAND_GPR) != 0)
185
            (*info->fprintf_func) (info->stream, "r%ld", value);
186
          else if ((operand->flags & PPC_OPERAND_FPR) != 0)
187
            (*info->fprintf_func) (info->stream, "f%ld", value);
188
          else if ((operand->flags & PPC_OPERAND_VR) != 0)
189
            (*info->fprintf_func) (info->stream, "v%ld", value);
190
          else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
191
            (*info->print_address_func) (memaddr + value, info);
192
          else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
193
            (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
194
          else if ((operand->flags & PPC_OPERAND_CR) == 0
195
                   || (dialect & PPC_OPCODE_PPC) == 0)
196
            (*info->fprintf_func) (info->stream, "%ld", value);
197
          else
198
            {
199
              if (operand->bits == 3)
200
                (*info->fprintf_func) (info->stream, "cr%d", value);
201
              else
202
                {
203
                  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
204
                  int cr;
205
                  int cc;
206
 
207
                  cr = value >> 2;
208
                  if (cr != 0)
209
                    (*info->fprintf_func) (info->stream, "4*cr%d", cr);
210
                  cc = value & 3;
211
                  if (cc != 0)
212
                    {
213
                      if (cr != 0)
214
                        (*info->fprintf_func) (info->stream, "+");
215
                      (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
216
                    }
217
                }
218
            }
219
 
220
          if (need_paren)
221
            {
222
              (*info->fprintf_func) (info->stream, ")");
223
              need_paren = 0;
224
            }
225
 
226
          if ((operand->flags & PPC_OPERAND_PARENS) == 0)
227
            need_comma = 1;
228
          else
229
            {
230
              (*info->fprintf_func) (info->stream, "(");
231
              need_paren = 1;
232
            }
233
        }
234
 
235
      /* We have found and printed an instruction; return.  */
236
      return 4;
237
    }
238
 
239
  /* We could not find a match.  */
240
  (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
241
 
242
  return 4;
243
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.