This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / opcodes / cgen-dis.in
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4 This file is used to generate @arch@-dis.c.
5
6 Copyright (C) 1996, 1997 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
22 Foundation, Inc., 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 "dis-asm.h"
28 #include "bfd.h"
29 #include "symcat.h"
30 #include "@arch@-opc.h"
31
32 /* ??? The layout of this stuff is still work in progress.
33 For speed in assembly/disassembly, we use inline functions. That of course
34 will only work for GCC. When this stuff is finished, we can decide whether
35 to keep the inline functions (and only get the performance increase when
36 compiled with GCC), or switch to macros, or use something else.
37 */
38
39 /* Default text to print if an instruction isn't recognized. */
40 #define UNKNOWN_INSN_MSG "*unknown*"
41
42 /* FIXME: Machine generate. */
43 #ifndef CGEN_PCREL_OFFSET
44 #define CGEN_PCREL_OFFSET 0
45 #endif
46
47 static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int));
48
49 static int extract_insn_normal
50 PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *));
51 static void print_insn_normal
52 PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int));
53 \f
54 /* Default extraction routine.
55
56 ATTRS is a mask of the boolean attributes. We only need `unsigned',
57 but for generality we take a bitmask of all of them. */
58
59 static int
60 extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
61 PTR buf_ctrl;
62 cgen_insn_t insn_value;
63 unsigned int attrs;
64 int start, length, shift, total_length;
65 long *valuep;
66 {
67 long value;
68
69 #ifdef CGEN_INT_INSN
70 #if 0
71 value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length)))
72 & ((1 << length) - 1));
73 #else
74 value = ((insn_value >> (total_length - (start + length)))
75 & ((1 << length) - 1));
76 #endif
77 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
78 && (value & (1 << (length - 1))))
79 value -= 1 << length;
80 #else
81 /* FIXME: unfinished */
82 #endif
83
84 /* This is backwards as we undo the effects of insert_normal. */
85 if (shift < 0)
86 value >>= -shift;
87 else
88 value <<= shift;
89
90 *valuep = value;
91
92 /* FIXME: for now */
93 return 1;
94 }
95
96 /* Default print handler. */
97
98 static void
99 print_normal (dis_info, value, attrs, pc, length)
100 PTR dis_info;
101 long value;
102 unsigned int attrs;
103 unsigned long pc; /* FIXME: should be bfd_vma */
104 int length;
105 {
106 disassemble_info *info = dis_info;
107
108 /* Print the operand as directed by the attributes. */
109 if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_FAKE))
110 ; /* nothing to do (??? at least not yet) */
111 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR))
112 (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info);
113 /* ??? Not all cases of this are currently caught. */
114 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR))
115 /* FIXME: Why & 0xffffffff? */
116 (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
117 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
118 (*info->fprintf_func) (info->stream, "0x%lx", value);
119 else
120 (*info->fprintf_func) (info->stream, "%ld", value);
121 }
122
123 /* Keyword print handler. */
124
125 static void
126 print_keyword (dis_info, keyword_table, value, attrs)
127 PTR dis_info;
128 CGEN_KEYWORD *keyword_table;
129 long value;
130 CGEN_ATTR *attrs;
131 {
132 disassemble_info *info = dis_info;
133 const CGEN_KEYWORD_ENTRY *ke;
134
135 ke = cgen_keyword_lookup_value (keyword_table, value);
136 if (ke != NULL)
137 (*info->fprintf_func) (info->stream, "%s", ke->name);
138 else
139 (*info->fprintf_func) (info->stream, "???");
140 }
141 \f
142 /* -- disassembler routines inserted here */
143 \f
144 /* Default insn extractor.
145
146 The extracted fields are stored in DIS_FLDS.
147 BUF_CTRL is used to handle reading variable length insns (FIXME: not done).
148 Return the length of the insn in bits, or 0 if no match. */
149
150 static int
151 extract_insn_normal (insn, buf_ctrl, insn_value, fields)
152 const CGEN_INSN *insn;
153 PTR buf_ctrl;
154 cgen_insn_t insn_value;
155 CGEN_FIELDS *fields;
156 {
157 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
158 const unsigned char *syn;
159
160 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
161
162 CGEN_INIT_EXTRACT ();
163
164 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
165 {
166 int length;
167
168 if (CGEN_SYNTAX_CHAR_P (*syn))
169 continue;
170
171 length = @arch@_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn),
172 buf_ctrl, insn_value, fields);
173 if (length == 0)
174 return 0;
175 }
176
177 /* We recognized and successfully extracted this insn. */
178 return CGEN_INSN_BITSIZE (insn);
179 }
180
181 /* Default insn printer.
182
183 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
184 about disassemble_info.
185 */
186
187 static void
188 print_insn_normal (dis_info, insn, fields, pc, length)
189 PTR dis_info;
190 const CGEN_INSN *insn;
191 CGEN_FIELDS *fields;
192 bfd_vma pc;
193 int length;
194 {
195 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
196 disassemble_info *info = dis_info;
197 const unsigned char *syn;
198
199 CGEN_INIT_PRINT ();
200
201 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
202 {
203 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
204 {
205 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
206 continue;
207 }
208 if (CGEN_SYNTAX_CHAR_P (*syn))
209 {
210 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
211 continue;
212 }
213
214 /* We have an operand. */
215 @arch@_cgen_print_operand (CGEN_SYNTAX_FIELD (*syn), info,
216 fields, CGEN_INSN_ATTRS (insn), pc, length);
217 }
218 }
219 \f
220 /* Default value for CGEN_PRINT_INSN.
221 Given BUFLEN bits (target byte order) read into BUF, look up the
222 insn in the instruction table and disassemble it.
223
224 The result is the size of the insn in bytes. */
225
226 #ifndef CGEN_PRINT_INSN
227 #define CGEN_PRINT_INSN print_insn
228 #endif
229
230 static int
231 print_insn (pc, info, buf, buflen)
232 bfd_vma pc;
233 disassemble_info *info;
234 char *buf;
235 int buflen;
236 {
237 unsigned long insn_value;
238 const CGEN_INSN_LIST *insn_list;
239
240 switch (buflen)
241 {
242 case 8:
243 insn_value = buf[0];
244 break;
245 case 16:
246 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
247 break;
248 case 32:
249 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
250 break;
251 default:
252 abort ();
253 }
254
255 /* The instructions are stored in hash lists.
256 Pick the first one and keep trying until we find the right one. */
257
258 insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value);
259 while (insn_list != NULL)
260 {
261 const CGEN_INSN *insn = insn_list->insn;
262 CGEN_FIELDS fields;
263 int length;
264
265 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
266 /* Supported by this cpu? */
267 if (! @arch@_cgen_insn_supported (insn))
268 continue;
269 #endif
270
271 /* Basic bit mask must be correct. */
272 /* ??? May wish to allow target to defer this check until the extract
273 handler. */
274 if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
275 {
276 /* Printing is handled in two passes. The first pass parses the
277 machine insn and extracts the fields. The second pass prints
278 them. */
279
280 length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields);
281 if (length > 0)
282 {
283 (*CGEN_PRINT_FN (insn)) (info, insn, &fields, pc, length);
284 /* length is in bits, result is in bytes */
285 return length / 8;
286 }
287 }
288
289 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
290 }
291
292 return 0;
293 }
294
295 /* Main entry point.
296 Print one instruction from PC on INFO->STREAM.
297 Return the size of the instruction (in bytes). */
298
299 int
300 print_insn_@arch@ (pc, info)
301 bfd_vma pc;
302 disassemble_info *info;
303 {
304 char buffer[CGEN_MAX_INSN_SIZE];
305 int status, length;
306 static int initialized = 0;
307 static int current_mach = 0;
308 static int current_big_p = 0;
309 int mach = info->mach;
310 int big_p = info->endian == BFD_ENDIAN_BIG;
311
312 /* If we haven't initialized yet, or if we've switched cpu's, initialize. */
313 if (!initialized || mach != current_mach || big_p != current_big_p)
314 {
315 initialized = 1;
316 current_mach = mach;
317 current_big_p = big_p;
318 @arch@_cgen_init_dis (mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
319 }
320
321 /* Read enough of the insn so we can look it up in the hash lists. */
322
323 status = (*info->read_memory_func) (pc, buffer, CGEN_BASE_INSN_SIZE, info);
324 if (status != 0)
325 {
326 (*info->memory_error_func) (status, pc, info);
327 return -1;
328 }
329
330 /* We try to have as much common code as possible.
331 But at this point some targets need to take over. */
332 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
333 but if not possible try to move this hook elsewhere rather than
334 have two hooks. */
335 length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
336 if (length)
337 return length;
338
339 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
340 return CGEN_DEFAULT_INSN_SIZE;
341 }
This page took 0.04511 seconds and 5 git commands to generate.