xref: /openbsd/gnu/usr.bin/binutils/opcodes/arc-dis.c (revision 78b63d65)
1 /* Instruction printing code for the ARC.
2    Copyright (C) 1994, 1995, 1997, 1998 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18 
19 #include "sysdep.h"
20 #include "dis-asm.h"
21 #include "opcode/arc.h"
22 #include "elf-bfd.h"
23 #include "elf/arc.h"
24 #include "opintl.h"
25 
26 static int print_insn_arc_base_little PARAMS ((bfd_vma, disassemble_info *));
27 static int print_insn_arc_base_big PARAMS ((bfd_vma, disassemble_info *));
28 
29 static int print_insn PARAMS ((bfd_vma, disassemble_info *, int, int));
30 
31 /* Print one instruction from PC on INFO->STREAM.
32    Return the size of the instruction (4 or 8 for the ARC). */
33 
34 static int
35 print_insn (pc, info, mach, big_p)
36      bfd_vma pc;
37      disassemble_info *info;
38      int mach;
39      int big_p;
40 {
41   const struct arc_opcode *opcode;
42   bfd_byte buffer[4];
43   void *stream = info->stream;
44   fprintf_ftype func = info->fprintf_func;
45   int status;
46   /* First element is insn, second element is limm (if present).  */
47   arc_insn insn[2];
48   int got_limm_p = 0;
49   static int initialized = 0;
50   static int current_mach = 0;
51 
52   if (!initialized || mach != current_mach)
53     {
54       initialized = 1;
55       current_mach = arc_get_opcode_mach (mach, big_p);
56       arc_opcode_init_tables (current_mach);
57     }
58 
59   status = (*info->read_memory_func) (pc, buffer, 4, info);
60   if (status != 0)
61     {
62       (*info->memory_error_func) (status, pc, info);
63       return -1;
64     }
65   if (big_p)
66     insn[0] = bfd_getb32 (buffer);
67   else
68     insn[0] = bfd_getl32 (buffer);
69 
70   (*func) (stream, "%08lx\t", insn[0]);
71 
72   /* The instructions are stored in lists hashed by the insn code
73      (though we needn't care how they're hashed).  */
74 
75   opcode = arc_opcode_lookup_dis (insn[0]);
76   for ( ; opcode != NULL; opcode = ARC_OPCODE_NEXT_DIS (opcode))
77     {
78       char *syn;
79       int mods,invalid;
80       long value;
81       const struct arc_operand *operand;
82       const struct arc_operand_value *opval;
83 
84       /* Basic bit mask must be correct.  */
85       if ((insn[0] & opcode->mask) != opcode->value)
86 	continue;
87 
88       /* Supported by this cpu?  */
89       if (! arc_opcode_supported (opcode))
90 	continue;
91 
92       /* Make two passes over the operands.  First see if any of them
93 	 have extraction functions, and, if they do, make sure the
94 	 instruction is valid.  */
95 
96       arc_opcode_init_extract ();
97       invalid = 0;
98 
99       /* ??? Granted, this is slower than the `ppc' way.  Maybe when this is
100 	 done it'll be clear what the right way to do this is.  */
101       /* Instructions like "add.f r0,r1,1" are tricky because the ".f" gets
102 	 printed first, but we don't know how to print it until we've processed
103 	 the regs.  Since we're scanning all the args before printing the insn
104 	 anyways, it's actually quite easy.  */
105 
106       for (syn = opcode->syntax; *syn; ++syn)
107 	{
108 	  int c;
109 
110 	  if (*syn != '%' || *++syn == '%')
111 	    continue;
112 	  mods = 0;
113 	  c = *syn;
114 	  while (ARC_MOD_P (arc_operands[arc_operand_map[c]].flags))
115 	    {
116 	      mods |= arc_operands[arc_operand_map[c]].flags & ARC_MOD_BITS;
117 	      ++syn;
118 	      c = *syn;
119 	    }
120 	  operand = arc_operands + arc_operand_map[c];
121 	  if (operand->extract)
122 	    (*operand->extract) (insn, operand, mods,
123 				 (const struct arc_operand_value **) NULL,
124 				 &invalid);
125 	}
126       if (invalid)
127 	continue;
128 
129       /* The instruction is valid.  */
130 
131       /* If we have an insn with a limm, fetch it now.  Scanning the insns
132 	 twice lets us do this.  */
133       if (arc_opcode_limm_p (NULL))
134 	{
135 	  status = (*info->read_memory_func) (pc + 4, buffer, 4, info);
136 	  if (status != 0)
137 	    {
138 	      (*info->memory_error_func) (status, pc, info);
139 	      return -1;
140 	    }
141 	  if (big_p)
142 	    insn[1] = bfd_getb32 (buffer);
143 	  else
144 	    insn[1] = bfd_getl32 (buffer);
145 	  got_limm_p = 1;
146 	}
147 
148       for (syn = opcode->syntax; *syn; ++syn)
149 	{
150 	  int c;
151 
152 	  if (*syn != '%' || *++syn == '%')
153 	    {
154 	      (*func) (stream, "%c", *syn);
155 	      continue;
156 	    }
157 
158 	  /* We have an operand.  Fetch any special modifiers.  */
159 	  mods = 0;
160 	  c = *syn;
161 	  while (ARC_MOD_P (arc_operands[arc_operand_map[c]].flags))
162 	    {
163 	      mods |= arc_operands[arc_operand_map[c]].flags & ARC_MOD_BITS;
164 	      ++syn;
165 	      c = *syn;
166 	    }
167 	  operand = arc_operands + arc_operand_map[c];
168 
169 	  /* Extract the value from the instruction.  */
170 	  opval = NULL;
171 	  if (operand->extract)
172 	    {
173 	      value = (*operand->extract) (insn, operand, mods,
174 					   &opval, (int *) NULL);
175 	    }
176 	  else
177 	    {
178 	      value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
179 	      if ((operand->flags & ARC_OPERAND_SIGNED)
180 		  && (value & (1 << (operand->bits - 1))))
181 		value -= 1 << operand->bits;
182 
183 	      /* If this is a suffix operand, set `opval'.  */
184 	      if (operand->flags & ARC_OPERAND_SUFFIX)
185 		opval = arc_opcode_lookup_suffix (operand, value);
186 	    }
187 
188 	  /* Print the operand as directed by the flags.  */
189 	  if (operand->flags & ARC_OPERAND_FAKE)
190 	    ; /* nothing to do (??? at least not yet) */
191 	  else if (operand->flags & ARC_OPERAND_SUFFIX)
192 	    {
193 	      /* Default suffixes aren't printed.  Fortunately, they all have
194 		 zero values.  Also, zero values for boolean suffixes are
195 		 represented by the absence of text.  */
196 
197 	      if (value != 0)
198 		{
199 		  /* ??? OPVAL should have a value.  If it doesn't just cope
200 		     as we want disassembly to be reasonably robust.
201 		     Also remember that several condition code values (16-31)
202 		     aren't defined yet.  For these cases just print the
203 		     number suitably decorated.  */
204 		  if (opval)
205 		    (*func) (stream, "%s%s",
206 			     mods & ARC_MOD_DOT ? "." : "",
207 			     opval->name);
208 		  else
209 		    (*func) (stream, "%s%c%d",
210 			     mods & ARC_MOD_DOT ? "." : "",
211 			     operand->fmt, value);
212 		}
213 	    }
214 	  else if (operand->flags & ARC_OPERAND_RELATIVE_BRANCH)
215 	    (*info->print_address_func) (pc + 4 + value, info);
216 	  /* ??? Not all cases of this are currently caught.  */
217 	  else if (operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH)
218 	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
219 	  else if (operand->flags & ARC_OPERAND_ADDRESS)
220 	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
221 	  else if (opval)
222 	    /* Note that this case catches both normal and auxiliary regs.  */
223 	    (*func) (stream, "%s", opval->name);
224 	  else
225 	    (*func) (stream, "%ld", value);
226 	}
227 
228       /* We have found and printed an instruction; return.  */
229       return got_limm_p ? 8 : 4;
230     }
231 
232   (*func) (stream, _("*unknown*"));
233   return 4;
234 }
235 
236 /* Given MACH, one of bfd_mach_arc_xxx, return the print_insn function to use.
237    This does things a non-standard way (the "standard" way would be to copy
238    this code into disassemble.c).  Since there are more than a couple of
239    variants, hiding all this crud here seems cleaner.  */
240 
241 disassembler_ftype
242 arc_get_disassembler (mach, big_p)
243      int mach;
244      int big_p;
245 {
246   switch (mach)
247     {
248     case bfd_mach_arc_base:
249       return big_p ? print_insn_arc_base_big : print_insn_arc_base_little;
250     }
251   return print_insn_arc_base_little;
252 }
253 
254 static int
255 print_insn_arc_base_little (pc, info)
256      bfd_vma pc;
257      disassemble_info *info;
258 {
259   return print_insn (pc, info, bfd_mach_arc_base, 0);
260 }
261 
262 static int
263 print_insn_arc_base_big (pc, info)
264      bfd_vma pc;
265      disassemble_info *info;
266 {
267   return print_insn (pc, info, bfd_mach_arc_base, 1);
268 }
269