* arc-opc.c (insertion fns): Pass pointer to value's table entry.
[external/binutils.git] / opcodes / arc-dis.c
1 /* Instruction printing code for the ARC.
2    Copyright (C) 1994 Free Software Foundation, Inc. 
3    Contributed by Doug Evans (dje@cygnus.com).
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
18
19 #include "dis-asm.h"
20 #include "opcode/arc.h"
21
22 /* Print one instruction from PC on INFO->STREAM.
23    Return the size of the instruction (4 or 8 for the ARC). */
24
25 int
26 print_insn_arc (pc, info)
27      bfd_vma pc;
28      struct disassemble_info *info;
29 {
30   const struct arc_opcode *opcode,*opcode_end;
31   bfd_byte buffer[4];
32   void *stream = info->stream;
33   fprintf_ftype func = info->fprintf_func;
34   int status;
35   /* First element is insn, second element is limm (if present).  */
36   arc_insn insn[2];
37   int got_limm_p = 0;
38   static int initialized = 0;
39
40   if (!initialized)
41     {
42       /* ??? Hmmm... what do we pass here?  */
43       arc_opcode_init_tables (ARC_HAVE_MULT_SHIFT);
44       initialized = 1;
45     }
46
47   status = (*info->read_memory_func) (pc, buffer, 4, info);
48   if (status != 0)
49     {
50       (*info->memory_error_func) (status, pc, info);
51       return -1;
52     }
53   insn[0] = bfd_getb32 (buffer);
54
55   func (stream, "%08lx\t", insn[0]);
56
57   opcode_end = arc_opcodes + arc_opcodes_count;
58   for (opcode = arc_opcodes; opcode < opcode_end; opcode++)
59     {
60       char *syn;
61       int mods,invalid;
62       long value;
63       const struct arc_operand *operand;
64       const struct arc_operand_value *opval;
65
66       if ((insn[0] & opcode->mask) != opcode->value)
67         continue;
68
69       /* Make two passes over the operands.  First see if any of them
70          have extraction functions, and, if they do, make sure the
71          instruction is valid.  */
72
73       arc_opcode_init_extract ();
74       invalid = 0;
75
76       /* ??? Granted, this is slower than the `ppc' way.  Maybe when this is
77          done it'll be clear what the right way to do this is.  */
78       /* Instructions like "add.f r0,r1,1" are tricky because the ".f" gets
79          printed first, but we don't know how to print it until we've processed
80          the regs.  Since we're scanning all the args before printing the insn
81          anyways, it's quite easy.  */
82
83       for (syn = opcode->syntax; *syn; ++syn)
84         {
85           if (*syn != '%' || *++syn == '%')
86             continue;
87           mods = 0;
88           while (ARC_MOD_P (arc_operands[arc_operand_map[*syn]].flags))
89             {
90               mods |= arc_operands[arc_operand_map[*syn]].flags & ARC_MOD_BITS;
91               ++syn;
92             }
93           operand = arc_operands + arc_operand_map[*syn];
94           if (operand->extract)
95             (*operand->extract) (insn, operand, mods,
96                                  (const struct arc_operand_value **) NULL,
97                                  &invalid);
98         }
99       if (invalid)
100         continue;
101
102       /* The instruction is valid.  */
103
104       /* If we have an insn with a limm, fetch it now.  Scanning the insns
105          twice lets us do this.  */
106       if (arc_opcode_limm_p (NULL))
107         {
108           status = (*info->read_memory_func) (pc + 4, buffer, 4, info);
109           if (status != 0)
110             {
111               (*info->memory_error_func) (status, pc, info);
112               return -1;
113             }
114           insn[1] = bfd_getb32 (buffer);
115           got_limm_p = 1;
116         }
117
118       for (syn = opcode->syntax; *syn; ++syn)
119         {
120           if (*syn != '%' || *++syn == '%')
121             {
122               func (stream, "%c", *syn);
123               continue;
124             }
125
126           /* We have an operand.  Fetch any special modifiers.  */
127           mods = 0;
128           while (ARC_MOD_P (arc_operands[arc_operand_map[*syn]].flags))
129             {
130               mods |= arc_operands[arc_operand_map[*syn]].flags & ARC_MOD_BITS;
131               ++syn;
132             }
133           operand = arc_operands + arc_operand_map[*syn];
134
135           /* Extract the value from the instruction.  */
136           opval = NULL;
137           if (operand->extract)
138             {
139               value = (*operand->extract) (insn, operand, mods,
140                                            &opval, (int *) NULL);
141             }
142           else
143             {
144               value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
145               if ((operand->flags & ARC_OPERAND_SIGNED)
146                   && (value & (1 << (operand->bits - 1))))
147                 value -= 1 << operand->bits;
148
149               /* If this is a suffix operand, set `opval'.  */
150               if (operand->flags & ARC_OPERAND_SUFFIX)
151                 opval = arc_opcode_lookup_suffix (operand, value);
152             }
153
154           /* Print the operand as directed by the flags.  */
155           if (operand->flags & ARC_OPERAND_FAKE)
156             ; /* nothing to do (??? at least not yet) */
157           else if (operand->flags & ARC_OPERAND_SUFFIX)
158             {
159               /* Default suffixes aren't printed.  Fortunately, they all have
160                  zero values.  Also, zero values for boolean suffixes are
161                  represented by the absence of text.  */
162
163               if (value != 0)
164                 {
165                   /* ??? OPVAL should have a value.  If it doesn't just cope
166                      as we want disassembly to be reasonably robust.
167                      Also remember that several condition code values (16-31)
168                      aren't defined yet.  For these cases just print the
169                      number suitably decorated.  */
170                   if (opval)
171                     func (stream, "%s%s",
172                           mods & ARC_MOD_DOT ? "." : "",
173                           opval->name);
174                   else
175                     func (stream, "%s%c%d",
176                           mods & ARC_MOD_DOT ? "." : "",
177                           operand->fmt, value);
178                 }
179             }
180           else if (operand->flags & ARC_OPERAND_RELATIVE)
181             (*info->print_address_func) (pc + value, info);
182           /* ??? Not all cases of this are currently caught.  */
183           else if (operand->flags & ARC_OPERAND_ABSOLUTE)
184             (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
185           else if (opval)
186             /* Note that this case catches both normal and auxiliary regs.  */
187             func (stream, "%s", opval->name);
188           else
189             func (stream, "%ld", value);
190         }
191
192       /* We have found and printed an instruction; return.  */
193       return got_limm_p ? 8 : 4;
194     }
195
196   func (stream, "*unknown*");
197   return 4;
198 }