1 /* Generic opcode table support for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
4 THIS FILE IS USED TO GENERATE fr30-opc.c.
6 Copyright (C) 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. */
27 #include "libiberty.h"
33 /* The hash functions are recorded here to help keep assembler code out of
34 the disassembler and vice versa. */
36 static int asm_hash_insn_p
PARAMS ((const CGEN_INSN
*));
37 static unsigned int asm_hash_insn
PARAMS ((const char *));
38 static int dis_hash_insn_p
PARAMS ((const CGEN_INSN
*));
39 static unsigned int dis_hash_insn
PARAMS ((const char *, unsigned long));
41 /* Cover function to read and properly byteswap an insn value. */
44 cgen_get_insn_value (od
, buf
, length
)
57 if (CGEN_OPCODE_INSN_ENDIAN (od
) == CGEN_ENDIAN_BIG
)
58 value
= bfd_getb16 (buf
);
60 value
= bfd_getl16 (buf
);
63 if (CGEN_OPCODE_INSN_ENDIAN (od
) == CGEN_ENDIAN_BIG
)
64 value
= bfd_getb32 (buf
);
66 value
= bfd_getl32 (buf
);
75 /* Cover function to store an insn value properly byteswapped. */
78 cgen_put_insn_value (od
, buf
, length
, value
)
90 if (CGEN_OPCODE_INSN_ENDIAN (od
) == CGEN_ENDIAN_BIG
)
91 bfd_putb16 (value
, buf
);
93 bfd_putl16 (value
, buf
);
96 if (CGEN_OPCODE_INSN_ENDIAN (od
) == CGEN_ENDIAN_BIG
)
97 bfd_putb32 (value
, buf
);
99 bfd_putl32 (value
, buf
);
106 /* Look up instruction INSN_VALUE and extract its fields.
107 INSN, if non-null, is the insn table entry.
108 Otherwise INSN_VALUE is examined to compute it.
109 LENGTH is the bit length of INSN_VALUE if known, otherwise 0.
110 0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
111 If INSN != NULL, LENGTH must be valid.
112 ALIAS_P is non-zero if alias insns are to be included in the search.
114 The result a pointer to the insn table entry, or NULL if the instruction
115 wasn't recognized. */
118 fr30_cgen_lookup_insn (od
, insn
, insn_value
, length
, fields
, alias_p
)
120 const CGEN_INSN
*insn
;
121 CGEN_INSN_BYTES insn_value
;
126 unsigned char buf
[16];
128 unsigned int base_insn
;
130 CGEN_EXTRACT_INFO
*info
= NULL
;
132 CGEN_EXTRACT_INFO ex_info
;
133 CGEN_EXTRACT_INFO
*info
= &ex_info
;
136 #if ! CGEN_INT_INSN_P
137 ex_info
.dis_info
= NULL
;
138 ex_info
.bytes
= insn_value
;
144 const CGEN_INSN_LIST
*insn_list
;
147 cgen_put_insn_value (od
, buf
, length
, insn_value
);
149 base_insn
= insn_value
; /*???*/
151 base_insn
= cgen_get_insn_value (od
, buf
, length
);
155 /* The instructions are stored in hash lists.
156 Pick the first one and keep trying until we find the right one. */
158 insn_list
= CGEN_DIS_LOOKUP_INSN (od
, bufp
, base_insn
);
159 while (insn_list
!= NULL
)
161 insn
= insn_list
->insn
;
164 || ! CGEN_INSN_ATTR (insn
, CGEN_INSN_ALIAS
))
166 /* Basic bit mask must be correct. */
167 /* ??? May wish to allow target to defer this check until the
169 if ((insn_value
& CGEN_INSN_MASK (insn
)) == CGEN_INSN_VALUE (insn
))
171 /* ??? 0 is passed for `pc' */
172 int elength
= (*CGEN_EXTRACT_FN (insn
)) (od
, insn
, info
,
178 if (length
!= 0 && length
!= elength
)
185 insn_list
= CGEN_DIS_NEXT_INSN (insn_list
);
190 /* Sanity check: can't pass an alias insn if ! alias_p. */
192 && CGEN_INSN_ATTR (insn
, CGEN_INSN_ALIAS
))
194 /* Sanity check: length must be correct. */
195 if (length
!= CGEN_INSN_BITSIZE (insn
))
198 /* ??? 0 is passed for `pc' */
199 length
= (*CGEN_EXTRACT_FN (insn
)) (od
, insn
, info
, insn_value
, fields
,
201 /* Sanity check: must succeed.
202 Could relax this later if it ever proves useful. */
211 /* Fill in the operand instances used by INSN whose operands are FIELDS.
212 INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
216 fr30_cgen_get_insn_operands (od
, insn
, fields
, indices
)
218 const CGEN_INSN
* insn
;
219 const CGEN_FIELDS
* fields
;
222 const CGEN_OPERAND_INSTANCE
*opinst
;
225 for (i
= 0, opinst
= CGEN_INSN_OPERANDS (insn
);
227 && CGEN_OPERAND_INSTANCE_TYPE (opinst
) != CGEN_OPERAND_INSTANCE_END
;
230 const CGEN_OPERAND
*op
= CGEN_OPERAND_INSTANCE_OPERAND (opinst
);
232 indices
[i
] = CGEN_OPERAND_INSTANCE_INDEX (opinst
);
234 indices
[i
] = fr30_cgen_get_int_operand (CGEN_OPERAND_INDEX (op
),
239 /* Cover function to fr30_cgen_get_insn_operands when either INSN or FIELDS
241 The INSN, INSN_VALUE, and LENGTH arguments are passed to
242 fr30_cgen_lookup_insn unchanged.
244 The result is the insn table entry or NULL if the instruction wasn't
248 fr30_cgen_lookup_get_insn_operands (od
, insn
, insn_value
, length
, indices
)
250 const CGEN_INSN
*insn
;
251 CGEN_INSN_BYTES insn_value
;
257 /* Pass non-zero for ALIAS_P only if INSN != NULL.
258 If INSN == NULL, we want a real insn. */
259 insn
= fr30_cgen_lookup_insn (od
, insn
, insn_value
, length
, &fields
,
264 fr30_cgen_get_insn_operands (od
, insn
, &fields
, indices
);
269 static const CGEN_ATTR_ENTRY MACH_attr
[] =
271 { "base", MACH_BASE
},
272 { "fr30", MACH_FR30
},
277 const CGEN_ATTR_TABLE fr30_cgen_hardware_attr_table
[] =
279 { "CACHE-ADDR", NULL
},
280 { "FUN-ACCESS", NULL
},
286 const CGEN_ATTR_TABLE fr30_cgen_operand_attr_table
[] =
288 { "ABS-ADDR", NULL
},
290 { "NEGATIVE", NULL
},
291 { "PCREL-ADDR", NULL
},
293 { "SIGN-OPT", NULL
},
294 { "UNSIGNED", NULL
},
298 const CGEN_ATTR_TABLE fr30_cgen_insn_attr_table
[] =
301 { "COND-CTI", NULL
},
304 { "RELAXABLE", NULL
},
305 { "SKIP-CTI", NULL
},
306 { "UNCOND-CTI", NULL
},
311 CGEN_KEYWORD_ENTRY fr30_cgen_opval_h_gr_entries
[] =
334 CGEN_KEYWORD fr30_cgen_opval_h_gr
=
336 & fr30_cgen_opval_h_gr_entries
[0],
340 CGEN_KEYWORD_ENTRY fr30_cgen_opval_h_dr_entries
[] =
348 CGEN_KEYWORD fr30_cgen_opval_h_dr
=
350 & fr30_cgen_opval_h_dr_entries
[0],
354 CGEN_KEYWORD_ENTRY fr30_cgen_opval_h_mdr_entries
[] =
360 CGEN_KEYWORD fr30_cgen_opval_h_mdr
=
362 & fr30_cgen_opval_h_mdr_entries
[0],
366 CGEN_KEYWORD_ENTRY fr30_cgen_opval_h_cr_entries
[] =
372 CGEN_KEYWORD fr30_cgen_opval_h_cr
=
374 & fr30_cgen_opval_h_cr_entries
[0],
379 /* The hardware table. */
381 #define HW_ENT(n) fr30_cgen_hw_entries[n]
382 static const CGEN_HW_ENTRY fr30_cgen_hw_entries
[] =
384 { HW_H_PC
, & HW_ENT (HW_H_PC
+ 1), "h-pc", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0|(1<<CGEN_HW_PROFILE
)|(1<<CGEN_HW_PC
), { 0 } } },
385 { HW_H_MEMORY
, & HW_ENT (HW_H_MEMORY
+ 1), "h-memory", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0, { 0 } } },
386 { HW_H_SINT
, & HW_ENT (HW_H_SINT
+ 1), "h-sint", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0, { 0 } } },
387 { HW_H_UINT
, & HW_ENT (HW_H_UINT
+ 1), "h-uint", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0, { 0 } } },
388 { HW_H_ADDR
, & HW_ENT (HW_H_ADDR
+ 1), "h-addr", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0, { 0 } } },
389 { HW_H_IADDR
, & HW_ENT (HW_H_IADDR
+ 1), "h-iaddr", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0, { 0 } } },
390 { HW_H_GR
, & HW_ENT (HW_H_GR
+ 1), "h-gr", CGEN_ASM_KEYWORD
, (PTR
) & fr30_cgen_opval_h_gr
, { 0, 0|(1<<CGEN_HW_CACHE_ADDR
)|(1<<CGEN_HW_PROFILE
), { 0 } } },
391 { HW_H_DR
, & HW_ENT (HW_H_DR
+ 1), "h-dr", CGEN_ASM_KEYWORD
, (PTR
) & fr30_cgen_opval_h_dr
, { 0, 0, { 0 } } },
392 { HW_H_MDR
, & HW_ENT (HW_H_MDR
+ 1), "h-mdr", CGEN_ASM_KEYWORD
, (PTR
) & fr30_cgen_opval_h_mdr
, { 0, 0, { 0 } } },
393 { HW_H_CR
, & HW_ENT (HW_H_CR
+ 1), "h-cr", CGEN_ASM_KEYWORD
, (PTR
) & fr30_cgen_opval_h_cr
, { 0, 0, { 0 } } },
394 { HW_H_NBIT
, & HW_ENT (HW_H_NBIT
+ 1), "h-nbit", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0|(1<<CGEN_HW_FUN_ACCESS
), { 0 } } },
395 { HW_H_ZBIT
, & HW_ENT (HW_H_ZBIT
+ 1), "h-zbit", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0|(1<<CGEN_HW_FUN_ACCESS
), { 0 } } },
396 { HW_H_VBIT
, & HW_ENT (HW_H_VBIT
+ 1), "h-vbit", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0|(1<<CGEN_HW_FUN_ACCESS
), { 0 } } },
397 { HW_H_CBIT
, & HW_ENT (HW_H_CBIT
+ 1), "h-cbit", CGEN_ASM_KEYWORD
, (PTR
) 0, { 0, 0|(1<<CGEN_HW_FUN_ACCESS
), { 0 } } },
401 /* The operand table. */
403 #define OPERAND(op) CONCAT2 (FR30_OPERAND_,op)
404 #define OP_ENT(op) fr30_cgen_operand_table[OPERAND (op)]
406 const CGEN_OPERAND fr30_cgen_operand_table
[MAX_OPERANDS
] =
408 /* pc: program counter */
409 { "pc", & HW_ENT (HW_H_PC
), 0, 0,
410 { 0, 0|(1<<CGEN_OPERAND_FAKE
), { 0 } } },
411 /* Ri: destination register */
412 { "Ri", & HW_ENT (HW_H_GR
), 12, 4,
413 { 0, 0|(1<<CGEN_OPERAND_UNSIGNED
), { 0 } } },
414 /* Rj: source register */
415 { "Rj", & HW_ENT (HW_H_GR
), 8, 4,
416 { 0, 0|(1<<CGEN_OPERAND_UNSIGNED
), { 0 } } },
417 /* nbit: negative bit */
418 { "nbit", & HW_ENT (HW_H_NBIT
), 0, 0,
419 { 0, 0|(1<<CGEN_OPERAND_FAKE
), { 0 } } },
420 /* vbit: overflow bit */
421 { "vbit", & HW_ENT (HW_H_VBIT
), 0, 0,
422 { 0, 0|(1<<CGEN_OPERAND_FAKE
), { 0 } } },
424 { "zbit", & HW_ENT (HW_H_ZBIT
), 0, 0,
425 { 0, 0|(1<<CGEN_OPERAND_FAKE
), { 0 } } },
426 /* cbit: carry bit */
427 { "cbit", & HW_ENT (HW_H_CBIT
), 0, 0,
428 { 0, 0|(1<<CGEN_OPERAND_FAKE
), { 0 } } },
431 /* Operand references. */
433 #define INPUT CGEN_OPERAND_INSTANCE_INPUT
434 #define OUTPUT CGEN_OPERAND_INSTANCE_OUTPUT
436 static const CGEN_OPERAND_INSTANCE fmt_add_ops
[] = {
437 { INPUT
, "Rj", & HW_ENT (HW_H_GR
), CGEN_MODE_SI
, & OP_ENT (RJ
), 0 },
438 { INPUT
, "Ri", & HW_ENT (HW_H_GR
), CGEN_MODE_SI
, & OP_ENT (RI
), 0 },
439 { OUTPUT
, "Ri", & HW_ENT (HW_H_GR
), CGEN_MODE_SI
, & OP_ENT (RI
), 0 },
440 { OUTPUT
, "vbit", & HW_ENT (HW_H_VBIT
), CGEN_MODE_BI
, 0, 0 },
441 { OUTPUT
, "cbit", & HW_ENT (HW_H_CBIT
), CGEN_MODE_BI
, 0, 0 },
442 { OUTPUT
, "zbit", & HW_ENT (HW_H_ZBIT
), CGEN_MODE_BI
, 0, 0 },
443 { OUTPUT
, "nbit", & HW_ENT (HW_H_NBIT
), CGEN_MODE_BI
, 0, 0 },
450 #define A(a) (1 << CONCAT2 (CGEN_INSN_,a))
451 #define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
452 #define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
454 /* The instruction table.
455 This is currently non-static because the simulator accesses it
458 const CGEN_INSN fr30_cgen_insn_table_entries
[MAX_INSNS
] =
460 /* Special null first entry.
461 A `num' value of zero is thus invalid.
462 Also, the special `invalid' insn resides here. */
467 FR30_INSN_ADD
, "add", "add",
468 { { MNEM
, ' ', OP (RJ
), ',', OP (RI
), 0 } },
469 { 16, 16, 0xff00 }, 0xa600,
470 (PTR
) & fmt_add_ops
[0],
479 static const CGEN_INSN_TABLE insn_table
=
481 & fr30_cgen_insn_table_entries
[0],
487 /* Each non-simple macro entry points to an array of expansion possibilities. */
489 #define A(a) (1 << CONCAT2 (CGEN_INSN_,a))
490 #define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
491 #define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
493 /* The macro instruction table. */
495 static const CGEN_INSN macro_insn_table_entries
[] =
503 static const CGEN_INSN_TABLE macro_insn_table
=
505 & macro_insn_table_entries
[0],
507 (sizeof (macro_insn_table_entries
) /
508 sizeof (macro_insn_table_entries
[0])),
517 /* Return non-zero if INSN is to be added to the hash table.
518 Targets are free to override CGEN_{ASM,DIS}_HASH_P in the .opc file. */
521 asm_hash_insn_p (insn
)
522 const CGEN_INSN
* insn
;
524 return CGEN_ASM_HASH_P (insn
);
528 dis_hash_insn_p (insn
)
529 const CGEN_INSN
* insn
;
531 /* If building the hash table and the NO-DIS attribute is present,
533 if (CGEN_INSN_ATTR (insn
, CGEN_INSN_NO_DIS
))
535 return CGEN_DIS_HASH_P (insn
);
538 /* The result is the hash value of the insn.
539 Targets are free to override CGEN_{ASM,DIS}_HASH in the .opc file. */
545 return CGEN_ASM_HASH (mnem
);
548 /* BUF is a pointer to the insn's bytes in target order.
549 VALUE is an integer of the first CGEN_BASE_INSN_BITSIZE bits,
553 dis_hash_insn (buf
, value
)
557 return CGEN_DIS_HASH (buf
, value
);
560 /* Initialize an opcode table and return a descriptor.
561 It's much like opening a file, and must be the first function called. */
564 fr30_cgen_opcode_open (mach
, endian
)
566 enum cgen_endian endian
;
568 CGEN_OPCODE_TABLE
* table
= (CGEN_OPCODE_TABLE
*) xmalloc (sizeof (CGEN_OPCODE_TABLE
));
577 memset (table
, 0, sizeof (*table
));
579 CGEN_OPCODE_MACH (table
) = mach
;
580 CGEN_OPCODE_ENDIAN (table
) = endian
;
581 /* FIXME: for the sparc case we can determine insn-endianness statically.
582 The worry here is where both data and insn endian can be independently
583 chosen, in which case this function will need another argument.
584 Actually, will want to allow for more arguments in the future anyway. */
585 CGEN_OPCODE_INSN_ENDIAN (table
) = endian
;
587 CGEN_OPCODE_HW_LIST (table
) = & fr30_cgen_hw_entries
[0];
589 CGEN_OPCODE_OPERAND_TABLE (table
) = & fr30_cgen_operand_table
[0];
591 * CGEN_OPCODE_INSN_TABLE (table
) = insn_table
;
593 * CGEN_OPCODE_MACRO_INSN_TABLE (table
) = macro_insn_table
;
595 CGEN_OPCODE_ASM_HASH_P (table
) = asm_hash_insn_p
;
596 CGEN_OPCODE_ASM_HASH (table
) = asm_hash_insn
;
597 CGEN_OPCODE_ASM_HASH_SIZE (table
) = CGEN_ASM_HASH_SIZE
;
599 CGEN_OPCODE_DIS_HASH_P (table
) = dis_hash_insn_p
;
600 CGEN_OPCODE_DIS_HASH (table
) = dis_hash_insn
;
601 CGEN_OPCODE_DIS_HASH_SIZE (table
) = CGEN_DIS_HASH_SIZE
;
603 return (CGEN_OPCODE_DESC
) table
;
606 /* Close an opcode table. */
609 fr30_cgen_opcode_close (desc
)
610 CGEN_OPCODE_DESC desc
;
615 /* Getting values from cgen_fields is handled by a collection of functions.
616 They are distinguished by the type of the VALUE argument they return.
617 TODO: floating point, inlining support, remove cases where result type
621 fr30_cgen_get_int_operand (opindex
, fields
)
623 const CGEN_FIELDS
* fields
;
629 case FR30_OPERAND_RI
:
630 value
= fields
->f_Ri
;
632 case FR30_OPERAND_RJ
:
633 value
= fields
->f_Rj
;
637 /* xgettext:c-format */
638 fprintf (stderr
, _("Unrecognized field %d while getting int operand.\n"),
647 fr30_cgen_get_vma_operand (opindex
, fields
)
649 const CGEN_FIELDS
* fields
;
655 case FR30_OPERAND_RI
:
656 value
= fields
->f_Ri
;
658 case FR30_OPERAND_RJ
:
659 value
= fields
->f_Rj
;
663 /* xgettext:c-format */
664 fprintf (stderr
, _("Unrecognized field %d while getting vma operand.\n"),
672 /* Stuffing values in cgen_fields is handled by a collection of functions.
673 They are distinguished by the type of the VALUE argument they accept.
674 TODO: floating point, inlining support, remove cases where argument type
678 fr30_cgen_set_int_operand (opindex
, fields
, value
)
680 CGEN_FIELDS
* fields
;
685 case FR30_OPERAND_RI
:
686 fields
->f_Ri
= value
;
688 case FR30_OPERAND_RJ
:
689 fields
->f_Rj
= value
;
693 /* xgettext:c-format */
694 fprintf (stderr
, _("Unrecognized field %d while setting int operand.\n"),
701 fr30_cgen_set_vma_operand (opindex
, fields
, value
)
703 CGEN_FIELDS
* fields
;
708 case FR30_OPERAND_RI
:
709 fields
->f_Ri
= value
;
711 case FR30_OPERAND_RJ
:
712 fields
->f_Rj
= value
;
716 /* xgettext:c-format */
717 fprintf (stderr
, _("Unrecognized field %d while setting vma operand.\n"),