1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
4 THIS FILE IS USED TO GENERATE @prefix@-dis.c.
6 Copyright (C) 1996, 1997, 1998 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 Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
30 #include "@prefix@-opc.h"
35 #define INLINE __inline__
40 /* Default text to print if an instruction isn't recognized. */
41 #define UNKNOWN_INSN_MSG _("*unknown*")
43 static int extract_normal
44 PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_BYTES,
45 unsigned int, int, int, int, long *));
46 static void print_normal
47 PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int));
48 static void print_address
49 PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
50 static void print_keyword
51 PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
52 static int extract_insn_normal
53 PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
54 unsigned long, CGEN_FIELDS *, bfd_vma));
55 static void print_insn_normal
56 PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
58 static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma,
59 disassemble_info *, char *, int));
60 static int default_print_insn
61 PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *));
63 /* -- disassembler routines inserted here */
67 /* Subroutine of extract_normal. */
70 extract_1 (od, ex_info, start, length, word_length, bufp)
72 CGEN_EXTRACT_INFO *info;
73 int start,length,word_length;
78 int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG;
80 /* FIXME: Need to use ex_info to ensure bytes have been fetched. */
89 x = bfd_getb16 (bufp);
91 x = bfd_getl16 (bufp);
94 /* ??? This may need reworking as these cases don't necessarily
95 want the first byte and the last two bytes handled like this. */
97 x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1);
99 x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16);
103 x = bfd_getb32 (bufp);
105 x = bfd_getl32 (bufp);
111 /* Written this way to avoid undefined behaviour. */
112 mask = (((1L << (length - 1)) - 1) << 1) | 1;
113 if (CGEN_INSN_LSB0_P)
116 shift = (word_length - (start + length));
117 return (x >> shift) & mask;
120 #endif /* ! CGEN_INT_INSN_P */
122 /* Default extraction routine.
124 ATTRS is a mask of the boolean attributes. We only need `unsigned',
125 but for generality we take a bitmask of all of them. */
127 /* ??? This doesn't handle bfd_vma's. Create another function when
131 extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep)
133 CGEN_EXTRACT_INFO *ex_info;
134 CGEN_INSN_BYTES insn_value;
136 int start, length, total_length;
141 /* If LENGTH is zero, this operand doesn't contribute to the value
142 so give it a standard value of zero. */
152 /* Written this way to avoid undefined behaviour. */
153 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
155 if (CGEN_INSN_LSB0_P)
156 value = insn_value >> start;
158 value = insn_value >> (total_length - (start + length));
161 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
162 && (value & (1L << (length - 1))))
168 /* The hard case is probably too slow for the normal cases.
169 It's certainly more difficult to understand than the normal case.
170 Thus this is split into two. Keep it that way. The hard case is defined
171 to be when a field straddles a (loosely defined) word boundary
172 (??? which may require target specific help to determine). */
176 #define HARD_CASE_P 0 /* FIXME:wip */
184 unsigned char *bufp = (unsigned char *) insn_value;
189 /* Adjust start,total_length,bufp to point to the pseudo-word that holds
190 the value. For example in a 48 bit insn where the value to insert
191 (say an immediate value) is the last 16 bits then word_length here
192 would be 16. To handle a 24 bit insn with an 18 bit immediate,
193 extract_1 handles 24 bits (using a combination of bfd_get8,16). */
195 if (total_length > 32)
197 int needed_width = start % 8 + length;
198 int fetch_length = (needed_width <= 8 ? 8
199 : needed_width <= 16 ? 16
202 if (CGEN_INSN_LSB0_P)
204 if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
210 int offset = start & ~7;
214 total_length -= offset;
219 if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
221 int offset = start & ~7;
225 total_length -= offset;
234 /* FIXME: which bytes are being extracted have been lost. */
235 value = extract_1 (od, ex_info, start, length, total_length, bufp);
238 #endif /* ! CGEN_INT_INSN_P */
246 /* Default print handler. */
249 print_normal (od, dis_info, value, attrs, pc, length)
257 disassemble_info *info = (disassemble_info *) dis_info;
259 #ifdef CGEN_PRINT_NORMAL
260 CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length);
263 /* Print the operand as directed by the attributes. */
264 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
265 ; /* nothing to do */
266 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
267 (*info->fprintf_func) (info->stream, "0x%lx", value);
269 (*info->fprintf_func) (info->stream, "%ld", value);
272 /* Default address handler. */
275 print_address (od, dis_info, value, attrs, pc, length)
283 disassemble_info *info = (disassemble_info *) dis_info;
285 #ifdef CGEN_PRINT_ADDRESS
286 CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length);
289 /* Print the operand as directed by the attributes. */
290 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
291 ; /* nothing to do */
292 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
293 (*info->print_address_func) (value, info);
294 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
295 (*info->print_address_func) (value, info);
296 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
297 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
299 (*info->fprintf_func) (info->stream, "%ld", (long) value);
302 /* Keyword print handler. */
305 print_keyword (od, dis_info, keyword_table, value, attrs)
308 CGEN_KEYWORD *keyword_table;
312 disassemble_info *info = (disassemble_info *) dis_info;
313 const CGEN_KEYWORD_ENTRY *ke;
315 ke = cgen_keyword_lookup_value (keyword_table, value);
317 (*info->fprintf_func) (info->stream, "%s", ke->name);
319 (*info->fprintf_func) (info->stream, "???");
322 /* Default insn extractor.
324 INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order.
325 The extracted fields are stored in FIELDS.
326 EX_INFO is used to handle reading variable length insns.
327 Return the length of the insn in bits, or 0 if no match,
328 or -1 if an error occurs fetching data (memory_error_func will have
332 extract_insn_normal (od, insn, ex_info, insn_value, fields, pc)
334 const CGEN_INSN *insn;
335 CGEN_EXTRACT_INFO *ex_info;
336 unsigned long insn_value;
340 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
341 const unsigned char *syn;
343 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
345 CGEN_INIT_EXTRACT (od);
347 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
351 if (CGEN_SYNTAX_CHAR_P (*syn))
354 length = @arch@_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn),
355 ex_info, insn_value, fields, pc);
360 /* We recognized and successfully extracted this insn. */
361 return CGEN_INSN_BITSIZE (insn);
364 /* Default insn printer.
366 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
367 about disassemble_info. */
370 print_insn_normal (od, dis_info, insn, fields, pc, length)
373 const CGEN_INSN *insn;
378 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
379 disassemble_info *info = (disassemble_info *) dis_info;
380 const unsigned char *syn;
382 CGEN_INIT_PRINT (od);
384 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
386 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
388 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
391 if (CGEN_SYNTAX_CHAR_P (*syn))
393 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
397 /* We have an operand. */
398 @arch@_cgen_print_operand (od, CGEN_SYNTAX_FIELD (*syn), info,
399 fields, CGEN_INSN_ATTRS (insn), pc, length);
403 /* Utility to print an insn.
404 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
405 The result is the size of the insn in bytes or zero for an unknown insn
406 or -1 if an error occurs fetching data (memory_error_func will have
410 print_insn (od, pc, info, buf, buflen)
413 disassemble_info *info;
417 unsigned long insn_value;
418 const CGEN_INSN_LIST *insn_list;
419 CGEN_EXTRACT_INFO ex_info;
421 ex_info.dis_info = info;
422 ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1;
431 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
434 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
440 /* The instructions are stored in hash lists.
441 Pick the first one and keep trying until we find the right one. */
443 insn_list = CGEN_DIS_LOOKUP_INSN (od, buf, insn_value);
444 while (insn_list != NULL)
446 const CGEN_INSN *insn = insn_list->insn;
450 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
451 /* Supported by this cpu? */
452 if (! @arch@_cgen_insn_supported (od, insn))
456 /* Basic bit mask must be correct. */
457 /* ??? May wish to allow target to defer this check until the extract
459 if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
461 /* Printing is handled in two passes. The first pass parses the
462 machine insn and extracts the fields. The second pass prints
465 length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value,
467 /* length < 0 -> error */
472 (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length);
473 /* length is in bits, result is in bytes */
478 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
484 /* Default value for CGEN_PRINT_INSN.
485 The result is the size of the insn in bytes or zero for an unknown insn
486 or -1 if an error occured fetching bytes. */
488 #ifndef CGEN_PRINT_INSN
489 #define CGEN_PRINT_INSN default_print_insn
493 default_print_insn (od, pc, info)
496 disassemble_info *info;
498 char buf[CGEN_MAX_INSN_SIZE];
501 /* Read the base part of the insn. */
503 status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info);
506 (*info->memory_error_func) (status, pc, info);
510 return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE);
514 Print one instruction from PC on INFO->STREAM.
515 Return the size of the instruction (in bytes). */
518 print_insn_@arch@ (pc, info)
520 disassemble_info *info;
523 static CGEN_OPCODE_DESC od = 0;
524 int mach = info->mach;
525 int big_p = info->endian == BFD_ENDIAN_BIG;
527 /* If we haven't initialized yet, initialize the opcode table. */
530 od = @arch@_cgen_opcode_open (mach,
533 : CGEN_ENDIAN_LITTLE);
534 @arch@_cgen_init_dis (od);
536 /* If we've switched cpu's, re-initialize. */
537 /* ??? Perhaps we should use BFD_ENDIAN. */
538 else if (mach != CGEN_OPCODE_MACH (od)
539 || (CGEN_OPCODE_ENDIAN (od)
540 != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE)))
542 cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
545 /* We try to have as much common code as possible.
546 But at this point some targets need to take over. */
547 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
548 but if not possible try to move this hook elsewhere rather than
550 length = CGEN_PRINT_INSN (od, pc, info);
556 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
557 return CGEN_DEFAULT_INSN_SIZE;