Update the address and phone number of the FSF
[external/binutils.git] / opcodes / v850-dis.c
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 }