Only look for two parallel instructions when we are at a 32 bit boundary
[deliverable/binutils-gdb.git] / opcodes / m32r-dis.c
CommitLineData
9c03036a
DE
1/* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4This file is used to generate m32r-dis.c.
5
6Copyright (C) 1996, 1997 Free Software Foundation, Inc.
7
8This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10This program is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2, or (at your option)
13any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
23cf992f 24#include "sysdep.h"
9c03036a
DE
25#include <stdio.h>
26#include "ansidecl.h"
27#include "dis-asm.h"
9c03036a 28#include "bfd.h"
23cf992f 29#include "m32r-opc.h"
9c03036a
DE
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
46static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int));
47
48static int extract_insn_normal
23cf992f 49 PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *));
9c03036a 50static void print_insn_normal
23cf992f
NC
51 PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int));
52
53CGEN_INLINE void
54m32r_cgen_print_operand
55 PARAMS ((int opindex, disassemble_info * info, CGEN_FIELDS * fields, void const * attrs, bfd_vma pc, int length));
56
9c03036a
DE
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
63static int
64extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
23cf992f
NC
65 void * buf_ctrl;
66 cgen_insn_t insn_value;
9c03036a 67 unsigned int attrs;
23cf992f
NC
68 int start;
69 int length;
70 int shift;
71 int total_length;
72 long * valuep;
9c03036a
DE
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
23cf992f 97 * valuep = value;
9c03036a
DE
98 return 1;
99}
100
101/* Default print handler. */
102
103static void
104print_normal (dis_info, value, attrs, pc, length)
23cf992f
NC
105 void * dis_info;
106 long value;
107 unsigned int attrs;
9c03036a 108 unsigned long pc; /* FIXME: should be bfd_vma */
23cf992f 109 int length;
9c03036a 110{
23cf992f 111 disassemble_info * info = dis_info;
9c03036a
DE
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
130static void
131print_keyword (dis_info, keyword_table, value, attrs)
23cf992f
NC
132 void * dis_info;
133 CGEN_KEYWORD * keyword_table;
134 long value;
135 CGEN_ATTR * attrs;
9c03036a 136{
23cf992f
NC
137 disassemble_info * info = dis_info;
138 const CGEN_KEYWORD_ENTRY * ke;
9c03036a
DE
139
140 ke = cgen_keyword_lookup_value (keyword_table, value);
23cf992f 141 info->fprintf_func (info->stream, "%s", ke == NULL ? "???" : ke->name);
9c03036a
DE
142}
143\f
144/* -- disassembler routines inserted here */
9c03036a
DE
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
152static int
153extract_insn_normal (insn, buf_ctrl, insn_value, fields)
23cf992f
NC
154 const CGEN_INSN * insn;
155 void * buf_ctrl;
156 cgen_insn_t insn_value;
157 CGEN_FIELDS * fields;
9c03036a 158{
23cf992f
NC
159 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
160 const unsigned char * syn;
9c03036a 161
9c03036a
DE
162 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
163
164 CGEN_INIT_EXTRACT ();
165
23cf992f 166 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
9c03036a
DE
167 {
168 int length;
169
23cf992f 170 if (CGEN_SYNTAX_CHAR_P (* syn))
9c03036a
DE
171 continue;
172
23cf992f 173 length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (* syn),
9c03036a
DE
174 buf_ctrl, insn_value, fields);
175 if (length == 0)
176 return 0;
177 }
178
23cf992f
NC
179 /* We recognized and successfully extracted this insn. */
180 return CGEN_INSN_BITSIZE (insn);
9c03036a
DE
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
189static void
190print_insn_normal (dis_info, insn, fields, pc, length)
23cf992f
NC
191 void * dis_info;
192 const CGEN_INSN * insn;
193 CGEN_FIELDS * fields;
194 bfd_vma pc;
195 int length;
9c03036a 196{
23cf992f
NC
197 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
198 disassemble_info * info = dis_info;
199 const unsigned char * syn;
9c03036a
DE
200
201 CGEN_INIT_PRINT ();
202
23cf992f 203 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
9c03036a 204 {
23cf992f
NC
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))
9c03036a 211 {
23cf992f 212 info->fprintf_func (info->stream, "%c", CGEN_SYNTAX_CHAR (* syn));
9c03036a
DE
213 continue;
214 }
215
216 /* We have an operand. */
23cf992f 217 m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (* syn), info,
9c03036a
DE
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
232static int
233print_insn (pc, info, buf, buflen)
23cf992f
NC
234 bfd_vma pc;
235 disassemble_info * info;
236 char * buf;
237 int buflen;
9c03036a 238{
23cf992f
NC
239 int i;
240 unsigned long insn_value;
241 const CGEN_INSN_LIST * insn_list;
242 int extra_bytes;
243
9c03036a
DE
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
23cf992f
NC
259 /* Special case - a 32 bit instruction which is actually two 16 bit instructions
260 being executed in parallel. */
261 if (buflen == 32
0d0bb914 262 && (pc & 0x3) == 0
23cf992f
NC
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
9c03036a
DE
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);
23cf992f 301
9c03036a
DE
302 while (insn_list != NULL)
303 {
23cf992f
NC
304 const CGEN_INSN * insn = insn_list->insn;
305 unsigned long value;
9c03036a
DE
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
23cf992f
NC
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
9c03036a
DE
324 /* Basic bit mask must be correct. */
325 /* ??? May wish to allow target to defer this check until the extract
326 handler. */
23cf992f 327 if ((value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
9c03036a 328 {
23cf992f
NC
329 CGEN_FIELDS fields;
330 int length;
331
9c03036a
DE
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
23cf992f 336 length = CGEN_EXTRACT_FN (insn) (insn, NULL, value, & fields);
9c03036a
DE
337 if (length > 0)
338 {
23cf992f
NC
339 CGEN_PRINT_FN (insn) (info, insn, & fields, pc, length);
340
9c03036a 341 /* length is in bits, result is in bytes */
23cf992f 342 return (length / 8) + extra_bytes;
9c03036a
DE
343 }
344 }
23cf992f 345
9c03036a
DE
346 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
347 }
348
23cf992f 349 return extra_bytes;
9c03036a
DE
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
356int
357print_insn_m32r (pc, info)
23cf992f
NC
358 bfd_vma pc;
359 disassemble_info * info;
9c03036a 360{
23cf992f
NC
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;
9c03036a
DE
369
370 /* If we haven't initialized yet, or if we've switched cpu's, initialize. */
23cf992f 371 if (!initialized || mach != current_mach || bigend != current_bigend)
9c03036a 372 {
23cf992f
NC
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);
9c03036a
DE
378 }
379
380 /* Read enough of the insn so we can look it up in the hash lists. */
381
23cf992f 382 status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE, info);
9c03036a
DE
383 if (status != 0)
384 {
23cf992f
NC
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);
9c03036a
DE
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,
23cf992f 399 but if not possible try to move this hook elsewhere rather than
9c03036a
DE
400 have two hooks. */
401 length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
23cf992f 402
9c03036a
DE
403 if (length)
404 return length;
405
23cf992f
NC
406 info->fprintf_func (info->stream, UNKNOWN_INSN_MSG);
407
9c03036a
DE
408 return CGEN_DEFAULT_INSN_SIZE;
409}
23cf992f
NC
410
411/* Get the generate machine specific code. */
412#include "m32r-dis.in"
This page took 0.073184 seconds and 4 git commands to generate.