Fixed disassembler to use processor type when decoding instructions.
[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   "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23", 
35   "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
36
37 static const char *const v850_cc_names[] =
38 { "v", "c/l", "z", "nh", "s/n", "t", "lt", "le", 
39   "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
40
41 static int
42 disassemble (memaddr, info, insn)
43      bfd_vma memaddr;
44      struct disassemble_info *info;
45      unsigned long insn;
46 {
47   struct v850_opcode *          op = (struct v850_opcode *)v850_opcodes;
48   const struct v850_operand *   operand;
49   int                           match = 0;
50   int                           short_op = ((insn & 0x0600) != 0x0600);
51   int                           bytes_read;
52   int                           target_processor;
53   
54 /* start-sanitize-v850e */
55   /* Special case: 32 bit MOV */
56   if ((insn & 0xffe0) == 0x0620)
57     short_op = true;
58 /* end-sanitize-v850e */
59   
60   bytes_read = short_op ? 2 : 4;
61   
62   /* If this is a two byte insn, then mask off the high bits. */
63   if (short_op)
64     insn &= 0xffff;
65
66   switch (info->mach)
67     {
68     case 0:
69     default:
70       target_processor = PROCESSOR_V850;
71       break;
72
73 /* start-sanitize-v850e */
74     case bfd_mach_v850e:
75       target_processor = PROCESSOR_V850E;
76       break;
77
78     case bfd_mach_v850eq: 
79       target_processor = PROCESSOR_V850EQ;
80       break;
81 /* end-sanitize-v850e */
82     }
83   
84   /* Find the opcode.  */
85   while (op->name)
86     {
87       if ((op->mask & insn) == op->opcode
88           && (op->processors & target_processor))
89         {
90           const unsigned char * opindex_ptr;
91           unsigned int          opnum;
92           unsigned int          memop;
93
94           match = 1;
95           (*info->fprintf_func) (info->stream, "%s\t", op->name);
96 //fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, op->name );
97
98           memop = op->memop;
99           /* Now print the operands.
100
101              MEMOP is the operand number at which a memory
102              address specification starts, or zero if this
103              instruction has no memory addresses.
104
105              A memory address is always two arguments.
106
107              This information allows us to determine when to
108              insert commas into the output stream as well as
109              when to insert disp[reg] expressions onto the
110              output stream.  */
111           
112           for (opindex_ptr = op->operands, opnum = 1;
113                *opindex_ptr != 0;
114                opindex_ptr++, opnum++)
115             {
116               long      value;
117               int       flag;
118               int       status;
119               bfd_byte  buffer[ 4 ];
120               
121               operand = &v850_operands[*opindex_ptr];
122               
123               if (operand->extract)
124                 value = (operand->extract) (insn, 0);
125               else
126                 {
127                   if (operand->bits == -1)
128                     value = (insn & operand->shift);
129                   else
130                     value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
131
132                   if (operand->flags & V850_OPERAND_SIGNED)
133                     value = ((long)(value << (32 - operand->bits))
134                              >> (32 - operand->bits));
135                 }
136
137               /* The first operand is always output without any
138                  special handling.
139
140                  For the following arguments:
141
142                    If memop && opnum == memop + 1, then we need '[' since
143                    we're about to output the register used in a memory
144                    reference.
145
146                    If memop && opnum == memop + 2, then we need ']' since
147                    we just finished the register in a memory reference.  We
148                    also need a ',' before this operand.
149
150                    Else we just need a comma.
151
152                    We may need to output a trailing ']' if the last operand
153                    in an instruction is the register for a memory address. 
154
155                    The exception (and there's always an exception) is the
156                    "jmp" insn which needs square brackets around it's only
157                    register argument.  */
158
159                    if (memop && opnum == memop + 1) info->fprintf_func (info->stream, "[");
160               else if (memop && opnum == memop + 2) info->fprintf_func (info->stream, "],");
161               else if (memop == 1 && opnum == 1
162                        && (operand->flags & V850_OPERAND_REG))
163                                                     info->fprintf_func (info->stream, "[");
164               else if (opnum > 1)                   info->fprintf_func (info->stream, ", ");
165
166               /* extract the flags, ignorng ones which do not effect disassembly output. */
167               flag = operand->flags;
168               flag &= ~ V850_OPERAND_SIGNED;
169               flag &= ~ V850_OPERAND_RELAX;
170               flag &= - flag;
171               
172               switch (flag)
173                 {
174                 case V850_OPERAND_REG:  info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
175                 case V850_OPERAND_SRG:  info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
176                 case V850_OPERAND_CC:   info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
177                 case V850_OPERAND_EP:   info->fprintf_func (info->stream, "ep"); break;
178                 case V850_OPERAND_DISP: info->print_address_func (value + memaddr, info); break;
179                 default:                info->fprintf_func (info->stream, "%d", value); break;
180 /* start-sanitize-v850e */
181                 case V850E_PUSH_POP:
182                   {
183                     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 };
184                     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 };
185                     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 };
186                     int *             regs;
187                     int               i;
188                     unsigned long int mask = 0;
189                     int               pc   = false;
190                     int               sr   = false;
191                     
192                     
193                     switch (operand->shift)
194                       {
195                       case 0xffe00001: regs = list12_regs; break;
196                       case 0xfff8000f: regs = list18_h_regs; break;
197                       case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break;  /* Do not include magic bit */
198                       default:
199                         fprintf (stderr, "unknown operand shift: %x\n", operand->shift );                   
200                         abort();
201                       }
202
203                     for (i = 0; i < 32; i++)
204                       {
205                         if (value & (1 << i))
206                           {
207                             switch (regs[ i ])
208                               {
209                               default: mask |= (1 << regs[ i ]); break;
210                               case 0:  fprintf (stderr, "unknown pop reg: %d\n", i ); abort();
211                               case -1: pc = true; break;
212                               case -2: sr = true; break;
213                               }
214                           }
215                       }
216
217                     info->fprintf_func (info->stream, "{");
218                     
219                     if (mask || pc || sr)
220                       {
221                         if (mask)
222                           {
223                             unsigned int bit;
224                             int          shown_one = false;
225                             
226                             for (bit = 0; bit < 32; bit++)
227                               if (mask & (1 << bit))
228                                 {
229                                   unsigned long int first = bit;
230                                   unsigned long int last;
231
232                                   if (shown_one)
233                                     info->fprintf_func (info->stream, ", ");
234                                   else
235                                     shown_one = true;
236                                   
237                                   info->fprintf_func (info->stream, v850_reg_names[first]);
238                                   
239                                   for (bit++; bit < 32; bit++)
240                                     if ((mask & (1 << bit)) == 0)
241                                       break;
242
243                                   last = bit;
244
245                                   if (last > first + 1)
246                                     {
247                                       info->fprintf_func (info->stream, " - %s", v850_reg_names[ last - 1 ]);
248                                     }
249                                 }
250                           }
251                         
252                         if (pc)
253                           info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
254                         if (sr)
255                           info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
256                       }
257                     
258                     info->fprintf_func (info->stream, "}");
259                   }
260                 break;
261                   
262                 case V850E_IMMEDIATE16:
263                   status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
264                   if (status == 0)
265                     {
266                       bytes_read += 2;
267                       value = bfd_getl16 (buffer);
268
269                       /* If this is a DISPOSE instruction with ff set to 0x10, then shift value up by 16.  */
270                       if ((insn & 0x001fffc0) == 0x00130780)
271                         value <<= 16;
272
273                       info->fprintf_func (info->stream, "0x%x", value);
274                     }
275                   else
276                     {
277                       info->memory_error_func (status, memaddr + bytes_read, info);
278                     }
279                   break;
280                   
281                 case V850E_IMMEDIATE32:
282                   status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
283                   if (status == 0)
284                     {
285                       bytes_read += 4;
286                       value = bfd_getl32 (buffer);
287                       info->fprintf_func (info->stream, "0x%lx", value);
288                     }
289                   else
290                     {
291                       info->memory_error_func (status, memaddr + bytes_read, info);
292                     }
293                   break;
294 /* end-sanitize-v850e */
295                 }                 
296
297               /* Handle jmp correctly.  */
298               if (memop == 1 && opnum == 1
299                   && ((operand->flags & V850_OPERAND_REG) != 0))
300                 (*info->fprintf_func) (info->stream, "]");
301             }
302
303           /* Close any square bracket we left open.  */
304           if (memop && opnum == memop + 2)
305             (*info->fprintf_func) (info->stream, "]");
306
307           /* All done. */
308           break;
309         }
310       op++;
311     }
312
313   if (!match)
314     {
315       if (short_op)
316         info->fprintf_func (info->stream, ".short\t0x%04x", insn);
317       else
318         info->fprintf_func (info->stream, ".long\t0x%08x", insn);
319     }
320
321   return bytes_read;
322 }
323
324 int 
325 print_insn_v850 (memaddr, info)
326      bfd_vma memaddr;
327      struct disassemble_info * info;
328 {
329   int           status;
330   bfd_byte      buffer[ 4 ];
331   unsigned long insn;
332
333   /* First figure out how big the opcode is.  */
334   
335   status = info->read_memory_func (memaddr, buffer, 2, info);
336   if (status == 0)
337     {
338       insn = bfd_getl16 (buffer);
339       
340       if (   (insn & 0x0600) == 0x0600
341           && (insn & 0xffe0) != 0x0620)
342         {
343           /* If this is a 4 byte insn, read 4 bytes of stuff.  */
344           status = info->read_memory_func (memaddr, buffer, 4, info);
345
346           if (status == 0)
347             insn = bfd_getl32 (buffer);
348         }
349     }
350   
351   if (status != 0)
352     {
353       info->memory_error_func (status, memaddr, info);
354       return -1;
355     }
356
357   /* Make sure we tell our caller how many bytes we consumed.  */
358   return disassemble (memaddr, info, insn);
359 }
360
361