Fix typos in ChangeLogs; fix dates in copyright notices
[platform/upstream/binutils.git] / opcodes / cgen-dis.c
1 /* CGEN generic disassembler support code.
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001
4    Free Software Foundation, Inc.
5
6    This file is part of the GNU Binutils and GDB, the GNU debugger.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License along
19    with this program; if not, write to the Free Software Foundation, Inc.,
20    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22 #include "sysdep.h"
23 #include <stdio.h>
24 #include "ansidecl.h"
25 #include "libiberty.h"
26 #include "bfd.h"
27 #include "symcat.h"
28 #include "opcode/cgen.h"
29
30 /* Subroutine of build_dis_hash_table to add INSNS to the hash table.
31
32    COUNT is the number of elements in INSNS.
33    ENTSIZE is sizeof (CGEN_IBASE) for the target.
34    ??? No longer used but leave in for now.
35    HTABLE points to the hash table.
36    HENTBUF is a pointer to sufficiently large buffer of hash entries.
37    The result is a pointer to the next entry to use.
38
39    The table is scanned backwards as additions are made to the front of the
40    list and we want earlier ones to be prefered.  */
41
42 static CGEN_INSN_LIST *
43 hash_insn_array (cd, insns, count, entsize, htable, hentbuf)
44      CGEN_CPU_DESC cd;
45      const CGEN_INSN * insns;
46      int count;
47      int entsize ATTRIBUTE_UNUSED;
48      CGEN_INSN_LIST ** htable;
49      CGEN_INSN_LIST * hentbuf;
50 {
51   int big_p = CGEN_CPU_ENDIAN (cd) == CGEN_ENDIAN_BIG;
52   int i;
53
54   for (i = count - 1; i >= 0; --i, ++hentbuf)
55     {
56       unsigned int hash;
57       char buf [4];
58       unsigned long value;
59       const CGEN_INSN *insn = &insns[i];
60
61       if (! (* cd->dis_hash_p) (insn))
62         continue;
63
64       /* We don't know whether the target uses the buffer or the base insn
65          to hash on, so set both up.  */
66
67       value = CGEN_INSN_BASE_VALUE (insn);
68       bfd_put_bits ((bfd_vma) value,
69                     buf,
70                     CGEN_INSN_MASK_BITSIZE (insn),
71                     big_p);
72       hash = (* cd->dis_hash) (buf, value);
73       hentbuf->next = htable[hash];
74       hentbuf->insn = insn;
75       htable[hash] = hentbuf;
76     }
77
78   return hentbuf;
79 }
80
81 /* Subroutine of build_dis_hash_table to add INSNS to the hash table.
82    This function is identical to hash_insn_array except the insns are
83    in a list.  */
84
85 static CGEN_INSN_LIST *
86 hash_insn_list (cd, insns, htable, hentbuf)
87      CGEN_CPU_DESC cd;
88      const CGEN_INSN_LIST *insns;
89      CGEN_INSN_LIST **htable;
90      CGEN_INSN_LIST *hentbuf;
91 {
92   int big_p = CGEN_CPU_ENDIAN (cd) == CGEN_ENDIAN_BIG;
93   const CGEN_INSN_LIST *ilist;
94
95   for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
96     {
97       unsigned int hash;
98       char buf[4];
99       unsigned long value;
100
101       if (! (* cd->dis_hash_p) (ilist->insn))
102         continue;
103
104       /* We don't know whether the target uses the buffer or the base insn
105          to hash on, so set both up.  */
106
107       value = CGEN_INSN_BASE_VALUE (ilist->insn);
108       bfd_put_bits((bfd_vma) value,
109                    buf,
110                    CGEN_INSN_MASK_BITSIZE (ilist->insn),
111                    big_p);
112       hash = (* cd->dis_hash) (buf, value);
113       hentbuf->next = htable [hash];
114       hentbuf->insn = ilist->insn;
115       htable [hash] = hentbuf;
116     }
117
118   return hentbuf;
119 }
120
121 /* Build the disassembler instruction hash table.  */
122
123 static void
124 build_dis_hash_table (cd)
125      CGEN_CPU_DESC cd;
126 {
127   int count = cgen_insn_count (cd) + cgen_macro_insn_count (cd);
128   CGEN_INSN_TABLE *insn_table = & cd->insn_table;
129   CGEN_INSN_TABLE *macro_insn_table = & cd->macro_insn_table;
130   unsigned int hash_size = cd->dis_hash_size;
131   CGEN_INSN_LIST *hash_entry_buf;
132   CGEN_INSN_LIST **dis_hash_table;
133   CGEN_INSN_LIST *dis_hash_table_entries;
134
135   /* The space allocated for the hash table consists of two parts:
136      the hash table and the hash lists.  */
137
138   dis_hash_table = (CGEN_INSN_LIST **)
139     xmalloc (hash_size * sizeof (CGEN_INSN_LIST *));
140   memset (dis_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *));
141   dis_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *)
142     xmalloc (count * sizeof (CGEN_INSN_LIST));
143
144   /* Add compiled in insns.
145      Don't include the first one as it is a reserved entry.  */
146   /* ??? It was the end of all hash chains, and also the special
147      "invalid insn" marker.  May be able to do it differently now.  */
148
149   hash_entry_buf = hash_insn_array (cd,
150                                     insn_table->init_entries + 1,
151                                     insn_table->num_init_entries - 1,
152                                     insn_table->entry_size,
153                                     dis_hash_table, hash_entry_buf);
154
155   /* Add compiled in macro-insns.  */
156
157   hash_entry_buf = hash_insn_array (cd, macro_insn_table->init_entries,
158                                     macro_insn_table->num_init_entries,
159                                     macro_insn_table->entry_size,
160                                     dis_hash_table, hash_entry_buf);
161
162   /* Add runtime added insns.
163      Later added insns will be prefered over earlier ones.  */
164
165   hash_entry_buf = hash_insn_list (cd, insn_table->new_entries,
166                                    dis_hash_table, hash_entry_buf);
167
168   /* Add runtime added macro-insns.  */
169
170   hash_insn_list (cd, macro_insn_table->new_entries,
171                   dis_hash_table, hash_entry_buf);
172
173   cd->dis_hash_table = dis_hash_table;
174   cd->dis_hash_table_entries = dis_hash_table_entries;
175 }
176
177 /* Return the first entry in the hash list for INSN.  */
178
179 CGEN_INSN_LIST *
180 cgen_dis_lookup_insn (cd, buf, value)
181      CGEN_CPU_DESC cd;
182      const char * buf;
183      CGEN_INSN_INT value;
184 {
185   unsigned int hash;
186
187   if (cd->dis_hash_table == NULL)
188     build_dis_hash_table (cd);
189
190   hash = (* cd->dis_hash) (buf, value);
191
192   return cd->dis_hash_table[hash];
193 }