1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
4 This file is used to generate @arch@-dis.c.
6 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
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)
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.
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. */
29 #include "@arch@-opc.h"
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.
38 /* Default text to print if an instruction isn't recognized. */
39 #define UNKNOWN_INSN_MSG "*unknown*"
41 /* FIXME: Machine generate. */
42 #ifndef CGEN_PCREL_OFFSET
43 #define CGEN_PCREL_OFFSET 0
46 static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int));
48 static int extract_insn_normal
49 PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *));
50 static void print_insn_normal
51 PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int));
53 /* Default extraction routine.
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. */
59 extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
61 cgen_insn_t insn_value;
63 int start, length, shift, total_length;
70 value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length)))
71 & ((1 << length) - 1));
73 value = ((insn_value >> (total_length - (start + length)))
74 & ((1 << length) - 1));
76 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
77 && (value & (1 << (length - 1))))
80 /* FIXME: unfinished */
83 /* This is backwards as we undo the effects of insert_normal. */
93 /* Default print handler. */
96 print_normal (dis_info, value, attrs, pc, length)
100 unsigned long pc; /* FIXME: should be bfd_vma */
103 disassemble_info *info = dis_info;
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);
117 (*info->fprintf_func) (info->stream, "%ld", value);
120 /* Keyword print handler. */
123 print_keyword (dis_info, keyword_table, value, attrs)
125 CGEN_KEYWORD *keyword_table;
129 disassemble_info *info = dis_info;
130 const CGEN_KEYWORD_ENTRY *ke;
132 ke = cgen_keyword_lookup_value (keyword_table, value);
134 (*info->fprintf_func) (info->stream, "%s", ke->name);
136 (*info->fprintf_func) (info->stream, "???");
139 /* -- disassembler routines inserted here */
141 /* Default insn extractor.
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. */
148 extract_insn_normal (insn, buf_ctrl, insn_value, fields)
149 const CGEN_INSN *insn;
151 cgen_insn_t insn_value;
154 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
155 const unsigned char *syn;
157 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
159 CGEN_INIT_EXTRACT ();
161 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
165 if (CGEN_SYNTAX_CHAR_P (*syn))
168 length = @arch@_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn),
169 buf_ctrl, insn_value, fields);
174 /* We recognized and successfully extracted this insn. */
175 return CGEN_INSN_BITSIZE (insn);
178 /* Default insn printer.
180 DIS_INFO is defined as `void *' so the disassembler needn't know anything
181 about disassemble_info.
185 print_insn_normal (dis_info, insn, fields, pc, length)
187 const CGEN_INSN *insn;
192 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
193 disassemble_info *info = dis_info;
194 const unsigned char *syn;
198 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
200 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
202 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
205 if (CGEN_SYNTAX_CHAR_P (*syn))
207 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
211 /* We have an operand. */
212 @arch@_cgen_print_operand (CGEN_SYNTAX_FIELD (*syn), info,
213 fields, CGEN_INSN_ATTRS (insn), pc, length);
217 /* Default value for CGEN_PRINT_INSN.
218 Given BUFLEN bytes (target byte order) read into BUF, look up the
219 insn in the instruction table and disassemble it.
221 The result is the size of the insn in bytes. */
223 #ifndef CGEN_PRINT_INSN
224 #define CGEN_PRINT_INSN print_insn
228 print_insn (pc, info, buf, buflen)
230 disassemble_info *info;
235 unsigned long insn_value;
236 const CGEN_INSN_LIST *insn_list;
244 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
247 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
253 /* The instructions are stored in hash lists.
254 Pick the first one and keep trying until we find the right one. */
256 insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value);
257 while (insn_list != NULL)
259 const CGEN_INSN *insn = insn_list->insn;
260 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
264 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
265 /* Supported by this cpu? */
266 if (! @arch@_cgen_insn_supported (insn))
270 /* Basic bit mask must be correct. */
271 /* ??? May wish to allow target to defer this check until the extract
273 if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
275 /* Printing is handled in two passes. The first pass parses the
276 machine insn and extracts the fields. The second pass prints
279 length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields);
282 (*CGEN_PRINT_FN (insn)) (info, insn, &fields, pc, length);
283 /* length is in bits, result is in bytes */
288 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
295 Print one instruction from PC on INFO->STREAM.
296 Return the size of the instruction (in bytes). */
299 print_insn_@arch@ (pc, info)
301 disassemble_info *info;
303 char buffer[CGEN_MAX_INSN_SIZE];
305 static int initialized = 0;
306 static int current_mach = 0;
307 static int current_big_p = 0;
308 int mach = info->mach;
309 int big_p = info->endian == BFD_ENDIAN_BIG;
311 /* If we haven't initialized yet, or if we've switched cpu's, initialize. */
312 if (!initialized || mach != current_mach || big_p != current_big_p)
316 current_big_p = big_p;
317 @arch@_cgen_init_dis (mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
320 /* Read enough of the insn so we can look it up in the hash lists. */
322 status = (*info->read_memory_func) (pc, buffer, CGEN_BASE_INSN_SIZE, info);
325 (*info->memory_error_func) (status, pc, info);
329 /* We try to have as much common code as possible.
330 But at this point some targets need to take over. */
331 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
332 but if not possible try to move this hook elsewhere rather than
334 length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
338 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
339 return CGEN_DEFAULT_INSN_SIZE;