014d9a352221788a18cbf6c55f9a18ff094d86b1
[deliverable/binutils-gdb.git] / opcodes / cgen-opc.in
1 /* Generic opcode table support for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4 THIS FILE IS USED TO GENERATE @prefix@-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 Foundation, Inc.,
22 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 "@prefix@-opc.h"
31 #include "opintl.h"
32
33 /* The hash functions are recorded here to help keep assembler code out of
34 the disassembler and vice versa. */
35
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));
40
41 /* Cover function to read and properly byteswap an insn value. */
42
43 CGEN_INSN_INT
44 cgen_get_insn_value (od, buf, length)
45 CGEN_OPCODE_DESC od;
46 unsigned char *buf;
47 int length;
48 {
49 CGEN_INSN_INT value;
50
51 switch (length)
52 {
53 case 8:
54 value = *buf;
55 break;
56 case 16:
57 if (CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG)
58 value = bfd_getb16 (buf);
59 else
60 value = bfd_getl16 (buf);
61 break;
62 case 32:
63 if (CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG)
64 value = bfd_getb32 (buf);
65 else
66 value = bfd_getl32 (buf);
67 break;
68 default:
69 abort ();
70 }
71
72 return value;
73 }
74
75 /* Cover function to store an insn value properly byteswapped. */
76
77 void
78 cgen_put_insn_value (od, buf, length, value)
79 CGEN_OPCODE_DESC od;
80 unsigned char *buf;
81 int length;
82 CGEN_INSN_INT value;
83 {
84 switch (length)
85 {
86 case 8:
87 buf[0] = value;
88 break;
89 case 16:
90 if (CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG)
91 bfd_putb16 (value, buf);
92 else
93 bfd_putl16 (value, buf);
94 break;
95 case 32:
96 if (CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG)
97 bfd_putb32 (value, buf);
98 else
99 bfd_putl32 (value, buf);
100 break;
101 default:
102 abort ();
103 }
104 }
105
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.
113
114 The result a pointer to the insn table entry, or NULL if the instruction
115 wasn't recognized. */
116
117 const CGEN_INSN *
118 @arch@_cgen_lookup_insn (od, insn, insn_value, length, fields, alias_p)
119 CGEN_OPCODE_DESC od;
120 const CGEN_INSN *insn;
121 CGEN_INSN_BYTES insn_value;
122 int length;
123 CGEN_FIELDS *fields;
124 int alias_p;
125 {
126 unsigned char buf[16];
127 unsigned char *bufp;
128 unsigned int base_insn;
129 #if CGEN_INT_INSN_P
130 CGEN_EXTRACT_INFO *info = NULL;
131 #else
132 CGEN_EXTRACT_INFO ex_info;
133 CGEN_EXTRACT_INFO *info = &ex_info;
134 #endif
135
136 #if ! CGEN_INT_INSN_P
137 ex_info.dis_info = NULL;
138 ex_info.bytes = insn_value;
139 ex_info.valid = -1;
140 #endif
141
142 if (!insn)
143 {
144 const CGEN_INSN_LIST *insn_list;
145
146 #if CGEN_INT_INSN_P
147 cgen_put_insn_value (od, buf, length, insn_value);
148 bufp = buf;
149 base_insn = insn_value; /*???*/
150 #else
151 base_insn = cgen_get_insn_value (od, buf, length);
152 bufp = insn_value;
153 #endif
154
155 /* The instructions are stored in hash lists.
156 Pick the first one and keep trying until we find the right one. */
157
158 insn_list = CGEN_DIS_LOOKUP_INSN (od, bufp, base_insn);
159 while (insn_list != NULL)
160 {
161 insn = insn_list->insn;
162
163 if (alias_p
164 || ! CGEN_INSN_ATTR (insn, CGEN_INSN_ALIAS))
165 {
166 /* Basic bit mask must be correct. */
167 /* ??? May wish to allow target to defer this check until the
168 extract handler. */
169 if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
170 {
171 /* ??? 0 is passed for `pc' */
172 int elength = (*CGEN_EXTRACT_FN (insn)) (od, insn, info,
173 insn_value, fields,
174 (bfd_vma) 0);
175 if (elength > 0)
176 {
177 /* sanity check */
178 if (length != 0 && length != elength)
179 abort ();
180 return insn;
181 }
182 }
183 }
184
185 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
186 }
187 }
188 else
189 {
190 /* Sanity check: can't pass an alias insn if ! alias_p. */
191 if (! alias_p
192 && CGEN_INSN_ATTR (insn, CGEN_INSN_ALIAS))
193 abort ();
194 /* Sanity check: length must be correct. */
195 if (length != CGEN_INSN_BITSIZE (insn))
196 abort ();
197
198 /* ??? 0 is passed for `pc' */
199 length = (*CGEN_EXTRACT_FN (insn)) (od, insn, info, insn_value, fields,
200 (bfd_vma) 0);
201 /* Sanity check: must succeed.
202 Could relax this later if it ever proves useful. */
203 if (length == 0)
204 abort ();
205 return insn;
206 }
207
208 return NULL;
209 }
210
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
213 in. */
214
215 void
216 @arch@_cgen_get_insn_operands (od, insn, fields, indices)
217 CGEN_OPCODE_DESC od;
218 const CGEN_INSN * insn;
219 const CGEN_FIELDS * fields;
220 int *indices;
221 {
222 const CGEN_OPERAND_INSTANCE *opinst;
223 int i;
224
225 for (i = 0, opinst = CGEN_INSN_OPERANDS (insn);
226 opinst != NULL
227 && CGEN_OPERAND_INSTANCE_TYPE (opinst) != CGEN_OPERAND_INSTANCE_END;
228 ++i, ++opinst)
229 {
230 const CGEN_OPERAND *op = CGEN_OPERAND_INSTANCE_OPERAND (opinst);
231 if (op == NULL)
232 indices[i] = CGEN_OPERAND_INSTANCE_INDEX (opinst);
233 else
234 indices[i] = @arch@_cgen_get_int_operand (CGEN_OPERAND_INDEX (op),
235 fields);
236 }
237 }
238
239 /* Cover function to @arch@_cgen_get_insn_operands when either INSN or FIELDS
240 isn't known.
241 The INSN, INSN_VALUE, and LENGTH arguments are passed to
242 @arch@_cgen_lookup_insn unchanged.
243
244 The result is the insn table entry or NULL if the instruction wasn't
245 recognized. */
246
247 const CGEN_INSN *
248 @arch@_cgen_lookup_get_insn_operands (od, insn, insn_value, length, indices)
249 CGEN_OPCODE_DESC od;
250 const CGEN_INSN *insn;
251 CGEN_INSN_BYTES insn_value;
252 int length;
253 int *indices;
254 {
255 CGEN_FIELDS fields;
256
257 /* Pass non-zero for ALIAS_P only if INSN != NULL.
258 If INSN == NULL, we want a real insn. */
259 insn = @arch@_cgen_lookup_insn (od, insn, insn_value, length, &fields,
260 insn != NULL);
261 if (! insn)
262 return NULL;
263
264 @arch@_cgen_get_insn_operands (od, insn, &fields, indices);
265 return insn;
266 }
This page took 0.036917 seconds and 3 git commands to generate.