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