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