]> Git Repo - binutils.git/blob - opcodes/cgen-opc.in
* m32r-asm.c: Regenerate.
[binutils.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 @[email protected].
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 "@[email protected]"
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.03874 seconds and 4 git commands to generate.