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