Update function declarations to ISO C90 formatting
[external/binutils.git] / opcodes / v850-dis.c
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
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, "%d", 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%x", 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%04x", insn);
359       else
360         info->fprintf_func (info->stream, ".long\t0x%08x", insn);
361     }
362
363   return bytes_read;
364 }
365
366 int
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 }