1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
4 This file is used to generate m32r-dis.c.
6 Copyright (C) 1996, 1997 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
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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.
38 /* Default text to print if an instruction isn't recognized. */
39 #define UNKNOWN_INSN_MSG "*unknown*"
41 /* FIXME: Machine generate. */
42 #ifndef CGEN_PCREL_OFFSET
43 #define CGEN_PCREL_OFFSET 0
46 static int print_insn
PARAMS ((bfd_vma
, disassemble_info
*, char *, int));
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));
53 /* Default extraction routine.
55 ATTRS is a mask of the boolean attributes. We only need `unsigned',
56 but for generality we take a bitmask of all of them. */
59 extract_normal (buf_ctrl
, insn_value
, attrs
, start
, length
, shift
, total_length
, valuep
)
61 cgen_insn_t insn_value
;
63 int start
, length
, shift
, total_length
;
70 value
= ((insn_value
>> (CGEN_BASE_INSN_BITSIZE
- (start
+ length
)))
71 & ((1 << length
) - 1));
73 value
= ((insn_value
>> (total_length
- (start
+ length
)))
74 & ((1 << length
) - 1));
76 if (! (attrs
& CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED
))
77 && (value
& (1 << (length
- 1))))
80 /* FIXME: unfinished */
83 /* This is backwards as we undo the effects of insert_normal. */
93 /* Default print handler. */
96 print_normal (dis_info
, value
, attrs
, pc
, length
)
100 unsigned long pc
; /* FIXME: should be bfd_vma */
103 disassemble_info
*info
= dis_info
;
105 /* Print the operand as directed by the attributes. */
106 if (attrs
& CGEN_ATTR_MASK (CGEN_OPERAND_FAKE
))
107 ; /* nothing to do (??? at least not yet) */
108 else if (attrs
& CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR
))
109 (*info
->print_address_func
) (pc
+ CGEN_PCREL_OFFSET
+ value
, info
);
110 /* ??? Not all cases of this are currently caught. */
111 else if (attrs
& CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR
))
112 /* FIXME: Why & 0xffffffff? */
113 (*info
->print_address_func
) ((bfd_vma
) value
& 0xffffffff, info
);
114 else if (attrs
& CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED
))
115 (*info
->fprintf_func
) (info
->stream
, "0x%lx", value
);
117 (*info
->fprintf_func
) (info
->stream
, "%ld", value
);
120 /* Keyword print handler. */
123 print_keyword (dis_info
, keyword_table
, value
, attrs
)
125 CGEN_KEYWORD
*keyword_table
;
129 disassemble_info
*info
= dis_info
;
130 const CGEN_KEYWORD_ENTRY
*ke
;
132 ke
= cgen_keyword_lookup_value (keyword_table
, value
);
134 (*info
->fprintf_func
) (info
->stream
, "%s", ke
->name
);
136 (*info
->fprintf_func
) (info
->stream
, "???");
139 /* -- disassembler routines inserted here */
142 #undef CGEN_PRINT_INSN
143 #define CGEN_PRINT_INSN my_print_insn
146 my_print_insn (pc
, info
, buf
, buflen
)
148 disassemble_info
*info
;
153 if ((pc
& 3) == 0 && (buf
[0] & 0x80) != 0)
154 return print_insn (pc
, info
, buf
, buflen
);
156 /* Print the first insn. */
159 if (print_insn (pc
, info
, buf
, 16) == 0)
160 (*info
->fprintf_func
) (info
->stream
, UNKNOWN_INSN_MSG
);
167 (*info
->fprintf_func
) (info
->stream
, " || ");
171 (*info
->fprintf_func
) (info
->stream
, " -> ");
173 /* The "& 3" is to ensure the branch address is computed correctly
174 [if it is a branch]. */
175 if (print_insn (pc
& ~ (bfd_vma
) 3, info
, buf
, 16) == 0)
176 (*info
->fprintf_func
) (info
->stream
, UNKNOWN_INSN_MSG
);
178 return (pc
& 3) ? 2 : 4;
183 /* Main entry point for operand extraction.
185 This function is basically just a big switch statement. Earlier versions
186 used tables to look up the function to use, but
187 - if the table contains both assembler and disassembler functions then
188 the disassembler contains much of the assembler and vice-versa,
189 - there's a lot of inlining possibilities as things grow,
190 - using a switch statement avoids the function call overhead.
192 This function could be moved into `print_insn_normal', but keeping it
193 separate makes clear the interface between `print_insn_normal' and each of
198 m32r_cgen_extract_operand (opindex
, buf_ctrl
, insn_value
, fields
)
201 cgen_insn_t insn_value
;
202 CGEN_FIELDS
* fields
;
208 case M32R_OPERAND_SR
:
209 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_r2
);
211 case M32R_OPERAND_DR
:
212 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_r1
);
214 case M32R_OPERAND_SRC1
:
215 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_r1
);
217 case M32R_OPERAND_SRC2
:
218 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_r2
);
220 case M32R_OPERAND_SCR
:
221 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_r2
);
223 case M32R_OPERAND_DCR
:
224 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_r1
);
226 case M32R_OPERAND_SIMM8
:
227 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0, 8, 8, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_simm8
);
229 case M32R_OPERAND_SIMM16
:
230 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_simm16
);
232 case M32R_OPERAND_UIMM4
:
233 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_uimm4
);
235 case M32R_OPERAND_UIMM5
:
236 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 11, 5, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_uimm5
);
238 case M32R_OPERAND_UIMM16
:
239 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_uimm16
);
241 case M32R_OPERAND_HI16
:
242 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 case M32R_OPERAND_SLO16
:
245 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_simm16
);
247 case M32R_OPERAND_ULO16
:
248 length
= extract_normal (NULL
/*FIXME*/, insn_value
, 0|(1<<CGEN_OPERAND_UNSIGNED
), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields
), & fields
->f_uimm16
);
250 case M32R_OPERAND_UIMM24
:
251 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 case M32R_OPERAND_DISP8
:
254 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 case M32R_OPERAND_DISP16
:
257 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 case M32R_OPERAND_DISP24
:
260 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
);
264 fprintf (stderr
, "Unrecognized field %d while decoding insn.\n",
272 /* Main entry point for printing operands.
274 This function is basically just a big switch statement. Earlier versions
275 used tables to look up the function to use, but
276 - if the table contains both assembler and disassembler functions then
277 the disassembler contains much of the assembler and vice-versa,
278 - there's a lot of inlining possibilities as things grow,
279 - using a switch statement avoids the function call overhead.
281 This function could be moved into `print_insn_normal', but keeping it
282 separate makes clear the interface between `print_insn_normal' and each of
287 m32r_cgen_print_operand (opindex
, info
, fields
, attrs
, pc
, length
)
289 disassemble_info
* info
;
290 CGEN_FIELDS
* fields
;
297 case M32R_OPERAND_SR
:
298 print_keyword (info
, & m32r_cgen_opval_h_gr
, fields
->f_r2
, 0|(1<<CGEN_OPERAND_UNSIGNED
));
300 case M32R_OPERAND_DR
:
301 print_keyword (info
, & m32r_cgen_opval_h_gr
, fields
->f_r1
, 0|(1<<CGEN_OPERAND_UNSIGNED
));
303 case M32R_OPERAND_SRC1
:
304 print_keyword (info
, & m32r_cgen_opval_h_gr
, fields
->f_r1
, 0|(1<<CGEN_OPERAND_UNSIGNED
));
306 case M32R_OPERAND_SRC2
:
307 print_keyword (info
, & m32r_cgen_opval_h_gr
, fields
->f_r2
, 0|(1<<CGEN_OPERAND_UNSIGNED
));
309 case M32R_OPERAND_SCR
:
310 print_keyword (info
, & m32r_cgen_opval_h_cr
, fields
->f_r2
, 0|(1<<CGEN_OPERAND_UNSIGNED
));
312 case M32R_OPERAND_DCR
:
313 print_keyword (info
, & m32r_cgen_opval_h_cr
, fields
->f_r1
, 0|(1<<CGEN_OPERAND_UNSIGNED
));
315 case M32R_OPERAND_SIMM8
:
316 print_normal (info
, fields
->f_simm8
, 0, pc
, length
);
318 case M32R_OPERAND_SIMM16
:
319 print_normal (info
, fields
->f_simm16
, 0, pc
, length
);
321 case M32R_OPERAND_UIMM4
:
322 print_normal (info
, fields
->f_uimm4
, 0|(1<<CGEN_OPERAND_UNSIGNED
), pc
, length
);
324 case M32R_OPERAND_UIMM5
:
325 print_normal (info
, fields
->f_uimm5
, 0|(1<<CGEN_OPERAND_UNSIGNED
), pc
, length
);
327 case M32R_OPERAND_UIMM16
:
328 print_normal (info
, fields
->f_uimm16
, 0|(1<<CGEN_OPERAND_UNSIGNED
), pc
, length
);
330 case M32R_OPERAND_HI16
:
331 print_normal (info
, fields
->f_hi16
, 0|(1<<CGEN_OPERAND_SIGN_OPT
)|(1<<CGEN_OPERAND_UNSIGNED
), pc
, length
);
333 case M32R_OPERAND_SLO16
:
334 print_normal (info
, fields
->f_simm16
, 0, pc
, length
);
336 case M32R_OPERAND_ULO16
:
337 print_normal (info
, fields
->f_uimm16
, 0|(1<<CGEN_OPERAND_UNSIGNED
), pc
, length
);
339 case M32R_OPERAND_UIMM24
:
340 print_normal (info
, fields
->f_uimm24
, 0|(1<<CGEN_OPERAND_RELOC
)|(1<<CGEN_OPERAND_ABS_ADDR
)|(1<<CGEN_OPERAND_UNSIGNED
), pc
, length
);
342 case M32R_OPERAND_DISP8
:
343 print_normal (info
, fields
->f_disp8
, 0|(1<<CGEN_OPERAND_RELAX
)|(1<<CGEN_OPERAND_RELOC
)|(1<<CGEN_OPERAND_PCREL_ADDR
), pc
, length
);
345 case M32R_OPERAND_DISP16
:
346 print_normal (info
, fields
->f_disp16
, 0|(1<<CGEN_OPERAND_RELOC
)|(1<<CGEN_OPERAND_PCREL_ADDR
), pc
, length
);
348 case M32R_OPERAND_DISP24
:
349 print_normal (info
, fields
->f_disp24
, 0|(1<<CGEN_OPERAND_RELAX
)|(1<<CGEN_OPERAND_RELOC
)|(1<<CGEN_OPERAND_PCREL_ADDR
), pc
, length
);
353 fprintf (stderr
, "Unrecognized field %d while printing insn.\n",
359 cgen_extract_fn
* m32r_cgen_extract_handlers
[] =
364 cgen_print_fn
* m32r_cgen_print_handlers
[] =
371 m32r_cgen_init_dis (mach
, endian
)
373 enum cgen_endian endian
;
375 m32r_cgen_init_tables (mach
);
376 cgen_set_cpu (& m32r_cgen_opcode_data
, mach
, endian
);
381 /* Default insn extractor.
383 The extracted fields are stored in DIS_FLDS.
384 BUF_CTRL is used to handle reading variable length insns (FIXME: not done).
385 Return the length of the insn in bits, or 0 if no match. */
388 extract_insn_normal (insn
, buf_ctrl
, insn_value
, fields
)
389 const CGEN_INSN
*insn
;
391 cgen_insn_t insn_value
;
394 const CGEN_SYNTAX
*syntax
= CGEN_INSN_SYNTAX (insn
);
395 const unsigned char *syn
;
397 CGEN_FIELDS_BITSIZE (fields
) = CGEN_INSN_BITSIZE (insn
);
399 CGEN_INIT_EXTRACT ();
401 for (syn
= CGEN_SYNTAX_STRING (syntax
); *syn
; ++syn
)
405 if (CGEN_SYNTAX_CHAR_P (*syn
))
408 length
= m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn
),
409 buf_ctrl
, insn_value
, fields
);
414 /* We recognized and successfully extracted this insn. */
415 return CGEN_INSN_BITSIZE (insn
);
418 /* Default insn printer.
420 DIS_INFO is defined as `void *' so the disassembler needn't know anything
421 about disassemble_info.
425 print_insn_normal (dis_info
, insn
, fields
, pc
, length
)
427 const CGEN_INSN
*insn
;
432 const CGEN_SYNTAX
*syntax
= CGEN_INSN_SYNTAX (insn
);
433 disassemble_info
*info
= dis_info
;
434 const unsigned char *syn
;
438 for (syn
= CGEN_SYNTAX_STRING (syntax
); *syn
; ++syn
)
440 if (CGEN_SYNTAX_MNEMONIC_P (*syn
))
442 (*info
->fprintf_func
) (info
->stream
, "%s", CGEN_INSN_MNEMONIC (insn
));
445 if (CGEN_SYNTAX_CHAR_P (*syn
))
447 (*info
->fprintf_func
) (info
->stream
, "%c", CGEN_SYNTAX_CHAR (*syn
));
451 /* We have an operand. */
452 m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (*syn
), info
,
453 fields
, CGEN_INSN_ATTRS (insn
), pc
, length
);
457 /* Default value for CGEN_PRINT_INSN.
458 Given BUFLEN bytes (target byte order) read into BUF, look up the
459 insn in the instruction table and disassemble it.
461 The result is the size of the insn in bytes. */
463 #ifndef CGEN_PRINT_INSN
464 #define CGEN_PRINT_INSN print_insn
468 print_insn (pc
, info
, buf
, buflen
)
470 disassemble_info
*info
;
475 unsigned long insn_value
;
476 const CGEN_INSN_LIST
*insn_list
;
484 insn_value
= info
->endian
== BFD_ENDIAN_BIG
? bfd_getb16 (buf
) : bfd_getl16 (buf
);
487 insn_value
= info
->endian
== BFD_ENDIAN_BIG
? bfd_getb32 (buf
) : bfd_getl32 (buf
);
493 /* The instructions are stored in hash lists.
494 Pick the first one and keep trying until we find the right one. */
496 insn_list
= CGEN_DIS_LOOKUP_INSN (buf
, insn_value
);
497 while (insn_list
!= NULL
)
499 const CGEN_INSN
*insn
= insn_list
->insn
;
500 const CGEN_SYNTAX
*syntax
= CGEN_INSN_SYNTAX (insn
);
504 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
505 /* Supported by this cpu? */
506 if (! m32r_cgen_insn_supported (insn
))
510 /* Basic bit mask must be correct. */
511 /* ??? May wish to allow target to defer this check until the extract
513 if ((insn_value
& CGEN_INSN_MASK (insn
)) == CGEN_INSN_VALUE (insn
))
515 /* Printing is handled in two passes. The first pass parses the
516 machine insn and extracts the fields. The second pass prints
519 length
= (*CGEN_EXTRACT_FN (insn
)) (insn
, NULL
, insn_value
, &fields
);
522 (*CGEN_PRINT_FN (insn
)) (info
, insn
, &fields
, pc
, length
);
523 /* length is in bits, result is in bytes */
528 insn_list
= CGEN_DIS_NEXT_INSN (insn_list
);
535 Print one instruction from PC on INFO->STREAM.
536 Return the size of the instruction (in bytes). */
539 print_insn_m32r (pc
, info
)
541 disassemble_info
*info
;
543 char buffer
[CGEN_MAX_INSN_SIZE
];
545 static int initialized
= 0;
546 static int current_mach
= 0;
547 static int current_big_p
= 0;
548 int mach
= info
->mach
;
549 int big_p
= info
->endian
== BFD_ENDIAN_BIG
;
551 /* If we haven't initialized yet, or if we've switched cpu's, initialize. */
552 if (!initialized
|| mach
!= current_mach
|| big_p
!= current_big_p
)
556 current_big_p
= big_p
;
557 m32r_cgen_init_dis (mach
, big_p
? CGEN_ENDIAN_BIG
: CGEN_ENDIAN_LITTLE
);
560 /* Read enough of the insn so we can look it up in the hash lists. */
562 status
= (*info
->read_memory_func
) (pc
, buffer
, CGEN_BASE_INSN_SIZE
, info
);
565 (*info
->memory_error_func
) (status
, pc
, info
);
569 /* We try to have as much common code as possible.
570 But at this point some targets need to take over. */
571 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
572 but if not possible try to move this hook elsewhere rather than
574 length
= CGEN_PRINT_INSN (pc
, info
, buffer
, CGEN_BASE_INSN_BITSIZE
);
578 (*info
->fprintf_func
) (info
->stream
, UNKNOWN_INSN_MSG
);
579 return CGEN_DEFAULT_INSN_SIZE
;