Only look for two parallel instructions when we are at a 32 bit boundary
[external/binutils.git] / opcodes / m32r-dis.c
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 This file is used to generate m32r-dis.c.
5
6 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
7
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23
24 #include "sysdep.h"
25 #include <stdio.h>
26 #include "ansidecl.h"
27 #include "dis-asm.h"
28 #include "bfd.h"
29 #include "m32r-opc.h"
30
31 /* ??? The layout of this stuff is still work in progress.
32    For speed in assembly/disassembly, we use inline functions.  That of course
33    will only work for GCC.  When this stuff is finished, we can decide whether
34    to keep the inline functions (and only get the performance increase when
35    compiled with GCC), or switch to macros, or use something else.
36 */
37
38 /* Default text to print if an instruction isn't recognized.  */
39 #define UNKNOWN_INSN_MSG "*unknown*"
40
41 /* FIXME: Machine generate.  */
42 #ifndef CGEN_PCREL_OFFSET
43 #define CGEN_PCREL_OFFSET 0
44 #endif
45
46 static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int));
47
48 static int extract_insn_normal
49      PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *));
50 static void print_insn_normal
51      PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int));
52
53 CGEN_INLINE void
54 m32r_cgen_print_operand
55      PARAMS ((int opindex, disassemble_info * info, CGEN_FIELDS * fields, void const * attrs, bfd_vma pc, int length));
56
57 \f
58 /* Default extraction routine.
59
60    ATTRS is a mask of the boolean attributes.  We only need `unsigned',
61    but for generality we take a bitmask of all of them.  */
62
63 static int
64 extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
65      void *       buf_ctrl;
66      cgen_insn_t  insn_value;
67      unsigned int attrs;
68      int          start;
69      int          length;
70      int          shift;
71      int          total_length;
72      long *       valuep;
73 {
74   long value;
75
76 #ifdef CGEN_INT_INSN
77 #if 0
78   value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length)))
79            & ((1 << length) - 1));
80 #else
81   value = ((insn_value >> (total_length - (start + length)))
82            & ((1 << length) - 1));
83 #endif
84   if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
85       && (value & (1 << (length - 1))))
86     value -= 1 << length;
87 #else
88   /* FIXME: unfinished */
89 #endif
90
91   /* This is backwards as we undo the effects of insert_normal.  */
92   if (shift < 0)
93     value >>= -shift;
94   else
95     value <<= shift;
96
97   * valuep = value;
98   return 1;
99 }
100
101 /* Default print handler.  */
102
103 static void
104 print_normal (dis_info, value, attrs, pc, length)
105      void *        dis_info;
106      long          value;
107      unsigned int  attrs;
108      unsigned long pc; /* FIXME: should be bfd_vma */
109      int           length;
110 {
111   disassemble_info * info = dis_info;
112
113   /* Print the operand as directed by the attributes.  */
114   if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_FAKE))
115     ; /* nothing to do (??? at least not yet) */
116   else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR))
117     (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info);
118   /* ??? Not all cases of this are currently caught.  */
119   else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR))
120     /* FIXME: Why & 0xffffffff?  */
121     (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
122   else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
123     (*info->fprintf_func) (info->stream, "0x%lx", value);
124   else
125     (*info->fprintf_func) (info->stream, "%ld", value);
126 }
127
128 /* Keyword print handler.  */
129
130 static void
131 print_keyword (dis_info, keyword_table, value, attrs)
132      void *         dis_info;
133      CGEN_KEYWORD * keyword_table;
134      long           value;
135      CGEN_ATTR *    attrs;
136 {
137   disassemble_info * info = dis_info;
138   const CGEN_KEYWORD_ENTRY * ke;
139
140   ke = cgen_keyword_lookup_value (keyword_table, value);
141   info->fprintf_func (info->stream, "%s", ke == NULL ? "???" : ke->name);
142 }
143 \f
144 /* -- disassembler routines inserted here */
145 \f
146 /* Default insn extractor.
147
148    The extracted fields are stored in DIS_FLDS.
149    BUF_CTRL is used to handle reading variable length insns (FIXME: not done).
150    Return the length of the insn in bits, or 0 if no match.  */
151
152 static int
153 extract_insn_normal (insn, buf_ctrl, insn_value, fields)
154      const CGEN_INSN *  insn;
155      void *             buf_ctrl;
156      cgen_insn_t        insn_value;
157      CGEN_FIELDS *      fields;
158 {
159   const CGEN_SYNTAX *   syntax = CGEN_INSN_SYNTAX (insn);
160   const unsigned char * syn;
161
162   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
163
164   CGEN_INIT_EXTRACT ();
165
166   for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
167     {
168       int length;
169
170       if (CGEN_SYNTAX_CHAR_P (* syn))
171         continue;
172
173       length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (* syn),
174                                            buf_ctrl, insn_value, fields);
175       if (length == 0)
176         return 0;
177     }
178
179   /* We recognized and successfully extracted this insn.  */
180   return CGEN_INSN_BITSIZE (insn);
181 }
182
183 /* Default insn printer.
184
185    DIS_INFO is defined as `void *' so the disassembler needn't know anything
186    about disassemble_info.
187 */
188
189 static void
190 print_insn_normal (dis_info, insn, fields, pc, length)
191      void *             dis_info;
192      const CGEN_INSN *  insn;
193      CGEN_FIELDS *      fields;
194      bfd_vma            pc;
195      int                length;
196 {
197   const CGEN_SYNTAX *   syntax = CGEN_INSN_SYNTAX (insn);
198   disassemble_info *    info = dis_info;
199   const unsigned char * syn;
200
201   CGEN_INIT_PRINT ();
202
203   for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
204     {
205       if (CGEN_SYNTAX_MNEMONIC_P (* syn))
206         {
207           info->fprintf_func (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
208           continue;
209         }
210       if (CGEN_SYNTAX_CHAR_P (* syn))
211         {
212           info->fprintf_func (info->stream, "%c", CGEN_SYNTAX_CHAR (* syn));
213           continue;
214         }
215
216       /* We have an operand.  */
217       m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (* syn), info,
218                                 fields, CGEN_INSN_ATTRS (insn), pc, length);
219     }
220 }
221 \f
222 /* Default value for CGEN_PRINT_INSN.
223    Given BUFLEN bytes (target byte order) read into BUF, look up the
224    insn in the instruction table and disassemble it.
225
226    The result is the size of the insn in bytes.  */
227
228 #ifndef CGEN_PRINT_INSN
229 #define CGEN_PRINT_INSN print_insn
230 #endif
231
232 static int
233 print_insn (pc, info, buf, buflen)
234      bfd_vma            pc;
235      disassemble_info * info;
236      char *             buf;
237      int                buflen;
238 {
239   int                    i;
240   unsigned long          insn_value;
241   const CGEN_INSN_LIST * insn_list;
242   int                    extra_bytes;
243   
244   switch (buflen)
245     {
246     case 8:
247       insn_value = buf[0];
248       break;
249     case 16:
250       insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
251       break;
252     case 32:
253       insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
254       break;
255     default:
256       abort ();
257     }
258
259   /* Special case - a 32 bit instruction which is actually two 16 bit instructions
260      being executed in parallel.  */
261   if (buflen == 32
262       && (pc & 0x3) == 0
263       && ((insn_value & 0x80008000) == 0x00008000))
264     {
265       if (info->endian == BFD_ENDIAN_BIG)
266         {
267           static char buf2 [4];
268           
269           print_insn (pc, info, buf, 16);
270
271           info->fprintf_func (info->stream, " || ");
272
273           buf2 [0] = buf [2] & ~ 0x80;
274           buf2 [1] = buf [3];
275           buf2 [2] = 0;
276           buf2 [3] = 0;
277           buf = buf2;
278           
279           insn_value <<= 17;
280           insn_value >>= 1;
281         }
282       else
283         {
284           print_insn (pc, info, buf + 2, 16);
285
286           info->fprintf_func (info->stream, " || ");
287
288           insn_value &= 0x7fff;
289         }
290
291       pc += 2;
292       extra_bytes = 2;
293     }
294   else
295     extra_bytes = 0;
296   
297   /* The instructions are stored in hash lists.
298      Pick the first one and keep trying until we find the right one.  */
299
300   insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value);
301
302   while (insn_list != NULL)
303     {
304       const CGEN_INSN *   insn = insn_list->insn;
305       unsigned long       value;
306
307 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
308       /* Supported by this cpu?  */
309       if (! m32r_cgen_insn_supported (insn))
310         continue;
311 #endif
312
313       /* If we are looking at a 16 bit insn we may have to adjust the value being examined.  */
314       value = insn_value;
315       if (CGEN_INSN_BITSIZE (insn) == 16)
316         {
317         /* If this is a big endian target,
318            and we have read 32 bits for the instruction value,
319            then we must examine the top 16 bits, not the bottom.  */
320           if (buflen == 32 && info->endian == BFD_ENDIAN_BIG)
321             value >>= 16;
322         }
323       
324       /* Basic bit mask must be correct.  */
325       /* ??? May wish to allow target to defer this check until the extract
326          handler.  */
327       if ((value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
328         {
329           CGEN_FIELDS fields;
330           int         length;
331           
332           /* Printing is handled in two passes.  The first pass parses the
333              machine insn and extracts the fields.  The second pass prints
334              them.  */
335
336           length = CGEN_EXTRACT_FN (insn) (insn, NULL, value, & fields);
337           if (length > 0)
338             {
339               CGEN_PRINT_FN (insn) (info, insn, & fields, pc, length);
340               
341               /* length is in bits, result is in bytes */
342               return (length / 8) + extra_bytes;
343             }
344         }
345       
346       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
347     }
348
349   return extra_bytes;
350 }
351
352 /* Main entry point.
353    Print one instruction from PC on INFO->STREAM.
354    Return the size of the instruction (in bytes).  */
355
356 int
357 print_insn_m32r (pc, info)
358      bfd_vma            pc;
359      disassemble_info * info;
360 {
361   char       buffer [CGEN_MAX_INSN_SIZE];
362   int        status;
363   int        length;
364   static int initialized    = 0;
365   static int current_mach   = 0;
366   static int current_bigend = 0;
367   int        mach           = info->mach;
368   int        bigend         = info->endian == BFD_ENDIAN_BIG;
369
370   /* If we haven't initialized yet, or if we've switched cpu's, initialize.  */
371   if (!initialized || mach != current_mach || bigend != current_bigend)
372     {
373       initialized    = 1;
374       current_mach   = mach;
375       current_bigend = bigend;
376       
377       m32r_cgen_init_dis (mach, bigend ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
378     }
379
380   /* Read enough of the insn so we can look it up in the hash lists.  */
381
382   status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE, info);
383   if (status != 0)
384     {
385       /* Try reading a 16 bit instruction.  */
386       info->bytes_per_chunk = 2;
387       status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE / 2, info);
388       buffer [2] = buffer [3] = 0;
389     }
390   if (status != 0)
391     {
392       info->memory_error_func (status, pc, info);
393       return -1;
394     }
395
396   /* We try to have as much common code as possible.
397      But at this point some targets need to take over.  */
398   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
399      but if not possible try to move this hook elsewhere rather than
400      have two hooks.  */
401   length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
402   
403   if (length)
404     return length;
405
406   info->fprintf_func (info->stream, UNKNOWN_INSN_MSG);
407   
408   return CGEN_DEFAULT_INSN_SIZE;
409 }
410
411 /* Get the generate machine specific code.  */
412 #include "m32r-dis.in"