xref: /netbsd-src/external/gpl3/binutils/dist/opcodes/v850-dis.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /* Disassemble V850 instructions.
2    Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2007
3    Free Software Foundation, Inc.
4 
5    This file is part of the GNU opcodes library.
6 
7    This library is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11 
12    It is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21 
22 
23 #include <stdio.h>
24 
25 #include "sysdep.h"
26 #include "opcode/v850.h"
27 #include "dis-asm.h"
28 #include "opintl.h"
29 
30 static const char *const v850_reg_names[] =
31 { "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
32   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
33   "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
34   "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" };
35 
36 static const char *const v850_sreg_names[] =
37 { "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7",
38   "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
39   "ctpc", "ctpsw", "dbpc", "dbpsw", "ctbp", "sr21", "sr22", "sr23",
40   "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31",
41   "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23",
42   "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
43 
44 static const char *const v850_cc_names[] =
45 { "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
46   "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
47 
48 static int
49 disassemble (bfd_vma memaddr,
50 	     struct disassemble_info * info,
51 	     unsigned long insn)
52 {
53   struct v850_opcode * op = (struct v850_opcode *) v850_opcodes;
54   const struct v850_operand * operand;
55   int match = 0;
56   int short_op = ((insn & 0x0600) != 0x0600);
57   int bytes_read;
58   int target_processor;
59 
60   /* Special case: 32 bit MOV.  */
61   if ((insn & 0xffe0) == 0x0620)
62     short_op = 1;
63 
64   bytes_read = short_op ? 2 : 4;
65 
66   /* If this is a two byte insn, then mask off the high bits.  */
67   if (short_op)
68     insn &= 0xffff;
69 
70   switch (info->mach)
71     {
72     case 0:
73     default:
74       target_processor = PROCESSOR_V850;
75       break;
76 
77     case bfd_mach_v850e:
78       target_processor = PROCESSOR_V850E;
79       break;
80 
81     case bfd_mach_v850e1:
82       target_processor = PROCESSOR_V850E1;
83       break;
84     }
85 
86   /* Find the opcode.  */
87   while (op->name)
88     {
89       if ((op->mask & insn) == op->opcode
90 	  && (op->processors & target_processor))
91 	{
92 	  const unsigned char *opindex_ptr;
93 	  unsigned int opnum;
94 	  unsigned int memop;
95 
96 	  match = 1;
97 	  (*info->fprintf_func) (info->stream, "%s\t", op->name);
98 
99 	  memop = op->memop;
100 	  /* Now print the operands.
101 
102 	     MEMOP is the operand number at which a memory
103 	     address specification starts, or zero if this
104 	     instruction has no memory addresses.
105 
106 	     A memory address is always two arguments.
107 
108 	     This information allows us to determine when to
109 	     insert commas into the output stream as well as
110 	     when to insert disp[reg] expressions onto the
111 	     output stream.  */
112 
113 	  for (opindex_ptr = op->operands, opnum = 1;
114 	       *opindex_ptr != 0;
115 	       opindex_ptr++, opnum++)
116 	    {
117 	      long value;
118 	      int flag;
119 	      int status;
120 	      bfd_byte buffer[4];
121 
122 	      operand = &v850_operands[*opindex_ptr];
123 
124 	      if (operand->extract)
125 		value = (operand->extract) (insn, 0);
126 	      else
127 		{
128 		  if (operand->bits == -1)
129 		    value = (insn & operand->shift);
130 		  else
131 		    value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
132 
133 		  if (operand->flags & V850_OPERAND_SIGNED)
134 		    value = ((long)(value << (32 - operand->bits))
135 			     >> (32 - operand->bits));
136 		}
137 
138 	      /* The first operand is always output without any
139 		 special handling.
140 
141 		 For the following arguments:
142 
143 		   If memop && opnum == memop + 1, then we need '[' since
144 		   we're about to output the register used in a memory
145 		   reference.
146 
147 		   If memop && opnum == memop + 2, then we need ']' since
148 		   we just finished the register in a memory reference.  We
149 		   also need a ',' before this operand.
150 
151 		   Else we just need a comma.
152 
153 		   We may need to output a trailing ']' if the last operand
154 		   in an instruction is the register for a memory address.
155 
156 		   The exception (and there's always an exception) is the
157 		   "jmp" insn which needs square brackets around it's only
158 		   register argument.  */
159 
160 	           if (memop && opnum == memop + 1)
161 		     info->fprintf_func (info->stream, "[");
162 		   else if (memop && opnum == memop + 2)
163 		     info->fprintf_func (info->stream, "],");
164 		   else if (memop == 1 && opnum == 1
165 			    && (operand->flags & V850_OPERAND_REG))
166 		     info->fprintf_func (info->stream, "[");
167 		   else if (opnum > 1)
168 		     info->fprintf_func (info->stream, ", ");
169 
170 	      /* Extract the flags, ignorng ones which
171 		 do not effect disassembly output. */
172 	      flag = operand->flags;
173 	      flag &= ~ V850_OPERAND_SIGNED;
174 	      flag &= ~ V850_OPERAND_RELAX;
175 	      flag &= - flag;
176 
177 	      switch (flag)
178 		{
179 		case V850_OPERAND_REG:
180 		  info->fprintf_func (info->stream, "%s", v850_reg_names[value]);
181 		  break;
182 		case V850_OPERAND_SRG:
183 		  info->fprintf_func (info->stream, "%s", v850_sreg_names[value]);
184 		  break;
185 		case V850_OPERAND_CC:
186 		  info->fprintf_func (info->stream, "%s", v850_cc_names[value]);
187 		  break;
188 		case V850_OPERAND_EP:
189 		  info->fprintf_func (info->stream, "ep");
190 		  break;
191 		default:
192 		  info->fprintf_func (info->stream, "%ld", value);
193 		  break;
194 		case V850_OPERAND_DISP:
195 		  {
196 		    bfd_vma addr = value + memaddr;
197 
198 		    /* On the v850 the top 8 bits of an address are used by an
199 		       overlay manager.  Thus it may happen that when we are
200 		       looking for a symbol to match against an address with
201 		       some of its top bits set, the search fails to turn up an
202 		       exact match.  In this case we try to find an exact match
203 		       against a symbol in the lower address space, and if we
204 		       find one, we use that address.   We only do this for
205 		       JARL instructions however, as we do not want to
206 		       misinterpret branch instructions.  */
207 		    if (operand->bits == 22)
208 		      {
209 			if ( ! info->symbol_at_address_func (addr, info)
210 			    && ((addr & 0xFF000000) != 0)
211 			    && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
212 			  addr &= 0x00FFFFFF;
213 		      }
214 		    info->print_address_func (addr, info);
215 		    break;
216 		  }
217 
218 		case V850E_PUSH_POP:
219 		  {
220 		    static int list12_regs[32]   = { 30,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
221 		    static int list18_h_regs[32] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
222 		    static int list18_l_regs[32] = {  3,  2,  1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 14, 15, 13, 12,  7,  6,  5,  4, 11, 10,  9,  8 };
223 		    int *regs;
224 		    int i;
225 		    unsigned long int mask = 0;
226 		    int pc = 0;
227 		    int sr = 0;
228 
229 		    switch (operand->shift)
230 		      {
231 		      case 0xffe00001: regs = list12_regs; break;
232 		      case 0xfff8000f: regs = list18_h_regs; break;
233 		      case 0xfff8001f:
234 			regs = list18_l_regs;
235 			value &= ~0x10;  /* Do not include magic bit.  */
236 			  break;
237 		      default:
238 			/* xgettext:c-format */
239 			fprintf (stderr, _("unknown operand shift: %x\n"),
240 				 operand->shift);
241 			abort ();
242 		      }
243 
244 		    for (i = 0; i < 32; i++)
245 		      {
246 			if (value & (1 << i))
247 			  {
248 			    switch (regs[ i ])
249 			      {
250 			      default: mask |= (1 << regs[ i ]); break;
251 				/* xgettext:c-format */
252 			      case 0:
253 				fprintf (stderr, _("unknown pop reg: %d\n"), i );
254 				abort ();
255 			      case -1: pc = 1; break;
256 			      case -2: sr = 1; break;
257 			      }
258 			  }
259 		      }
260 
261 		    info->fprintf_func (info->stream, "{");
262 
263 		    if (mask || pc || sr)
264 		      {
265 			if (mask)
266 			  {
267 			    unsigned int bit;
268 			    int shown_one = 0;
269 
270 			    for (bit = 0; bit < 32; bit++)
271 			      if (mask & (1 << bit))
272 				{
273 				  unsigned long int first = bit;
274 				  unsigned long int last;
275 
276 				  if (shown_one)
277 				    info->fprintf_func (info->stream, ", ");
278 				  else
279 				    shown_one = 1;
280 
281 				  info->fprintf_func (info->stream,
282 						      v850_reg_names[first]);
283 
284 				  for (bit++; bit < 32; bit++)
285 				    if ((mask & (1 << bit)) == 0)
286 				      break;
287 
288 				  last = bit;
289 
290 				  if (last > first + 1)
291 				    info->fprintf_func (info->stream, " - %s",
292 							v850_reg_names[last - 1]);
293 				}
294 			  }
295 
296 			if (pc)
297 			  info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
298 			if (sr)
299 			  info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
300 		      }
301 
302 		    info->fprintf_func (info->stream, "}");
303 		  }
304 		break;
305 
306 		case V850E_IMMEDIATE16:
307 		  status = info->read_memory_func (memaddr + bytes_read,
308 						   buffer, 2, info);
309 		  if (status == 0)
310 		    {
311 		      bytes_read += 2;
312 		      value = bfd_getl16 (buffer);
313 
314 		      /* If this is a DISPOSE instruction with ff
315 			 set to 0x10, then shift value up by 16.  */
316 		      if ((insn & 0x001fffc0) == 0x00130780)
317 			value <<= 16;
318 
319 		      info->fprintf_func (info->stream, "0x%lx", value);
320 		    }
321 		  else
322 		    info->memory_error_func (status, memaddr + bytes_read,
323 					     info);
324 		  break;
325 
326 		case V850E_IMMEDIATE32:
327 		  status = info->read_memory_func (memaddr + bytes_read,
328 						   buffer, 4, info);
329 		  if (status == 0)
330 		    {
331 		      bytes_read += 4;
332 		      value = bfd_getl32 (buffer);
333 		      info->fprintf_func (info->stream, "0x%lx", value);
334 		    }
335 		  else
336 		    info->memory_error_func (status, memaddr + bytes_read,
337 					     info);
338 		  break;
339 		}
340 
341 	      /* Handle jmp correctly.  */
342 	      if (memop == 1 && opnum == 1
343 		  && ((operand->flags & V850_OPERAND_REG) != 0))
344 		(*info->fprintf_func) (info->stream, "]");
345 	    }
346 
347 	  /* Close any square bracket we left open.  */
348 	  if (memop && opnum == memop + 2)
349 	    (*info->fprintf_func) (info->stream, "]");
350 
351 	  /* All done. */
352 	  break;
353 	}
354       op++;
355     }
356 
357   if (!match)
358     {
359       if (short_op)
360 	info->fprintf_func (info->stream, ".short\t0x%04lx", insn);
361       else
362 	info->fprintf_func (info->stream, ".long\t0x%08lx", insn);
363     }
364 
365   return bytes_read;
366 }
367 
368 int
369 print_insn_v850 (bfd_vma memaddr, struct disassemble_info * info)
370 {
371   int status;
372   bfd_byte buffer[4];
373   unsigned long insn = 0;
374 
375   /* First figure out how big the opcode is.  */
376   status = info->read_memory_func (memaddr, buffer, 2, info);
377   if (status == 0)
378     {
379       insn = bfd_getl16 (buffer);
380 
381       if (   (insn & 0x0600) == 0x0600
382 	  && (insn & 0xffe0) != 0x0620)
383 	{
384 	  /* If this is a 4 byte insn, read 4 bytes of stuff.  */
385 	  status = info->read_memory_func (memaddr, buffer, 4, info);
386 
387 	  if (status == 0)
388 	    insn = bfd_getl32 (buffer);
389 	}
390     }
391 
392   if (status != 0)
393     {
394       info->memory_error_func (status, memaddr, info);
395       return -1;
396     }
397 
398   /* Make sure we tell our caller how many bytes we consumed.  */
399   return disassemble (memaddr, info, insn);
400 }
401