OSDN Git Service

Initial revision
[pf3gnuchains/pf3gnuchains3x.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;
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       switch (CGEN_INSN_MASK_BITSIZE (insn))
68         {
69         case 8:
70           buf[0] = value;
71           break;
72         case 16:
73           if (big_p)
74             bfd_putb16 ((bfd_vma) value, buf);
75           else
76             bfd_putl16 ((bfd_vma) value, buf);
77           break;
78         case 32:
79           if (big_p)
80             bfd_putb32 ((bfd_vma) value, buf);
81           else
82             bfd_putl32 ((bfd_vma) value, buf);
83           break;
84         default:
85           abort ();
86         }
87
88       hash = (* cd->dis_hash) (buf, value);
89       hentbuf->next = htable[hash];
90       hentbuf->insn = insn;
91       htable[hash] = hentbuf;
92     }
93
94   return hentbuf;
95 }
96
97 /* Subroutine of build_dis_hash_table to add INSNS to the hash table.
98    This function is identical to hash_insn_array except the insns are
99    in a list.  */
100
101 static CGEN_INSN_LIST *
102 hash_insn_list (cd, insns, htable, hentbuf)
103      CGEN_CPU_DESC cd;
104      const CGEN_INSN_LIST *insns;
105      CGEN_INSN_LIST **htable;
106      CGEN_INSN_LIST *hentbuf;
107 {
108   int big_p = CGEN_CPU_ENDIAN (cd) == CGEN_ENDIAN_BIG;
109   const CGEN_INSN_LIST *ilist;
110
111   for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
112     {
113       unsigned int hash;
114       char buf[4];
115       unsigned long value;
116
117       if (! (* cd->dis_hash_p) (ilist->insn))
118         continue;
119
120       /* We don't know whether the target uses the buffer or the base insn
121          to hash on, so set both up.  */
122
123       value = CGEN_INSN_BASE_VALUE (ilist->insn);
124       switch (CGEN_INSN_MASK_BITSIZE (ilist->insn))
125         {
126         case 8:
127           buf[0] = value;
128           break;
129         case 16:
130           if (big_p)
131             bfd_putb16 ((bfd_vma) value, buf);
132           else
133             bfd_putl16 ((bfd_vma) value, buf);
134           break;
135         case 32:
136           if (big_p)
137             bfd_putb32 ((bfd_vma) value, buf);
138           else
139             bfd_putl32 ((bfd_vma) value, buf);
140           break;
141         default:
142           abort ();
143         }
144
145       hash = (* cd->dis_hash) (buf, value);
146       hentbuf->next = htable [hash];
147       hentbuf->insn = ilist->insn;
148       htable [hash] = hentbuf;
149     }
150
151   return hentbuf;
152 }
153
154 /* Build the disassembler instruction hash table.  */
155
156 static void
157 build_dis_hash_table (cd)
158      CGEN_CPU_DESC cd;
159 {
160   int count = cgen_insn_count (cd) + cgen_macro_insn_count (cd);
161   CGEN_INSN_TABLE *insn_table = & cd->insn_table;
162   CGEN_INSN_TABLE *macro_insn_table = & cd->macro_insn_table;
163   unsigned int hash_size = cd->dis_hash_size;
164   CGEN_INSN_LIST *hash_entry_buf;
165   CGEN_INSN_LIST **dis_hash_table;
166   CGEN_INSN_LIST *dis_hash_table_entries;
167
168   /* The space allocated for the hash table consists of two parts:
169      the hash table and the hash lists.  */
170
171   dis_hash_table = (CGEN_INSN_LIST **)
172     xmalloc (hash_size * sizeof (CGEN_INSN_LIST *));
173   memset (dis_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *));
174   dis_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *)
175     xmalloc (count * sizeof (CGEN_INSN_LIST));
176
177   /* Add compiled in insns.
178      Don't include the first one as it is a reserved entry.  */
179   /* ??? It was the end of all hash chains, and also the special
180      "invalid insn" marker.  May be able to do it differently now.  */
181
182   hash_entry_buf = hash_insn_array (cd,
183                                     insn_table->init_entries + 1,
184                                     insn_table->num_init_entries - 1,
185                                     insn_table->entry_size,
186                                     dis_hash_table, hash_entry_buf);
187
188   /* Add compiled in macro-insns.  */
189
190   hash_entry_buf = hash_insn_array (cd, macro_insn_table->init_entries,
191                                     macro_insn_table->num_init_entries,
192                                     macro_insn_table->entry_size,
193                                     dis_hash_table, hash_entry_buf);
194
195   /* Add runtime added insns.
196      Later added insns will be prefered over earlier ones.  */
197
198   hash_entry_buf = hash_insn_list (cd, insn_table->new_entries,
199                                    dis_hash_table, hash_entry_buf);
200
201   /* Add runtime added macro-insns.  */
202
203   hash_insn_list (cd, macro_insn_table->new_entries,
204                   dis_hash_table, hash_entry_buf);
205
206   cd->dis_hash_table = dis_hash_table;
207   cd->dis_hash_table_entries = dis_hash_table_entries;
208 }
209
210 /* Return the first entry in the hash list for INSN.  */
211
212 CGEN_INSN_LIST *
213 cgen_dis_lookup_insn (cd, buf, value)
214      CGEN_CPU_DESC cd;
215      const char * buf;
216      CGEN_INSN_INT value;
217 {
218   unsigned int hash;
219
220   if (cd->dis_hash_table == NULL)
221     build_dis_hash_table (cd);
222
223   hash = (* cd->dis_hash) (buf, value);
224
225   return cd->dis_hash_table[hash];
226 }