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