Removed use of V850_OPERNAD_ADJUST_SHORT_MEMORY.
[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                     int        shown_one = false;
170                     
171                     switch (operand->shift)
172                       {
173                       case 0xffe00001: regs = list12_regs; break;
174 /* start-sanitize-v850eq */
175                       case 0xfff8000f: regs = list18_h_regs; break;
176                       case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break;  /* Do not include magic bit */
177 /* end-sanitize-v850eq */
178                       default:
179                         fprintf (stderr, "unknown operand shift: %x\n", operand->shift );                   
180                         abort();
181                       }
182
183                     info->fprintf_func (info->stream, "{");
184                     for (i = 0; i < 32; i++)
185                       {
186                         if (value & (1 << i))
187                           {
188                             if (shown_one)
189                               info->fprintf_func (info->stream, ",");
190                             else
191                               shown_one = true;
192                               
193                             switch (regs[ i ])
194                               {
195                               default: info->fprintf_func (info->stream, "%s", v850_reg_names[regs[ i ]]); break;
196 /* start-sanitize-v850eq */
197                               case 0:  fprintf (stderr, "unknown pop reg: %d\n", i ); abort();
198                               case -1: info->fprintf_func (info->stream, "PC "); break;
199                               case -2: info->fprintf_func (info->stream, "SR"); break;
200 /* end-sanitize-v850eq */
201                               }
202                           }
203                       }
204                     info->fprintf_func (info->stream, "}");
205                   }
206                 break;
207                   
208                 case V850E_IMMEDIATE16:
209                   status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
210                   if (status == 0)
211                     {
212                       bytes_read += 2;
213                       value = bfd_getl16 (buffer);
214
215                       /* If this is a DISPOSE instruction with ff set to 0x10, then shift value up by 16.  */
216                       if ((insn & 0x001fffc0) == 0x00130780)
217                         value <<= 16;
218
219                       info->fprintf_func (info->stream, "0x%x", value);
220                     }
221                   else
222                     {
223                       info->memory_error_func (status, memaddr + bytes_read, info);
224                     }
225                   break;
226                   
227                 case V850E_IMMEDIATE32:
228                   status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
229                   if (status == 0)
230                     {
231                       bytes_read += 4;
232                       value = bfd_getl32 (buffer);
233                       info->fprintf_func (info->stream, "0x%lx", value);
234                     }
235                   else
236                     {
237                       info->memory_error_func (status, memaddr + bytes_read, info);
238                     }
239                   break;
240 /* end-sanitize-v850e */
241                 }                 
242
243               /* Handle jmp correctly.  */
244               if (memop == 1 && opnum == 1
245                   && ((operand->flags & V850_OPERAND_REG) != 0))
246                 (*info->fprintf_func) (info->stream, "]");
247             }
248
249           /* Close any square bracket we left open.  */
250           if (memop && opnum == memop + 2)
251             (*info->fprintf_func) (info->stream, "]");
252
253           /* All done. */
254           break;
255         }
256       op++;
257     }
258
259   if (!match)
260     {
261       if (short_op)
262         info->fprintf_func (info->stream, ".short\t0x%04x", insn);
263       else
264         info->fprintf_func (info->stream, ".long\t0x%08x", insn);
265     }
266
267   return bytes_read;
268 }
269
270 int 
271 print_insn_v850 (memaddr, info)
272      bfd_vma memaddr;
273      struct disassemble_info * info;
274 {
275   int           status;
276   bfd_byte      buffer[ 4 ];
277   unsigned long insn;
278
279   /* First figure out how big the opcode is.  */
280   
281   status = info->read_memory_func (memaddr, buffer, 2, info);
282   if (status == 0)
283     {
284       insn = bfd_getl16 (buffer);
285       
286       if (   (insn & 0x0600) == 0x0600
287           && (insn & 0xffe0) != 0x0620)
288         {
289           /* If this is a 4 byte insn, read 4 bytes of stuff.  */
290           status = info->read_memory_func (memaddr, buffer, 4, info);
291
292           if (status == 0)
293             insn = bfd_getl32 (buffer);
294         }
295     }
296   
297   if (status != 0)
298     {
299       info->memory_error_func (status, memaddr, info);
300       return -1;
301     }
302
303   /* Make sure we tell our caller how many bytes we consumed.  */
304   return disassemble (memaddr, info, insn);
305 }
306
307