1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
4 This file is used to generate m32r-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. */
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));
54 m32r_cgen_print_operand
55 PARAMS ((int opindex, disassemble_info * info, CGEN_FIELDS * fields, void const * attrs, bfd_vma pc, int length));
58 /* Default extraction routine.
60 ATTRS is a mask of the boolean attributes. We only need `unsigned',
61 but for generality we take a bitmask of all of them. */
64 extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
66 cgen_insn_t insn_value;
78 value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length)))
79 & ((1 << length) - 1));
81 value = ((insn_value >> (total_length - (start + length)))
82 & ((1 << length) - 1));
84 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
85 && (value & (1 << (length - 1))))
88 /* FIXME: unfinished */
91 /* This is backwards as we undo the effects of insert_normal. */
101 /* Default print handler. */
104 print_normal (dis_info, value, attrs, pc, length)
108 unsigned long pc; /* FIXME: should be bfd_vma */
111 disassemble_info * info = dis_info;
113 /* Print the operand as directed by the attributes. */
114 if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_FAKE))
115 ; /* nothing to do (??? at least not yet) */
116 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR))
117 (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info);
118 /* ??? Not all cases of this are currently caught. */
119 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR))
120 /* FIXME: Why & 0xffffffff? */
121 (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
122 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
123 (*info->fprintf_func) (info->stream, "0x%lx", value);
125 (*info->fprintf_func) (info->stream, "%ld", value);
128 /* Keyword print handler. */
131 print_keyword (dis_info, keyword_table, value, attrs)
133 CGEN_KEYWORD * keyword_table;
137 disassemble_info * info = dis_info;
138 const CGEN_KEYWORD_ENTRY * ke;
140 ke = cgen_keyword_lookup_value (keyword_table, value);
141 info->fprintf_func (info->stream, "%s", ke == NULL ? "???" : ke->name);
144 /* -- disassembler routines inserted here */
146 /* Default insn extractor.
148 The extracted fields are stored in DIS_FLDS.
149 BUF_CTRL is used to handle reading variable length insns (FIXME: not done).
150 Return the length of the insn in bits, or 0 if no match. */
153 extract_insn_normal (insn, buf_ctrl, insn_value, fields)
154 const CGEN_INSN * insn;
156 cgen_insn_t insn_value;
157 CGEN_FIELDS * fields;
159 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
160 const unsigned char * syn;
162 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
164 CGEN_INIT_EXTRACT ();
166 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
170 if (CGEN_SYNTAX_CHAR_P (* syn))
173 length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (* syn),
174 buf_ctrl, insn_value, fields);
179 /* We recognized and successfully extracted this insn. */
180 return CGEN_INSN_BITSIZE (insn);
183 /* Default insn printer.
185 DIS_INFO is defined as `void *' so the disassembler needn't know anything
186 about disassemble_info.
190 print_insn_normal (dis_info, insn, fields, pc, length)
192 const CGEN_INSN * insn;
193 CGEN_FIELDS * fields;
197 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
198 disassemble_info * info = dis_info;
199 const unsigned char * syn;
203 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
205 if (CGEN_SYNTAX_MNEMONIC_P (* syn))
207 info->fprintf_func (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
210 if (CGEN_SYNTAX_CHAR_P (* syn))
212 info->fprintf_func (info->stream, "%c", CGEN_SYNTAX_CHAR (* syn));
216 /* We have an operand. */
217 m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (* syn), info,
218 fields, CGEN_INSN_ATTRS (insn), pc, length);
222 /* Default value for CGEN_PRINT_INSN.
223 Given BUFLEN bytes (target byte order) read into BUF, look up the
224 insn in the instruction table and disassemble it.
226 The result is the size of the insn in bytes. */
228 #ifndef CGEN_PRINT_INSN
229 #define CGEN_PRINT_INSN print_insn
233 print_insn (pc, info, buf, buflen)
235 disassemble_info * info;
240 unsigned long insn_value;
241 const CGEN_INSN_LIST * insn_list;
250 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
253 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
259 /* Special case - a 32 bit instruction which is actually two 16 bit instructions
260 being executed in parallel. */
263 && ((insn_value & 0x80008000) == 0x00008000))
265 if (info->endian == BFD_ENDIAN_BIG)
267 static char buf2 [4];
269 print_insn (pc, info, buf, 16);
271 info->fprintf_func (info->stream, " || ");
273 buf2 [0] = buf [2] & ~ 0x80;
284 print_insn (pc, info, buf + 2, 16);
286 info->fprintf_func (info->stream, " || ");
288 insn_value &= 0x7fff;
297 /* The instructions are stored in hash lists.
298 Pick the first one and keep trying until we find the right one. */
300 insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value);
302 while (insn_list != NULL)
304 const CGEN_INSN * insn = insn_list->insn;
307 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
308 /* Supported by this cpu? */
309 if (! m32r_cgen_insn_supported (insn))
313 /* If we are looking at a 16 bit insn we may have to adjust the value being examined. */
315 if (CGEN_INSN_BITSIZE (insn) == 16)
317 /* If this is a big endian target,
318 and we have read 32 bits for the instruction value,
319 then we must examine the top 16 bits, not the bottom. */
320 if (buflen == 32 && info->endian == BFD_ENDIAN_BIG)
324 /* Basic bit mask must be correct. */
325 /* ??? May wish to allow target to defer this check until the extract
327 if ((value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
332 /* Printing is handled in two passes. The first pass parses the
333 machine insn and extracts the fields. The second pass prints
336 length = CGEN_EXTRACT_FN (insn) (insn, NULL, value, & fields);
339 CGEN_PRINT_FN (insn) (info, insn, & fields, pc, length);
341 /* length is in bits, result is in bytes */
342 return (length / 8) + extra_bytes;
346 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
353 Print one instruction from PC on INFO->STREAM.
354 Return the size of the instruction (in bytes). */
357 print_insn_m32r (pc, info)
359 disassemble_info * info;
361 char buffer [CGEN_MAX_INSN_SIZE];
364 static int initialized = 0;
365 static int current_mach = 0;
366 static int current_bigend = 0;
367 int mach = info->mach;
368 int bigend = info->endian == BFD_ENDIAN_BIG;
370 /* If we haven't initialized yet, or if we've switched cpu's, initialize. */
371 if (!initialized || mach != current_mach || bigend != current_bigend)
375 current_bigend = bigend;
377 m32r_cgen_init_dis (mach, bigend ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
380 /* Read enough of the insn so we can look it up in the hash lists. */
382 status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE, info);
385 /* Try reading a 16 bit instruction. */
386 info->bytes_per_chunk = 2;
387 status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE / 2, info);
388 buffer [2] = buffer [3] = 0;
392 info->memory_error_func (status, pc, info);
396 /* We try to have as much common code as possible.
397 But at this point some targets need to take over. */
398 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
399 but if not possible try to move this hook elsewhere rather than
401 length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
406 info->fprintf_func (info->stream, UNKNOWN_INSN_MSG);
408 return CGEN_DEFAULT_INSN_SIZE;
411 /* Get the generate machine specific code. */
412 #include "m32r-dis.in"