Commit | Line | Data |
---|---|---|
ab0bd049 DE |
1 | /* Generic opcode table support for targets using CGEN. -*- C -*- |
2 | CGEN: Cpu tools GENerator | |
3 | ||
4 | This file is used to generate @arch@-opc.c. | |
5 | ||
6 | Copyright (C) 1998 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 "sysdep.h" | |
25 | #include <stdio.h> | |
26 | #include "ansidecl.h" | |
27 | #include "libiberty.h" | |
28 | #include "bfd.h" | |
29 | #include "symcat.h" | |
30 | #include "@arch@-opc.h" | |
31 | ||
32 | /* Look up instruction INSN_VALUE and extract its fields. | |
33 | If non-null INSN is the insn table entry. | |
34 | Otherwise INSN_VALUE is examined to compute it. | |
35 | LENGTH is the bit length of INSN_VALUE if known, otherwise 0. | |
390bd87d | 36 | ALIAS_P is non-zero if alias insns are to be included in the search. |
ab0bd049 DE |
37 | The result a pointer to the insn table entry, or NULL if the instruction |
38 | wasn't recognized. */ | |
39 | ||
40 | const CGEN_INSN * | |
390bd87d | 41 | @arch@_cgen_lookup_insn (insn, insn_value, length, fields, alias_p) |
ab0bd049 DE |
42 | const CGEN_INSN *insn; |
43 | cgen_insn_t insn_value; | |
44 | int length; | |
45 | CGEN_FIELDS *fields; | |
46 | { | |
390bd87d | 47 | char buf[16]; |
ab0bd049 DE |
48 | |
49 | if (!insn) | |
50 | { | |
51 | const CGEN_INSN_LIST *insn_list; | |
52 | ||
53 | #ifdef CGEN_INT_INSN | |
54 | switch (length) | |
55 | { | |
56 | case 8: | |
57 | buf[0] = insn_value; | |
58 | break; | |
59 | case 16: | |
60 | if (cgen_current_endian == CGEN_ENDIAN_BIG) | |
61 | bfd_putb16 (insn_value, buf); | |
62 | else | |
63 | bfd_putl16 (insn_value, buf); | |
64 | break; | |
65 | case 32: | |
66 | if (cgen_current_endian == CGEN_ENDIAN_BIG) | |
67 | bfd_putb32 (insn_value, buf); | |
68 | else | |
69 | bfd_putl32 (insn_value, buf); | |
70 | break; | |
71 | default: | |
72 | abort (); | |
73 | } | |
74 | #else | |
75 | abort (); /* FIXME: unfinished */ | |
76 | #endif | |
77 | ||
78 | /* The instructions are stored in hash lists. | |
79 | Pick the first one and keep trying until we find the right one. */ | |
80 | ||
81 | insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value); | |
82 | while (insn_list != NULL) | |
83 | { | |
84 | insn = insn_list->insn; | |
85 | ||
390bd87d DE |
86 | if (alias_p |
87 | || ! CGEN_INSN_ATTR (insn, CGEN_INSN_ALIAS)) | |
ab0bd049 | 88 | { |
390bd87d DE |
89 | /* Basic bit mask must be correct. */ |
90 | /* ??? May wish to allow target to defer this check until the | |
91 | extract handler. */ | |
92 | if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn)) | |
93 | { | |
94 | length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, fields); | |
95 | if (length > 0) | |
96 | return insn; | |
97 | } | |
ab0bd049 DE |
98 | } |
99 | ||
100 | insn_list = CGEN_DIS_NEXT_INSN (insn_list); | |
101 | } | |
102 | } | |
103 | else | |
104 | { | |
390bd87d DE |
105 | /* Sanity check: can't pass an alias insn if ! alias_p. */ |
106 | if (! alias_p | |
107 | && CGEN_INSN_ATTR (insn, CGEN_INSN_ALIAS)) | |
108 | abort (); | |
109 | ||
ab0bd049 DE |
110 | length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, fields); |
111 | if (length > 0) | |
112 | return insn; | |
113 | } | |
114 | ||
115 | return NULL; | |
116 | } | |
117 | ||
118 | /* Fill in the operand instances used by insn INSN_VALUE. | |
119 | If non-null INS is the insn table entry. | |
120 | Otherwise INSN_VALUE is examined to compute it. | |
121 | LENGTH is the number of bits in INSN_VALUE if known, otherwise 0. | |
122 | INDICES is a pointer to a buffer of MAX_OPERANDS ints to be filled in. | |
123 | The result a pointer to the insn table entry, or NULL if the instruction | |
124 | wasn't recognized. */ | |
125 | ||
126 | const CGEN_INSN * | |
127 | @arch@_cgen_get_insn_operands (insn, insn_value, length, indices) | |
128 | const CGEN_INSN *insn; | |
129 | cgen_insn_t insn_value; | |
130 | int length; | |
131 | int *indices; | |
132 | { | |
133 | CGEN_FIELDS fields; | |
134 | const CGEN_OPERAND_INSTANCE *opinst; | |
135 | int i; | |
136 | ||
390bd87d DE |
137 | /* FIXME: ALIAS insns are in transition from being record in the insn table |
138 | to being recorded separately as macros. They don't have semantic code | |
139 | so they can't be used here. Thus we currently always ignore the INSN | |
140 | argument. */ | |
141 | insn = @arch@_cgen_lookup_insn (NULL, insn_value, length, &fields, 0); | |
ab0bd049 DE |
142 | if (! insn) |
143 | return NULL; | |
144 | ||
145 | for (i = 0, opinst = CGEN_INSN_OPERANDS (insn); | |
146 | CGEN_OPERAND_INSTANCE_TYPE (opinst) != CGEN_OPERAND_INSTANCE_END; | |
147 | ++i, ++opinst) | |
148 | { | |
149 | const CGEN_OPERAND *op = CGEN_OPERAND_INSTANCE_OPERAND (opinst); | |
150 | if (op == NULL) | |
151 | indices[i] = CGEN_OPERAND_INSTANCE_INDEX (opinst); | |
152 | else | |
153 | indices[i] = @arch@_cgen_get_operand (CGEN_OPERAND_INDEX (op), &fields); | |
154 | } | |
155 | ||
156 | return insn; | |
157 | } |