* v850-dis.c (disassemble): Remove bfd_mach_v850ea case.
[external/binutils.git] / 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   
82   /* Find the opcode.  */
83   while (op->name)
84     {
85       if ((op->mask & insn) == op->opcode
86           && (op->processors & target_processor))
87         {
88           const unsigned char * opindex_ptr;
89           unsigned int          opnum;
90           unsigned int          memop;
91
92           match = 1;
93           (*info->fprintf_func) (info->stream, "%s\t", op->name);
94 /*fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, op->name );*/
95
96           memop = op->memop;
97           /* Now print the operands.
98
99              MEMOP is the operand number at which a memory
100              address specification starts, or zero if this
101              instruction has no memory addresses.
102
103              A memory address is always two arguments.
104
105              This information allows us to determine when to
106              insert commas into the output stream as well as
107              when to insert disp[reg] expressions onto the
108              output stream.  */
109           
110           for (opindex_ptr = op->operands, opnum = 1;
111                *opindex_ptr != 0;
112                opindex_ptr++, opnum++)
113             {
114               long      value;
115               int       flag;
116               int       status;
117               bfd_byte  buffer[ 4 ];
118               
119               operand = &v850_operands[*opindex_ptr];
120               
121               if (operand->extract)
122                 value = (operand->extract) (insn, 0);
123               else
124                 {
125                   if (operand->bits == -1)
126                     value = (insn & operand->shift);
127                   else
128                     value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
129
130                   if (operand->flags & V850_OPERAND_SIGNED)
131                     value = ((long)(value << (32 - operand->bits))
132                              >> (32 - operand->bits));
133                 }
134
135               /* The first operand is always output without any
136                  special handling.
137
138                  For the following arguments:
139
140                    If memop && opnum == memop + 1, then we need '[' since
141                    we're about to output the register used in a memory
142                    reference.
143
144                    If memop && opnum == memop + 2, then we need ']' since
145                    we just finished the register in a memory reference.  We
146                    also need a ',' before this operand.
147
148                    Else we just need a comma.
149
150                    We may need to output a trailing ']' if the last operand
151                    in an instruction is the register for a memory address. 
152
153                    The exception (and there's always an exception) is the
154                    "jmp" insn which needs square brackets around it's only
155                    register argument.  */
156
157                    if (memop && opnum == memop + 1) info->fprintf_func (info->stream, "[");
158               else if (memop && opnum == memop + 2) info->fprintf_func (info->stream, "],");
159               else if (memop == 1 && opnum == 1
160                        && (operand->flags & V850_OPERAND_REG))
161                                                     info->fprintf_func (info->stream, "[");
162               else if (opnum > 1)                   info->fprintf_func (info->stream, ", ");
163
164               /* extract the flags, ignorng ones which do not effect disassembly output. */
165               flag = operand->flags;
166               flag &= ~ V850_OPERAND_SIGNED;
167               flag &= ~ V850_OPERAND_RELAX;
168               flag &= - flag;
169               
170               switch (flag)
171                 {
172                 case V850_OPERAND_REG:  info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
173                 case V850_OPERAND_SRG:  info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
174                 case V850_OPERAND_CC:   info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
175                 case V850_OPERAND_EP:   info->fprintf_func (info->stream, "ep"); break;
176                 default:                info->fprintf_func (info->stream, "%d", value); break;
177                 case V850_OPERAND_DISP:
178                   {
179                     bfd_vma addr = value + memaddr;
180                     
181                     /* On the v850 the top 8 bits of an address are used by an overlay manager.
182                        Thus it may happen that when we are looking for a symbol to match
183                        against an address with some of its top bits set, the search fails to
184                        turn up an exact match.  In this case we try to find an exact match
185                        against a symbol in the lower address space, and if we find one, we
186                        use that address.   We only do this for JARL instructions however, as
187                        we do not want to misinterpret branch instructions.  */
188                     if (operand->bits == 22)
189                       {
190                         if ( ! info->symbol_at_address_func (addr, info)
191                             && ((addr & 0xFF000000) != 0)
192                             && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
193                           {
194                             addr &= 0x00FFFFFF;
195                           }
196                       }
197                     info->print_address_func (addr, info);
198                     break;
199                   }
200                     
201                 case V850E_PUSH_POP:
202                   {
203                     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 };
204                     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 };
205                     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 };
206                     int *             regs;
207                     int               i;
208                     unsigned long int mask = 0;
209                     int               pc   = false;
210                     int               sr   = false;
211                     
212                     
213                     switch (operand->shift)
214                       {
215                       case 0xffe00001: regs = list12_regs; break;
216                       case 0xfff8000f: regs = list18_h_regs; break;
217                       case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break;  /* Do not include magic bit */
218                       default:
219                         /* xgettext:c-format */
220                         fprintf (stderr, _("unknown operand shift: %x\n"), operand->shift );
221                         abort();
222                       }
223
224                     for (i = 0; i < 32; i++)
225                       {
226                         if (value & (1 << i))
227                           {
228                             switch (regs[ i ])
229                               {
230                               default: mask |= (1 << regs[ i ]); break;
231                                 /* xgettext:c-format */
232                               case 0:  fprintf (stderr, _("unknown pop reg: %d\n"), i ); abort();
233                               case -1: pc = true; break;
234                               case -2: sr = true; break;
235                               }
236                           }
237                       }
238
239                     info->fprintf_func (info->stream, "{");
240                     
241                     if (mask || pc || sr)
242                       {
243                         if (mask)
244                           {
245                             unsigned int bit;
246                             int          shown_one = false;
247                             
248                             for (bit = 0; bit < 32; bit++)
249                               if (mask & (1 << bit))
250                                 {
251                                   unsigned long int first = bit;
252                                   unsigned long int last;
253
254                                   if (shown_one)
255                                     info->fprintf_func (info->stream, ", ");
256                                   else
257                                     shown_one = true;
258                                   
259                                   info->fprintf_func (info->stream, v850_reg_names[first]);
260                                   
261                                   for (bit++; bit < 32; bit++)
262                                     if ((mask & (1 << bit)) == 0)
263                                       break;
264
265                                   last = bit;
266
267                                   if (last > first + 1)
268                                     {
269                                       info->fprintf_func (info->stream, " - %s", v850_reg_names[ last - 1 ]);
270                                     }
271                                 }
272                           }
273                         
274                         if (pc)
275                           info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
276                         if (sr)
277                           info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
278                       }
279                     
280                     info->fprintf_func (info->stream, "}");
281                   }
282                 break;
283                   
284                 case V850E_IMMEDIATE16:
285                   status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
286                   if (status == 0)
287                     {
288                       bytes_read += 2;
289                       value = bfd_getl16 (buffer);
290
291                       /* If this is a DISPOSE instruction with ff set to 0x10, then shift value up by 16.  */
292                       if ((insn & 0x001fffc0) == 0x00130780)
293                         value <<= 16;
294
295                       info->fprintf_func (info->stream, "0x%x", value);
296                     }
297                   else
298                     {
299                       info->memory_error_func (status, memaddr + bytes_read, info);
300                     }
301                   break;
302                   
303                 case V850E_IMMEDIATE32:
304                   status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
305                   if (status == 0)
306                     {
307                       bytes_read += 4;
308                       value = bfd_getl32 (buffer);
309                       info->fprintf_func (info->stream, "0x%lx", value);
310                     }
311                   else
312                     {
313                       info->memory_error_func (status, memaddr + bytes_read, info);
314                     }
315                   break;
316                 }                 
317
318               /* Handle jmp correctly.  */
319               if (memop == 1 && opnum == 1
320                   && ((operand->flags & V850_OPERAND_REG) != 0))
321                 (*info->fprintf_func) (info->stream, "]");
322             }
323
324           /* Close any square bracket we left open.  */
325           if (memop && opnum == memop + 2)
326             (*info->fprintf_func) (info->stream, "]");
327
328           /* All done. */
329           break;
330         }
331       op++;
332     }
333
334   if (!match)
335     {
336       if (short_op)
337         info->fprintf_func (info->stream, ".short\t0x%04x", insn);
338       else
339         info->fprintf_func (info->stream, ".long\t0x%08x", insn);
340     }
341
342   return bytes_read;
343 }
344
345 int 
346 print_insn_v850 (memaddr, info)
347      bfd_vma memaddr;
348      struct disassemble_info * info;
349 {
350   int           status;
351   bfd_byte      buffer[ 4 ];
352   unsigned long insn = 0;
353
354   /* First figure out how big the opcode is.  */
355   
356   status = info->read_memory_func (memaddr, buffer, 2, info);
357   if (status == 0)
358     {
359       insn = bfd_getl16 (buffer);
360       
361       if (   (insn & 0x0600) == 0x0600
362           && (insn & 0xffe0) != 0x0620)
363         {
364           /* If this is a 4 byte insn, read 4 bytes of stuff.  */
365           status = info->read_memory_func (memaddr, buffer, 4, info);
366
367           if (status == 0)
368             insn = bfd_getl32 (buffer);
369         }
370     }
371   
372   if (status != 0)
373     {
374       info->memory_error_func (status, memaddr, info);
375       return -1;
376     }
377
378   /* Make sure we tell our caller how many bytes we consumed.  */
379   return disassemble (memaddr, info, insn);
380 }