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