1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
4 THIS FILE IS USED TO GENERATE fr30-dis.c.
6 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
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)
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.
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 Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
35 #define INLINE __inline__
40 /* Default text to print if an instruction isn't recognized. */
41 #define UNKNOWN_INSN_MSG _("*unknown*")
43 static int extract_normal
44 PARAMS ((CGEN_OPCODE_DESC
, CGEN_EXTRACT_INFO
*, CGEN_INSN_BYTES
,
45 unsigned int, int, int, int, long *));
46 static void print_normal
47 PARAMS ((CGEN_OPCODE_DESC
, PTR
, long, unsigned int, bfd_vma
, int));
48 static void print_address
49 PARAMS ((CGEN_OPCODE_DESC
, PTR
, bfd_vma
, unsigned int, bfd_vma
, int));
50 static void print_keyword
51 PARAMS ((CGEN_OPCODE_DESC
, PTR
, CGEN_KEYWORD
*, long, unsigned int));
52 static int extract_insn_normal
53 PARAMS ((CGEN_OPCODE_DESC
, const CGEN_INSN
*, CGEN_EXTRACT_INFO
*,
54 unsigned long, CGEN_FIELDS
*, bfd_vma
));
55 static void print_insn_normal
56 PARAMS ((CGEN_OPCODE_DESC
, PTR
, const CGEN_INSN
*, CGEN_FIELDS
*,
58 static int print_insn
PARAMS ((CGEN_OPCODE_DESC
, bfd_vma
,
59 disassemble_info
*, char *, int));
60 static int default_print_insn
61 PARAMS ((CGEN_OPCODE_DESC
, bfd_vma
, disassemble_info
*));
63 /* -- disassembler routines inserted here */
65 /* Main entry point for operand extraction.
67 This function is basically just a big switch statement. Earlier versions
68 used tables to look up the function to use, but
69 - if the table contains both assembler and disassembler functions then
70 the disassembler contains much of the assembler and vice-versa,
71 - there's a lot of inlining possibilities as things grow,
72 - using a switch statement avoids the function call overhead.
74 This function could be moved into `print_insn_normal', but keeping it
75 separate makes clear the interface between `print_insn_normal' and each of
80 fr30_cgen_extract_operand (od
, opindex
, ex_info
, insn_value
, fields
, pc
)
83 CGEN_EXTRACT_INFO
*ex_info
;
84 CGEN_INSN_BYTES insn_value
;
92 case FR30_OPERAND_RI
:
93 length
= extract_normal (od
, ex_info
, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 12, 4, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_Ri
);
95 case FR30_OPERAND_RJ
:
96 length
= extract_normal (od
, ex_info
, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 8, 4, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_Rj
);
100 /* xgettext:c-format */
101 fprintf (stderr
, _("Unrecognized field %d while decoding insn.\n"),
109 /* Main entry point for printing operands.
111 This function is basically just a big switch statement. Earlier versions
112 used tables to look up the function to use, but
113 - if the table contains both assembler and disassembler functions then
114 the disassembler contains much of the assembler and vice-versa,
115 - there's a lot of inlining possibilities as things grow,
116 - using a switch statement avoids the function call overhead.
118 This function could be moved into `print_insn_normal', but keeping it
119 separate makes clear the interface between `print_insn_normal' and each of
124 fr30_cgen_print_operand (od
, opindex
, info
, fields
, attrs
, pc
, length
)
127 disassemble_info
* info
;
128 CGEN_FIELDS
* fields
;
135 case FR30_OPERAND_RI
:
136 print_keyword (od
, info
, & fr30_cgen_opval_h_gr
, fields
->f_Ri
, 0|(1<<CGEN_OPERAND_UNSIGNED
));
138 case FR30_OPERAND_RJ
:
139 print_keyword (od
, info
, & fr30_cgen_opval_h_gr
, fields
->f_Rj
, 0|(1<<CGEN_OPERAND_UNSIGNED
));
143 /* xgettext:c-format */
144 fprintf (stderr
, _("Unrecognized field %d while printing insn.\n"),
150 cgen_extract_fn
* const fr30_cgen_extract_handlers
[] =
156 cgen_print_fn
* const fr30_cgen_print_handlers
[] =
164 fr30_cgen_init_dis (od
)
170 #if ! CGEN_INT_INSN_P
172 /* Subroutine of extract_normal. */
175 extract_1 (od
, ex_info
, start
, length
, word_length
, bufp
)
177 CGEN_EXTRACT_INFO
*info
;
178 int start
,length
,word_length
;
181 unsigned long x
,mask
;
183 int big_p
= CGEN_OPCODE_INSN_ENDIAN (od
) == CGEN_ENDIAN_BIG
;
185 /* FIXME: Need to use ex_info to ensure bytes have been fetched. */
194 x
= bfd_getb16 (bufp
);
196 x
= bfd_getl16 (bufp
);
199 /* ??? This may need reworking as these cases don't necessarily
200 want the first byte and the last two bytes handled like this. */
202 x
= (bfd_getb8 (bufp
) << 16) | bfd_getb16 (bufp
+ 1);
204 x
= bfd_getl16 (bufp
) | (bfd_getb8 (bufp
+ 2) << 16);
208 x
= bfd_getb32 (bufp
);
210 x
= bfd_getl32 (bufp
);
216 /* Written this way to avoid undefined behaviour. */
217 mask
= (((1L << (length
- 1)) - 1) << 1) | 1;
218 if (CGEN_INSN_LSB0_P
)
221 shift
= (word_length
- (start
+ length
));
222 return (x
>> shift
) & mask
;
225 #endif /* ! CGEN_INT_INSN_P */
227 /* Default extraction routine.
229 ATTRS is a mask of the boolean attributes. We only need `unsigned',
230 but for generality we take a bitmask of all of them. */
232 /* ??? This doesn't handle bfd_vma's. Create another function when
236 extract_normal (od
, ex_info
, insn_value
, attrs
, start
, length
, total_length
, valuep
)
238 CGEN_EXTRACT_INFO
*ex_info
;
239 CGEN_INSN_BYTES insn_value
;
241 int start
, length
, total_length
;
246 /* If LENGTH is zero, this operand doesn't contribute to the value
247 so give it a standard value of zero. */
257 /* Written this way to avoid undefined behaviour. */
258 unsigned long mask
= (((1L << (length
- 1)) - 1) << 1) | 1;
260 if (CGEN_INSN_LSB0_P
)
261 value
= insn_value
>> start
;
263 value
= insn_value
>> (total_length
- (start
+ length
));
266 if (! (attrs
& CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED
))
267 && (value
& (1L << (length
- 1))))
273 /* The hard case is probably too slow for the normal cases.
274 It's certainly more difficult to understand than the normal case.
275 Thus this is split into two. Keep it that way. The hard case is defined
276 to be when a field straddles a (loosely defined) word boundary
277 (??? which may require target specific help to determine). */
281 #define HARD_CASE_P 0 /* FIXME:wip */
289 unsigned char *bufp
= (unsigned char *) insn_value
;
294 /* Adjust start,total_length,bufp to point to the pseudo-word that holds
295 the value. For example in a 48 bit insn where the value to insert
296 (say an immediate value) is the last 16 bits then word_length here
297 would be 16. To handle a 24 bit insn with an 18 bit immediate,
298 extract_1 handles 24 bits (using a combination of bfd_get8,16). */
300 if (total_length
> 32)
302 int needed_width
= start
% 8 + length
;
303 int fetch_length
= (needed_width
<= 8 ? 8
304 : needed_width
<= 16 ? 16
307 if (CGEN_INSN_LSB0_P
)
309 if (CGEN_INSN_WORD_ENDIAN (od
) == CGEN_ENDIAN_BIG
)
315 int offset
= start
& ~7;
319 total_length
-= offset
;
324 if (CGEN_INSN_WORD_ENDIAN (od
) == CGEN_ENDIAN_BIG
)
326 int offset
= start
& ~7;
330 total_length
-= offset
;
339 /* FIXME: which bytes are being extracted have been lost. */
340 value
= extract_1 (od
, ex_info
, start
, length
, total_length
, bufp
);
343 #endif /* ! CGEN_INT_INSN_P */
351 /* Default print handler. */
354 print_normal (od
, dis_info
, value
, attrs
, pc
, length
)
362 disassemble_info
*info
= (disassemble_info
*) dis_info
;
364 #ifdef CGEN_PRINT_NORMAL
365 CGEN_PRINT_NORMAL (od
, info
, value
, attrs
, pc
, length
);
368 /* Print the operand as directed by the attributes. */
369 if (CGEN_BOOL_ATTR (attrs
, CGEN_OPERAND_SEM_ONLY
))
370 ; /* nothing to do */
371 else if (CGEN_BOOL_ATTR (attrs
, CGEN_OPERAND_UNSIGNED
))
372 (*info
->fprintf_func
) (info
->stream
, "0x%lx", value
);
374 (*info
->fprintf_func
) (info
->stream
, "%ld", value
);
377 /* Default address handler. */
380 print_address (od
, dis_info
, value
, attrs
, pc
, length
)
388 disassemble_info
*info
= (disassemble_info
*) dis_info
;
390 #ifdef CGEN_PRINT_ADDRESS
391 CGEN_PRINT_ADDRESS (od
, info
, value
, attrs
, pc
, length
);
394 /* Print the operand as directed by the attributes. */
395 if (CGEN_BOOL_ATTR (attrs
, CGEN_OPERAND_SEM_ONLY
))
396 ; /* nothing to do */
397 else if (CGEN_BOOL_ATTR (attrs
, CGEN_OPERAND_PCREL_ADDR
))
398 (*info
->print_address_func
) (value
, info
);
399 else if (CGEN_BOOL_ATTR (attrs
, CGEN_OPERAND_ABS_ADDR
))
400 (*info
->print_address_func
) (value
, info
);
401 else if (CGEN_BOOL_ATTR (attrs
, CGEN_OPERAND_UNSIGNED
))
402 (*info
->fprintf_func
) (info
->stream
, "0x%lx", (long) value
);
404 (*info
->fprintf_func
) (info
->stream
, "%ld", (long) value
);
407 /* Keyword print handler. */
410 print_keyword (od
, dis_info
, keyword_table
, value
, attrs
)
413 CGEN_KEYWORD
*keyword_table
;
417 disassemble_info
*info
= (disassemble_info
*) dis_info
;
418 const CGEN_KEYWORD_ENTRY
*ke
;
420 ke
= cgen_keyword_lookup_value (keyword_table
, value
);
422 (*info
->fprintf_func
) (info
->stream
, "%s", ke
->name
);
424 (*info
->fprintf_func
) (info
->stream
, "???");
427 /* Default insn extractor.
429 INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order.
430 The extracted fields are stored in FIELDS.
431 EX_INFO is used to handle reading variable length insns.
432 Return the length of the insn in bits, or 0 if no match,
433 or -1 if an error occurs fetching data (memory_error_func will have
437 extract_insn_normal (od
, insn
, ex_info
, insn_value
, fields
, pc
)
439 const CGEN_INSN
*insn
;
440 CGEN_EXTRACT_INFO
*ex_info
;
441 unsigned long insn_value
;
445 const CGEN_SYNTAX
*syntax
= CGEN_INSN_SYNTAX (insn
);
446 const unsigned char *syn
;
448 CGEN_FIELDS_BITSIZE (fields
) = CGEN_INSN_BITSIZE (insn
);
450 CGEN_INIT_EXTRACT (od
);
452 for (syn
= CGEN_SYNTAX_STRING (syntax
); *syn
; ++syn
)
456 if (CGEN_SYNTAX_CHAR_P (*syn
))
459 length
= fr30_cgen_extract_operand (od
, CGEN_SYNTAX_FIELD (*syn
),
460 ex_info
, insn_value
, fields
, pc
);
465 /* We recognized and successfully extracted this insn. */
466 return CGEN_INSN_BITSIZE (insn
);
469 /* Default insn printer.
471 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
472 about disassemble_info. */
475 print_insn_normal (od
, dis_info
, insn
, fields
, pc
, length
)
478 const CGEN_INSN
*insn
;
483 const CGEN_SYNTAX
*syntax
= CGEN_INSN_SYNTAX (insn
);
484 disassemble_info
*info
= (disassemble_info
*) dis_info
;
485 const unsigned char *syn
;
487 CGEN_INIT_PRINT (od
);
489 for (syn
= CGEN_SYNTAX_STRING (syntax
); *syn
; ++syn
)
491 if (CGEN_SYNTAX_MNEMONIC_P (*syn
))
493 (*info
->fprintf_func
) (info
->stream
, "%s", CGEN_INSN_MNEMONIC (insn
));
496 if (CGEN_SYNTAX_CHAR_P (*syn
))
498 (*info
->fprintf_func
) (info
->stream
, "%c", CGEN_SYNTAX_CHAR (*syn
));
502 /* We have an operand. */
503 fr30_cgen_print_operand (od
, CGEN_SYNTAX_FIELD (*syn
), info
,
504 fields
, CGEN_INSN_ATTRS (insn
), pc
, length
);
508 /* Utility to print an insn.
509 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
510 The result is the size of the insn in bytes or zero for an unknown insn
511 or -1 if an error occurs fetching data (memory_error_func will have
515 print_insn (od
, pc
, info
, buf
, buflen
)
518 disassemble_info
*info
;
522 unsigned long insn_value
;
523 const CGEN_INSN_LIST
*insn_list
;
524 CGEN_EXTRACT_INFO ex_info
;
526 ex_info
.dis_info
= info
;
527 ex_info
.valid
= (1 << CGEN_BASE_INSN_SIZE
) - 1;
536 insn_value
= info
->endian
== BFD_ENDIAN_BIG
? bfd_getb16 (buf
) : bfd_getl16 (buf
);
539 insn_value
= info
->endian
== BFD_ENDIAN_BIG
? bfd_getb32 (buf
) : bfd_getl32 (buf
);
545 /* The instructions are stored in hash lists.
546 Pick the first one and keep trying until we find the right one. */
548 insn_list
= CGEN_DIS_LOOKUP_INSN (od
, buf
, insn_value
);
549 while (insn_list
!= NULL
)
551 const CGEN_INSN
*insn
= insn_list
->insn
;
555 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
556 /* Supported by this cpu? */
557 if (! fr30_cgen_insn_supported (od
, insn
))
561 /* Basic bit mask must be correct. */
562 /* ??? May wish to allow target to defer this check until the extract
564 if ((insn_value
& CGEN_INSN_MASK (insn
)) == CGEN_INSN_VALUE (insn
))
566 /* Printing is handled in two passes. The first pass parses the
567 machine insn and extracts the fields. The second pass prints
570 length
= (*CGEN_EXTRACT_FN (insn
)) (od
, insn
, &ex_info
, insn_value
,
572 /* length < 0 -> error */
577 (*CGEN_PRINT_FN (insn
)) (od
, info
, insn
, &fields
, pc
, length
);
578 /* length is in bits, result is in bytes */
583 insn_list
= CGEN_DIS_NEXT_INSN (insn_list
);
589 /* Default value for CGEN_PRINT_INSN.
590 The result is the size of the insn in bytes or zero for an unknown insn
591 or -1 if an error occured fetching bytes. */
593 #ifndef CGEN_PRINT_INSN
594 #define CGEN_PRINT_INSN default_print_insn
598 default_print_insn (od
, pc
, info
)
601 disassemble_info
*info
;
603 char buf
[CGEN_MAX_INSN_SIZE
];
606 /* Read the base part of the insn. */
608 status
= (*info
->read_memory_func
) (pc
, buf
, CGEN_BASE_INSN_SIZE
, info
);
611 (*info
->memory_error_func
) (status
, pc
, info
);
615 return print_insn (od
, pc
, info
, buf
, CGEN_BASE_INSN_SIZE
);
619 Print one instruction from PC on INFO->STREAM.
620 Return the size of the instruction (in bytes). */
623 print_insn_fr30 (pc
, info
)
625 disassemble_info
*info
;
628 static CGEN_OPCODE_DESC od
= 0;
629 int mach
= info
->mach
;
630 int big_p
= info
->endian
== BFD_ENDIAN_BIG
;
632 /* If we haven't initialized yet, initialize the opcode table. */
635 od
= fr30_cgen_opcode_open (mach
,
638 : CGEN_ENDIAN_LITTLE
);
639 fr30_cgen_init_dis (od
);
641 /* If we've switched cpu's, re-initialize. */
642 /* ??? Perhaps we should use BFD_ENDIAN. */
643 else if (mach
!= CGEN_OPCODE_MACH (od
)
644 || (CGEN_OPCODE_ENDIAN (od
)
645 != (big_p
? CGEN_ENDIAN_BIG
: CGEN_ENDIAN_LITTLE
)))
647 cgen_set_cpu (od
, mach
, big_p
? CGEN_ENDIAN_BIG
: CGEN_ENDIAN_LITTLE
);
650 /* We try to have as much common code as possible.
651 But at this point some targets need to take over. */
652 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
653 but if not possible try to move this hook elsewhere rather than
655 length
= CGEN_PRINT_INSN (od
, pc
, info
);
661 (*info
->fprintf_func
) (info
->stream
, UNKNOWN_INSN_MSG
);
662 return CGEN_DEFAULT_INSN_SIZE
;