OSDN Git Service

d817f80bcebc9fc475397216ffc913af6dd176ef
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / v850-dis.c
1 /* Disassemble V850 instructions.
2    Copyright (C) 1996, 1997, 1998 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
45 disassemble (memaddr, info, insn)
46      bfd_vma memaddr;
47      struct disassemble_info *info;
48      unsigned long insn;
49 {
50   struct v850_opcode *          op = (struct v850_opcode *)v850_opcodes;
51   const struct v850_operand *   operand;
52   int                           match = 0;
53   int                           short_op = ((insn & 0x0600) != 0x0600);
54   int                           bytes_read;
55   int                           target_processor;
56   
57   /* Special case: 32 bit MOV */
58   if ((insn & 0xffe0) == 0x0620)
59     short_op = true;
60   
61   bytes_read = short_op ? 2 : 4;
62   
63   /* If this is a two byte insn, then mask off the high bits. */
64   if (short_op)
65     insn &= 0xffff;
66
67   switch (info->mach)
68     {
69     case 0:
70     default:
71       target_processor = PROCESSOR_V850;
72       break;
73
74     case bfd_mach_v850e:
75       target_processor = PROCESSOR_V850E;
76       break;
77
78     case bfd_mach_v850ea: 
79       target_processor = PROCESSOR_V850EA;
80       break;
81     }
82   
83   /* Find the opcode.  */
84   while (op->name)
85     {
86       if ((op->mask & insn) == op->opcode
87           && (op->processors & target_processor))
88         {
89           const unsigned char * opindex_ptr;
90           unsigned int          opnum;
91           unsigned int          memop;
92
93           match = 1;
94           (*info->fprintf_func) (info->stream, "%s\t", op->name);
95 /*fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, 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) info->fprintf_func (info->stream, "[");
159               else if (memop && opnum == memop + 2) info->fprintf_func (info->stream, "],");
160               else if (memop == 1 && opnum == 1
161                        && (operand->flags & V850_OPERAND_REG))
162                                                     info->fprintf_func (info->stream, "[");
163               else if (opnum > 1)                   info->fprintf_func (info->stream, ", ");
164
165               /* extract the flags, ignorng ones which do not effect disassembly output. */
166               flag = operand->flags;
167               flag &= ~ V850_OPERAND_SIGNED;
168               flag &= ~ V850_OPERAND_RELAX;
169               flag &= - flag;
170               
171               switch (flag)
172                 {
173                 case V850_OPERAND_REG:  info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
174                 case V850_OPERAND_SRG:  info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
175                 case V850_OPERAND_CC:   info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
176                 case V850_OPERAND_EP:   info->fprintf_func (info->stream, "ep"); break;
177                 default:                info->fprintf_func (info->stream, "%d", value); break;
178                 case V850_OPERAND_DISP:
179                   {
180                     bfd_vma addr = value + memaddr;
181                     
182                     /* On the v850 the top 8 bits of an address are used by an overlay manager.
183                        Thus it may happen that when we are looking for a symbol to match
184                        against an address with some of its top bits set, the search fails to
185                        turn up an exact match.  In this case we try to find an exact match
186                        against a symbol in the lower address space, and if we find one, we
187                        use that address.   We only do this for JARL instructions however, as
188                        we do not want to misinterpret branch instructions.  */
189                     if (operand->bits == 22)
190                       {
191                         if ( ! info->symbol_at_address_func (addr, info)
192                             && ((addr & 0xFF000000) != 0)
193                             && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
194                           {
195                             addr &= 0x00FFFFFF;
196                           }
197                       }
198                     info->print_address_func (addr, info);
199                     break;
200                   }
201                     
202                 case V850E_PUSH_POP:
203                   {
204                     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 };
205                     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 };
206                     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 };
207                     int *             regs;
208                     int               i;
209                     unsigned long int mask = 0;
210                     int               pc   = false;
211                     int               sr   = false;
212                     
213                     
214                     switch (operand->shift)
215                       {
216                       case 0xffe00001: regs = list12_regs; break;
217                       case 0xfff8000f: regs = list18_h_regs; break;
218                       case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break;  /* Do not include magic bit */
219                       default:
220                         /* xgettext:c-format */
221                         fprintf (stderr, _("unknown operand shift: %x\n"), operand->shift );
222                         abort();
223                       }
224
225                     for (i = 0; i < 32; i++)
226                       {
227                         if (value & (1 << i))
228                           {
229                             switch (regs[ i ])
230                               {
231                               default: mask |= (1 << regs[ i ]); break;
232                                 /* xgettext:c-format */
233                               case 0:  fprintf (stderr, _("unknown pop reg: %d\n"), i ); abort();
234                               case -1: pc = true; break;
235                               case -2: sr = true; break;
236                               }
237                           }
238                       }
239
240                     info->fprintf_func (info->stream, "{");
241                     
242                     if (mask || pc || sr)
243                       {
244                         if (mask)
245                           {
246                             unsigned int bit;
247                             int          shown_one = false;
248                             
249                             for (bit = 0; bit < 32; bit++)
250                               if (mask & (1 << bit))
251                                 {
252                                   unsigned long int first = bit;
253                                   unsigned long int last;
254
255                                   if (shown_one)
256                                     info->fprintf_func (info->stream, ", ");
257                                   else
258                                     shown_one = true;
259                                   
260                                   info->fprintf_func (info->stream, v850_reg_names[first]);
261                                   
262                                   for (bit++; bit < 32; bit++)
263                                     if ((mask & (1 << bit)) == 0)
264                                       break;
265
266                                   last = bit;
267
268                                   if (last > first + 1)
269                                     {
270                                       info->fprintf_func (info->stream, " - %s", v850_reg_names[ last - 1 ]);
271                                     }
272                                 }
273                           }
274                         
275                         if (pc)
276                           info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
277                         if (sr)
278                           info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
279                       }
280                     
281                     info->fprintf_func (info->stream, "}");
282                   }
283                 break;
284                   
285                 case V850E_IMMEDIATE16:
286                   status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
287                   if (status == 0)
288                     {
289                       bytes_read += 2;
290                       value = bfd_getl16 (buffer);
291
292                       /* If this is a DISPOSE instruction with ff set to 0x10, then shift value up by 16.  */
293                       if ((insn & 0x001fffc0) == 0x00130780)
294                         value <<= 16;
295
296                       info->fprintf_func (info->stream, "0x%x", value);
297                     }
298                   else
299                     {
300                       info->memory_error_func (status, memaddr + bytes_read, info);
301                     }
302                   break;
303                   
304                 case V850E_IMMEDIATE32:
305                   status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
306                   if (status == 0)
307                     {
308                       bytes_read += 4;
309                       value = bfd_getl32 (buffer);
310                       info->fprintf_func (info->stream, "0x%lx", value);
311                     }
312                   else
313                     {
314                       info->memory_error_func (status, memaddr + bytes_read, info);
315                     }
316                   break;
317                 }                 
318
319               /* Handle jmp correctly.  */
320               if (memop == 1 && opnum == 1
321                   && ((operand->flags & V850_OPERAND_REG) != 0))
322                 (*info->fprintf_func) (info->stream, "]");
323             }
324
325           /* Close any square bracket we left open.  */
326           if (memop && opnum == memop + 2)
327             (*info->fprintf_func) (info->stream, "]");
328
329           /* All done. */
330           break;
331         }
332       op++;
333     }
334
335   if (!match)
336     {
337       if (short_op)
338         info->fprintf_func (info->stream, ".short\t0x%04x", insn);
339       else
340         info->fprintf_func (info->stream, ".long\t0x%08x", insn);
341     }
342
343   return bytes_read;
344 }
345
346 int 
347 print_insn_v850 (memaddr, info)
348      bfd_vma memaddr;
349      struct disassemble_info * info;
350 {
351   int           status;
352   bfd_byte      buffer[ 4 ];
353   unsigned long insn = 0;
354
355   /* First figure out how big the opcode is.  */
356   
357   status = info->read_memory_func (memaddr, buffer, 2, info);
358   if (status == 0)
359     {
360       insn = bfd_getl16 (buffer);
361       
362       if (   (insn & 0x0600) == 0x0600
363           && (insn & 0xffe0) != 0x0620)
364         {
365           /* If this is a 4 byte insn, read 4 bytes of stuff.  */
366           status = info->read_memory_func (memaddr, buffer, 4, info);
367
368           if (status == 0)
369             insn = bfd_getl32 (buffer);
370         }
371     }
372   
373   if (status != 0)
374     {
375       info->memory_error_func (status, memaddr, info);
376       return -1;
377     }
378
379   /* Make sure we tell our caller how many bytes we consumed.  */
380   return disassemble (memaddr, info, insn);
381 }