]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/m32r-dis.c
* m32r-asm.c, m32r-dis.c, m32r-opc.c, m32r-opc.h: New files.
[thirdparty/binutils-gdb.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 <stdio.h>
25 #include "ansidecl.h"
26 #include "dis-asm.h"
27 #include "m32r-opc.h"
28 #include "bfd.h"
29
30 /* ??? The layout of this stuff is still work in progress.
31 For speed in assembly/disassembly, we use inline functions. That of course
32 will only work for GCC. When this stuff is finished, we can decide whether
33 to keep the inline functions (and only get the performance increase when
34 compiled with GCC), or switch to macros, or use something else.
35 */
36
37 /* Default text to print if an instruction isn't recognized. */
38 #define UNKNOWN_INSN_MSG "*unknown*"
39
40 /* FIXME: Machine generate. */
41 #ifndef CGEN_PCREL_OFFSET
42 #define CGEN_PCREL_OFFSET 0
43 #endif
44
45 static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int));
46
47 static int extract_insn_normal
48 PARAMS ((const struct cgen_insn *, void *, cgen_insn_t, struct cgen_fields *));
49 static void print_insn_normal
50 PARAMS ((void *, const struct cgen_insn *, struct cgen_fields *, bfd_vma, int));
51 \f
52 /* Default extraction routine.
53
54 ATTRS is a mask of the boolean attributes. We only need `unsigned',
55 but for generality we take a bitmask of all of them. */
56
57 static int
58 extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
59 void *buf_ctrl;
60 cgen_insn_t insn_value;
61 unsigned int attrs;
62 int start, length, shift, total_length;
63 long *valuep;
64 {
65 long value;
66
67 #ifdef CGEN_INT_INSN
68 #if 0
69 value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length)))
70 & ((1 << length) - 1));
71 #else
72 value = ((insn_value >> (total_length - (start + length)))
73 & ((1 << length) - 1));
74 #endif
75 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
76 && (value & (1 << (length - 1))))
77 value -= 1 << length;
78 #else
79 /* FIXME: unfinished */
80 #endif
81
82 /* This is backwards as we undo the effects of insert_normal. */
83 if (shift < 0)
84 value >>= -shift;
85 else
86 value <<= shift;
87
88 *valuep = value;
89 return 1;
90 }
91
92 /* Default print handler. */
93
94 static void
95 print_normal (dis_info, value, attrs, pc, length)
96 void *dis_info;
97 long value;
98 unsigned int attrs;
99 unsigned long pc; /* FIXME: should be bfd_vma */
100 int length;
101 {
102 disassemble_info *info = dis_info;
103
104 /* Print the operand as directed by the attributes. */
105 if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_FAKE))
106 ; /* nothing to do (??? at least not yet) */
107 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR))
108 (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info);
109 /* ??? Not all cases of this are currently caught. */
110 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR))
111 /* FIXME: Why & 0xffffffff? */
112 (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
113 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
114 (*info->fprintf_func) (info->stream, "0x%lx", value);
115 else
116 (*info->fprintf_func) (info->stream, "%ld", value);
117 }
118
119 /* Keyword print handler. */
120
121 static void
122 print_keyword (dis_info, keyword_table, value, attrs)
123 void *dis_info;
124 struct cgen_keyword *keyword_table;
125 long value;
126 CGEN_ATTR *attrs;
127 {
128 disassemble_info *info = dis_info;
129 const struct cgen_keyword_entry *ke;
130
131 ke = cgen_keyword_lookup_value (keyword_table, value);
132 if (ke != NULL)
133 (*info->fprintf_func) (info->stream, "%s", ke->name);
134 else
135 (*info->fprintf_func) (info->stream, "???");
136 }
137 \f
138 /* -- disassembler routines inserted here */
139 /* -- dis.c */
140
141 #undef CGEN_PRINT_INSN
142 #define CGEN_PRINT_INSN my_print_insn
143
144 static int
145 my_print_insn (pc, info, buf, buflen)
146 bfd_vma pc;
147 disassemble_info *info;
148 char *buf;
149 int buflen;
150 {
151 unsigned long insn_value;
152
153 /* 32 bit insn? */
154 if ((pc & 3) == 0 && (buf[0] & 0x80) != 0)
155 return print_insn (pc, info, buf, buflen);
156
157 /* Print the first insn. */
158 if ((pc & 3) == 0)
159 {
160 if (print_insn (pc, info, buf, 16) == 0)
161 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
162 buf += 2;
163 }
164
165 if (buf[0] & 0x80)
166 {
167 /* Parallel. */
168 (*info->fprintf_func) (info->stream, " || ");
169 buf[0] &= 0x7f;
170 }
171 else
172 (*info->fprintf_func) (info->stream, " -> ");
173
174 /* The "& 3" is to ensure the branch address is computed correctly
175 [if it is a branch]. */
176 if (print_insn (pc & ~ (bfd_vma) 3, info, buf, 16) == 0)
177 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
178
179 return (pc & 3) ? 2 : 4;
180 }
181
182 /* -- */
183
184 /* Main entry point for operand extraction.
185
186 This function is basically just a big switch statement. Earlier versions
187 used tables to look up the function to use, but
188 - if the table contains both assembler and disassembler functions then
189 the disassembler contains much of the assembler and vice-versa,
190 - there's a lot of inlining possibilities as things grow,
191 - using a switch statement avoids the function call overhead.
192
193 This function could be moved into `print_insn_normal', but keeping it
194 separate makes clear the interface between `print_insn_normal' and each of
195 the handlers.
196 */
197
198 CGEN_INLINE int
199 m32r_cgen_extract_operand (opindex, buf_ctrl, insn_value, fields)
200 int opindex;
201 void *buf_ctrl;
202 cgen_insn_t insn_value;
203 struct cgen_fields *fields;
204 {
205 int length;
206
207 switch (opindex)
208 {
209 case 0 :
210 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_r2);
211 break;
212 case 1 :
213 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_r1);
214 break;
215 case 2 :
216 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_r1);
217 break;
218 case 3 :
219 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_r2);
220 break;
221 case 4 :
222 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_r2);
223 break;
224 case 5 :
225 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_r1);
226 break;
227 case 6 :
228 length = extract_normal (NULL /*FIXME*/, insn_value, 0, 8, 8, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_simm8);
229 break;
230 case 7 :
231 length = extract_normal (NULL /*FIXME*/, insn_value, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_simm16);
232 break;
233 case 8 :
234 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_uimm4);
235 break;
236 case 9 :
237 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 11, 5, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_uimm5);
238 break;
239 case 10 :
240 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_uimm16);
241 break;
242 case 11 :
243 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_hi16);
244 break;
245 case 12 :
246 length = extract_normal (NULL /*FIXME*/, insn_value, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_simm16);
247 break;
248 case 13 :
249 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_uimm16);
250 break;
251 case 14 :
252 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR)|(1<<CGEN_OPERAND_UNSIGNED), 8, 24, 0, CGEN_FIELDS_BITSIZE (fields), &fields->f_uimm24);
253 break;
254 case 15 :
255 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 8, 8, 2, CGEN_FIELDS_BITSIZE (fields), &fields->f_disp8);
256 break;
257 case 16 :
258 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 16, 16, 2, CGEN_FIELDS_BITSIZE (fields), &fields->f_disp16);
259 break;
260 case 17 :
261 length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 8, 24, 2, CGEN_FIELDS_BITSIZE (fields), &fields->f_disp24);
262 break;
263
264 default :
265 fprintf (stderr, "Unrecognized field %d while decoding insn.\n",
266 opindex);
267 abort ();
268 }
269
270 return length;
271 }
272
273 /* Main entry point for printing operands.
274
275 This function is basically just a big switch statement. Earlier versions
276 used tables to look up the function to use, but
277 - if the table contains both assembler and disassembler functions then
278 the disassembler contains much of the assembler and vice-versa,
279 - there's a lot of inlining possibilities as things grow,
280 - using a switch statement avoids the function call overhead.
281
282 This function could be moved into `print_insn_normal', but keeping it
283 separate makes clear the interface between `print_insn_normal' and each of
284 the handlers.
285 */
286
287 CGEN_INLINE void
288 m32r_cgen_print_operand (opindex, info, fields, attrs, pc, length)
289 int opindex;
290 disassemble_info *info;
291 struct cgen_fields *fields;
292 int attrs;
293 bfd_vma pc;
294 int length;
295 {
296 switch (opindex)
297 {
298 case 0 :
299 print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED));
300 break;
301 case 1 :
302 print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED));
303 break;
304 case 2 :
305 print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED));
306 break;
307 case 3 :
308 print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED));
309 break;
310 case 4 :
311 print_keyword (info, & m32r_cgen_opval_h_cr, fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED));
312 break;
313 case 5 :
314 print_keyword (info, & m32r_cgen_opval_h_cr, fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED));
315 break;
316 case 6 :
317 print_normal (info, fields->f_simm8, 0, pc, length);
318 break;
319 case 7 :
320 print_normal (info, fields->f_simm16, 0, pc, length);
321 break;
322 case 8 :
323 print_normal (info, fields->f_uimm4, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
324 break;
325 case 9 :
326 print_normal (info, fields->f_uimm5, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
327 break;
328 case 10 :
329 print_normal (info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
330 break;
331 case 11 :
332 print_normal (info, fields->f_hi16, 0|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
333 break;
334 case 12 :
335 print_normal (info, fields->f_simm16, 0, pc, length);
336 break;
337 case 13 :
338 print_normal (info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
339 break;
340 case 14 :
341 print_normal (info, fields->f_uimm24, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
342 break;
343 case 15 :
344 print_normal (info, fields->f_disp8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
345 break;
346 case 16 :
347 print_normal (info, fields->f_disp16, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
348 break;
349 case 17 :
350 print_normal (info, fields->f_disp24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
351 break;
352
353 default :
354 fprintf (stderr, "Unrecognized field %d while printing insn.\n",
355 opindex);
356 abort ();
357 }
358 }
359
360 cgen_extract_fn *m32r_cgen_extract_handlers[] = {
361 0, /* default */
362 extract_insn_normal,
363 };
364
365 cgen_print_fn *m32r_cgen_print_handlers[] = {
366 0, /* default */
367 print_insn_normal,
368 };
369
370
371 void
372 m32r_cgen_init_dis (mach, endian)
373 int mach;
374 enum cgen_endian endian;
375 {
376 m32r_cgen_init_tables (mach);
377 cgen_set_cpu (& m32r_cgen_opcode_data, mach, endian);
378 cgen_dis_init ();
379 }
380
381 \f
382 /* Default insn extractor.
383
384 The extracted fields are stored in DIS_FLDS.
385 BUF_CTRL is used to handle reading variable length insns (FIXME: not done).
386 Return the length of the insn in bits, or 0 if no match. */
387
388 static int
389 extract_insn_normal (insn, buf_ctrl, insn_value, fields)
390 const struct cgen_insn *insn;
391 void *buf_ctrl;
392 cgen_insn_t insn_value;
393 struct cgen_fields *fields;
394 {
395 const struct cgen_syntax *syntax = CGEN_INSN_SYNTAX (insn);
396 const unsigned char *syn;
397
398 /* ??? Some of the operand extract routines need to know the insn length,
399 which might be computed as we go. Set a default value and it'll be
400 modified as necessary. */
401 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
402
403 CGEN_INIT_EXTRACT ();
404
405 for (syn = syntax->syntax; *syn; ++syn)
406 {
407 int length;
408
409 if (CGEN_SYNTAX_CHAR_P (*syn))
410 continue;
411
412 length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn),
413 buf_ctrl, insn_value, fields);
414 if (length == 0)
415 return 0;
416 }
417
418 /* We recognized and successfully extracted this insn.
419 If a length is recorded with this insn, it has a fixed length.
420 Otherwise we require the syntax string to have a fake operand which
421 sets the `length' field in `flds'. */
422 /* FIXME: wip */
423 if (syntax->length > 0)
424 return syntax->length;
425 return fields->length;
426 }
427
428 /* Default insn printer.
429
430 DIS_INFO is defined as `void *' so the disassembler needn't know anything
431 about disassemble_info.
432 */
433
434 static void
435 print_insn_normal (dis_info, insn, fields, pc, length)
436 void *dis_info;
437 const struct cgen_insn *insn;
438 struct cgen_fields *fields;
439 bfd_vma pc;
440 int length;
441 {
442 const struct cgen_syntax *syntax = CGEN_INSN_SYNTAX (insn);
443 disassemble_info *info = dis_info;
444 const unsigned char *syn;
445
446 CGEN_INIT_PRINT ();
447
448 for (syn = syntax->syntax; *syn; ++syn)
449 {
450 if (CGEN_SYNTAX_CHAR_P (*syn))
451 {
452 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
453 continue;
454 }
455
456 /* We have an operand. */
457 m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (*syn), info,
458 fields, CGEN_INSN_ATTRS (insn), pc, length);
459 }
460 }
461 \f
462 /* Default value for CGEN_PRINT_INSN.
463 Given BUFLEN bytes (target byte order) read into BUF, look up the
464 insn in the instruction table and disassemble it.
465
466 The result is the size of the insn in bytes. */
467
468 #ifndef CGEN_PRINT_INSN
469 #define CGEN_PRINT_INSN print_insn
470 #endif
471
472 static int
473 print_insn (pc, info, buf, buflen)
474 bfd_vma pc;
475 disassemble_info *info;
476 char *buf;
477 int buflen;
478 {
479 int i;
480 unsigned long insn_value;
481 const CGEN_INSN_LIST *insn_list;
482
483 switch (buflen)
484 {
485 case 8:
486 insn_value = buf[0];
487 break;
488 case 16:
489 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
490 break;
491 case 32:
492 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
493 break;
494 default:
495 abort ();
496 }
497
498 /* The instructions are stored in hash lists.
499 Pick the first one and keep trying until we find the right one. */
500
501 insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value);
502 while (insn_list != NULL)
503 {
504 const CGEN_INSN *insn = insn_list->insn;
505 const struct cgen_syntax *syntax = CGEN_INSN_SYNTAX (insn);
506 struct cgen_fields fields;
507 int length;
508
509 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
510 /* Supported by this cpu? */
511 if (! m32r_cgen_insn_supported (insn))
512 continue;
513 #endif
514
515 /* Basic bit mask must be correct. */
516 /* ??? May wish to allow target to defer this check until the extract
517 handler. */
518 if ((insn_value & syntax->mask) == syntax->value)
519 {
520 /* Printing is handled in two passes. The first pass parses the
521 machine insn and extracts the fields. The second pass prints
522 them. */
523
524 length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields);
525 if (length > 0)
526 {
527 (*CGEN_PRINT_FN (insn)) (info, insn, &fields, pc, length);
528 /* length is in bits, result is in bytes */
529 return length / 8;
530 }
531 }
532
533 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
534 }
535
536 return 0;
537 }
538
539 /* Main entry point.
540 Print one instruction from PC on INFO->STREAM.
541 Return the size of the instruction (in bytes). */
542
543 int
544 print_insn_m32r (pc, info)
545 bfd_vma pc;
546 disassemble_info *info;
547 {
548 char buffer[CGEN_MAX_INSN_SIZE];
549 int status, length;
550 static int initialized = 0;
551 static int current_mach = 0;
552 static int current_big_p = 0;
553 int mach = info->mach;
554 int big_p = info->endian == BFD_ENDIAN_BIG;
555
556 /* If we haven't initialized yet, or if we've switched cpu's, initialize. */
557 if (!initialized || mach != current_mach || big_p != current_big_p)
558 {
559 initialized = 1;
560 current_mach = mach;
561 current_big_p = big_p;
562 m32r_cgen_init_dis (mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
563 }
564
565 /* Read enough of the insn so we can look it up in the hash lists. */
566
567 status = (*info->read_memory_func) (pc, buffer, CGEN_BASE_INSN_SIZE, info);
568 if (status != 0)
569 {
570 (*info->memory_error_func) (status, pc, info);
571 return -1;
572 }
573
574 /* We try to have as much common code as possible.
575 But at this point some targets need to take over. */
576 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
577 but if not possible, try to move this hook elsewhere rather than
578 have two hooks. */
579 length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
580 if (length)
581 return length;
582
583 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
584 return CGEN_DEFAULT_INSN_SIZE;
585 }