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