This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / opcodes / v850-dis.c
1 /* Disassemble V850 instructions.
2    Copyright (C) 1996 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 "ansidecl.h"
22 #include "opcode/v850.h" 
23 #include "dis-asm.h"
24
25 static const char *const v850_reg_names[] =
26 { "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7", 
27   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 
28   "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 
29   "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" };
30
31 static const char *const v850_sreg_names[] =
32 { "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7", 
33   "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
34 /* start-sanitize-v850e */
35   "ctpc", "ctpsw", "dbpc", "dbpsw", "ctbp", "sr21", "sr22", "sr23", 
36   "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31",
37 /* end-sanitize-v850e */
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
46 disassemble (memaddr, info, insn)
47      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 /* start-sanitize-v850e */
59   /* Special case: 32 bit MOV */
60   if ((insn & 0xffe0) == 0x0620)
61     short_op = true;
62 /* end-sanitize-v850e */
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 /* start-sanitize-v850e */
78     case bfd_mach_v850e:
79       target_processor = PROCESSOR_V850E;
80       break;
81
82     case bfd_mach_v850eq: 
83       target_processor = PROCESSOR_V850EQ;
84       break;
85 /* end-sanitize-v850e */
86     }
87   
88   /* Find the opcode.  */
89   while (op->name)
90     {
91       if ((op->mask & insn) == op->opcode
92           && (op->processors & target_processor))
93         {
94           const unsigned char * opindex_ptr;
95           unsigned int          opnum;
96           unsigned int          memop;
97
98           match = 1;
99           (*info->fprintf_func) (info->stream, "%s\t", op->name);
100 //fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, op->name );
101
102           memop = op->memop;
103           /* Now print the operands.
104
105              MEMOP is the operand number at which a memory
106              address specification starts, or zero if this
107              instruction has no memory addresses.
108
109              A memory address is always two arguments.
110
111              This information allows us to determine when to
112              insert commas into the output stream as well as
113              when to insert disp[reg] expressions onto the
114              output stream.  */
115           
116           for (opindex_ptr = op->operands, opnum = 1;
117                *opindex_ptr != 0;
118                opindex_ptr++, opnum++)
119             {
120               long      value;
121               int       flag;
122               int       status;
123               bfd_byte  buffer[ 4 ];
124               
125               operand = &v850_operands[*opindex_ptr];
126               
127               if (operand->extract)
128                 value = (operand->extract) (insn, 0);
129               else
130                 {
131                   if (operand->bits == -1)
132                     value = (insn & operand->shift);
133                   else
134                     value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
135
136                   if (operand->flags & V850_OPERAND_SIGNED)
137                     value = ((long)(value << (32 - operand->bits))
138                              >> (32 - operand->bits));
139                 }
140
141               /* The first operand is always output without any
142                  special handling.
143
144                  For the following arguments:
145
146                    If memop && opnum == memop + 1, then we need '[' since
147                    we're about to output the register used in a memory
148                    reference.
149
150                    If memop && opnum == memop + 2, then we need ']' since
151                    we just finished the register in a memory reference.  We
152                    also need a ',' before this operand.
153
154                    Else we just need a comma.
155
156                    We may need to output a trailing ']' if the last operand
157                    in an instruction is the register for a memory address. 
158
159                    The exception (and there's always an exception) is the
160                    "jmp" insn which needs square brackets around it's only
161                    register argument.  */
162
163                    if (memop && opnum == memop + 1) info->fprintf_func (info->stream, "[");
164               else if (memop && opnum == memop + 2) info->fprintf_func (info->stream, "],");
165               else if (memop == 1 && opnum == 1
166                        && (operand->flags & V850_OPERAND_REG))
167                                                     info->fprintf_func (info->stream, "[");
168               else if (opnum > 1)                   info->fprintf_func (info->stream, ", ");
169
170               /* extract the flags, ignorng ones which do not effect disassembly output. */
171               flag = operand->flags;
172               flag &= ~ V850_OPERAND_SIGNED;
173               flag &= ~ V850_OPERAND_RELAX;
174               flag &= - flag;
175               
176               switch (flag)
177                 {
178                 case V850_OPERAND_REG:  info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
179                 case V850_OPERAND_SRG:  info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
180                 case V850_OPERAND_CC:   info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
181                 case V850_OPERAND_EP:   info->fprintf_func (info->stream, "ep"); break;
182                 default:                info->fprintf_func (info->stream, "%d", value); break;
183                 case V850_OPERAND_DISP:
184                   {
185                     bfd_vma addr = value + memaddr;
186                     
187                     /* On the v850 the top 8 bits of an address are used by an overlay manager.
188                        Thus it may happen that when we are looking for a symbol to match
189                        against an address with some of its top bits set, the search fails to
190                        turn up an exact match.  In this case we try to find an exact match
191                        against a symbol in the lower address space, and if we find one, we
192                        use that address.   We only do this for JARL instructions however, as
193                        we do not want to misinterpret branch instructions.  */
194                     if (operand->bits == 22)
195                       {
196                         if ( ! info->symbol_at_address_func (addr, info)
197                             && ((addr & 0xFF000000) != 0)
198                             && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
199                           {
200                             addr &= 0x00FFFFFF;
201                           }
202                       }
203                     info->print_address_func (addr, info);
204                     break;
205                   }
206                     
207 /* start-sanitize-v850e */
208                 case V850E_PUSH_POP:
209                   {
210                     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 };
211                     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 };
212                     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 };
213                     int *             regs;
214                     int               i;
215                     unsigned long int mask = 0;
216                     int               pc   = false;
217                     int               sr   = false;
218                     
219                     
220                     switch (operand->shift)
221                       {
222                       case 0xffe00001: regs = list12_regs; break;
223                       case 0xfff8000f: regs = list18_h_regs; break;
224                       case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break;  /* Do not include magic bit */
225                       default:
226                         fprintf (stderr, "unknown operand shift: %x\n", operand->shift );                   
227                         abort();
228                       }
229
230                     for (i = 0; i < 32; i++)
231                       {
232                         if (value & (1 << i))
233                           {
234                             switch (regs[ i ])
235                               {
236                               default: mask |= (1 << regs[ i ]); break;
237                               case 0:  fprintf (stderr, "unknown pop reg: %d\n", i ); abort();
238                               case -1: pc = true; break;
239                               case -2: sr = true; 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 = false;
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 = true;
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 /* end-sanitize-v850e */
322                 }                 
323
324               /* Handle jmp correctly.  */
325               if (memop == 1 && opnum == 1
326                   && ((operand->flags & V850_OPERAND_REG) != 0))
327                 (*info->fprintf_func) (info->stream, "]");
328             }
329
330           /* Close any square bracket we left open.  */
331           if (memop && opnum == memop + 2)
332             (*info->fprintf_func) (info->stream, "]");
333
334           /* All done. */
335           break;
336         }
337       op++;
338     }
339
340   if (!match)
341     {
342       if (short_op)
343         info->fprintf_func (info->stream, ".short\t0x%04x", insn);
344       else
345         info->fprintf_func (info->stream, ".long\t0x%08x", insn);
346     }
347
348   return bytes_read;
349 }
350
351 int 
352 print_insn_v850 (memaddr, info)
353      bfd_vma memaddr;
354      struct disassemble_info * info;
355 {
356   int           status;
357   bfd_byte      buffer[ 4 ];
358   unsigned long insn;
359
360   /* First figure out how big the opcode is.  */
361   
362   status = info->read_memory_func (memaddr, buffer, 2, info);
363   if (status == 0)
364     {
365       insn = bfd_getl16 (buffer);
366       
367       if (   (insn & 0x0600) == 0x0600
368           && (insn & 0xffe0) != 0x0620)
369         {
370           /* If this is a 4 byte insn, read 4 bytes of stuff.  */
371           status = info->read_memory_func (memaddr, buffer, 4, info);
372
373           if (status == 0)
374             insn = bfd_getl32 (buffer);
375         }
376     }
377   
378   if (status != 0)
379     {
380       info->memory_error_func (status, memaddr, info);
381       return -1;
382     }
383
384   /* Make sure we tell our caller how many bytes we consumed.  */
385   return disassemble (memaddr, info, insn);
386 }