X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=opcodes%2Fm32r-dis.c;h=c778b88326e3834b618b846b73b4eea83af9f459;hb=e46d79a76ea748165a3ecd1102dd10498d089a49;hp=d0b97332b88a2dab91b9fe4c0671887e45bc103b;hpb=5d07b6cf9e5d11596d26b132761e2a4fbac0728f;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/m32r-dis.c b/opcodes/m32r-dis.c index d0b97332b8..c778b88326 100644 --- a/opcodes/m32r-dis.c +++ b/opcodes/m32r-dis.c @@ -1,178 +1,165 @@ +/* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */ /* Disassembler interface for targets using CGEN. -*- C -*- CGEN: Cpu tools GENerator -This file is used to generate m32r-dis.c. + THIS FILE IS MACHINE GENERATED WITH CGEN. + - the resultant file is machine generated, cgen-dis.in isn't -Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996-2019 Free Software Foundation, Inc. -This file is part of the GNU Binutils and GDB, the GNU debugger. + This file is part of libopcodes. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* ??? Eventually more and more of this stuff can go to cpu-independent files. + Keep that in mind. */ #include "sysdep.h" #include #include "ansidecl.h" -#include "dis-asm.h" +#include "disassemble.h" #include "bfd.h" +#include "symcat.h" +#include "libiberty.h" +#include "m32r-desc.h" #include "m32r-opc.h" - -/* ??? The layout of this stuff is still work in progress. - For speed in assembly/disassembly, we use inline functions. That of course - will only work for GCC. When this stuff is finished, we can decide whether - to keep the inline functions (and only get the performance increase when - compiled with GCC), or switch to macros, or use something else. -*/ +#include "opintl.h" /* Default text to print if an instruction isn't recognized. */ -#define UNKNOWN_INSN_MSG "*unknown*" - -/* FIXME: Machine generate. */ -#ifndef CGEN_PCREL_OFFSET -#define CGEN_PCREL_OFFSET 0 -#endif - -static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int)); - -static int extract_insn_normal - PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *)); +#define UNKNOWN_INSN_MSG _("*unknown*") + +static void print_normal + (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int); +static void print_address + (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED; +static void print_keyword + (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED; static void print_insn_normal - PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int)); + (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int); +static int print_insn + (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, unsigned); +static int default_print_insn + (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED; +static int read_insn + (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *, + unsigned long *); -/* Default extraction routine. - - ATTRS is a mask of the boolean attributes. We only need `unsigned', - but for generality we take a bitmask of all of them. */ +/* -- disassembler routines inserted here. */ -static int -extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep) - void *buf_ctrl; - cgen_insn_t insn_value; - unsigned int attrs; - int start, length, shift, total_length; - long *valuep; -{ - long value; +/* -- dis.c */ -#ifdef CGEN_INT_INSN -#if 0 - value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length))) - & ((1 << length) - 1)); -#else - value = ((insn_value >> (total_length - (start + length))) - & ((1 << length) - 1)); -#endif - if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) - && (value & (1 << (length - 1)))) - value -= 1 << length; -#else - /* FIXME: unfinished */ -#endif +/* Print signed operands with '#' prefixes. */ - /* This is backwards as we undo the effects of insert_normal. */ - if (shift < 0) - value >>= -shift; - else - value <<= shift; +static void +print_signed_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void * dis_info, + long value, + unsigned int attrs ATTRIBUTE_UNUSED, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) +{ + disassemble_info *info = (disassemble_info *) dis_info; - *valuep = value; - return 1; + (*info->fprintf_func) (info->stream, "#"); + (*info->fprintf_func) (info->stream, "%ld", value); } -/* Default print handler. */ +/* Print unsigned operands with '#' prefixes. */ static void -print_normal (dis_info, value, attrs, pc, length) - void *dis_info; - long value; - unsigned int attrs; - unsigned long pc; /* FIXME: should be bfd_vma */ - int length; +print_unsigned_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void * dis_info, + long value, + unsigned int attrs ATTRIBUTE_UNUSED, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) { - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; - /* Print the operand as directed by the attributes. */ - if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_FAKE)) - ; /* nothing to do (??? at least not yet) */ - else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR)) - (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info); - /* ??? Not all cases of this are currently caught. */ - else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR)) - /* FIXME: Why & 0xffffffff? */ - (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); - else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) - (*info->fprintf_func) (info->stream, "0x%lx", value); - else - (*info->fprintf_func) (info->stream, "%ld", value); + (*info->fprintf_func) (info->stream, "#"); + (*info->fprintf_func) (info->stream, "0x%lx", value); } -/* Keyword print handler. */ +/* Handle '#' prefixes as operands. */ static void -print_keyword (dis_info, keyword_table, value, attrs) - void *dis_info; - CGEN_KEYWORD *keyword_table; - long value; - CGEN_ATTR *attrs; +print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void * dis_info, + long value ATTRIBUTE_UNUSED, + unsigned int attrs ATTRIBUTE_UNUSED, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) { - disassemble_info *info = dis_info; - const CGEN_KEYWORD_ENTRY *ke; + disassemble_info *info = (disassemble_info *) dis_info; - ke = cgen_keyword_lookup_value (keyword_table, value); - if (ke != NULL) - (*info->fprintf_func) (info->stream, "%s", ke->name); - else - (*info->fprintf_func) (info->stream, "???"); + (*info->fprintf_func) (info->stream, "#"); } - -/* -- disassembler routines inserted here */ -/* -- dis.c */ -#undef CGEN_PRINT_INSN +#undef CGEN_PRINT_INSN #define CGEN_PRINT_INSN my_print_insn static int -my_print_insn (pc, info, buf, buflen) - bfd_vma pc; - disassemble_info *info; - char *buf; - int buflen; +my_print_insn (CGEN_CPU_DESC cd, + bfd_vma pc, + disassemble_info *info) { + bfd_byte buffer[CGEN_MAX_INSN_SIZE]; + bfd_byte *buf = buffer; + int status; + int buflen = (pc & 3) == 0 ? 4 : 2; + int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG; + bfd_byte *x; + + /* Read the base part of the insn. */ + + status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0), + buf, buflen, info); + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return -1; + } + /* 32 bit insn? */ - if ((pc & 3) == 0 && (buf[0] & 0x80) != 0) - return print_insn (pc, info, buf, buflen); + x = (big_p ? &buf[0] : &buf[3]); + if ((pc & 3) == 0 && (*x & 0x80) != 0) + return print_insn (cd, pc, info, buf, buflen); /* Print the first insn. */ if ((pc & 3) == 0) { - if (print_insn (pc, info, buf, 16) == 0) + buf += (big_p ? 0 : 2); + if (print_insn (cd, pc, info, buf, 2) == 0) (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); - buf += 2; + buf += (big_p ? 2 : -2); } - if (buf[0] & 0x80) + x = (big_p ? &buf[0] : &buf[1]); + if (*x & 0x80) { /* Parallel. */ (*info->fprintf_func) (info->stream, " || "); - buf[0] &= 0x7f; + *x &= 0x7f; } else (*info->fprintf_func) (info->stream, " -> "); - /* The "& 3" is to ensure the branch address is computed correctly - [if it is a branch]. */ - if (print_insn (pc & ~ (bfd_vma) 3, info, buf, 16) == 0) + /* The "& 3" is to pass a consistent address. + Parallel insns arguably both begin on the word boundary. + Also, branch insns are calculated relative to the word boundary. */ + if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0) (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); return (pc & 3) ? 2 : 4; @@ -180,7 +167,12 @@ my_print_insn (pc, info, buf, buflen) /* -- */ -/* Main entry point for operand extraction. +void m32r_cgen_print_operand + (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int); + +/* Main entry point for printing operands. + XINFO is a `void *' and not a `disassemble_info *' to not put a requirement + of dis-asm.h on cgen.h. This function is basically just a big switch statement. Earlier versions used tables to look up the function to use, but @@ -191,251 +183,205 @@ my_print_insn (pc, info, buf, buflen) This function could be moved into `print_insn_normal', but keeping it separate makes clear the interface between `print_insn_normal' and each of - the handlers. -*/ - -CGEN_INLINE int -m32r_cgen_extract_operand (opindex, buf_ctrl, insn_value, fields) - int opindex; - void * buf_ctrl; - cgen_insn_t insn_value; - CGEN_FIELDS * fields; + the handlers. */ + +void +m32r_cgen_print_operand (CGEN_CPU_DESC cd, + int opindex, + void * xinfo, + CGEN_FIELDS *fields, + void const *attrs ATTRIBUTE_UNUSED, + bfd_vma pc, + int length) { - int length; + disassemble_info *info = (disassemble_info *) xinfo; switch (opindex) { - case M32R_OPERAND_SR : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r2); + case M32R_OPERAND_ACC : + print_keyword (cd, info, & m32r_cgen_opval_h_accums, fields->f_acc, 0); break; - case M32R_OPERAND_DR : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r1); + case M32R_OPERAND_ACCD : + print_keyword (cd, info, & m32r_cgen_opval_h_accums, fields->f_accd, 0); break; - case M32R_OPERAND_SRC1 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r1); - break; - case M32R_OPERAND_SRC2 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r2); - break; - case M32R_OPERAND_SCR : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r2); + case M32R_OPERAND_ACCS : + print_keyword (cd, info, & m32r_cgen_opval_h_accums, fields->f_accs, 0); break; case M32R_OPERAND_DCR : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r1); + print_keyword (cd, info, & m32r_cgen_opval_cr_names, fields->f_r1, 0); break; - case M32R_OPERAND_SIMM8 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0, 8, 8, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_simm8); + case M32R_OPERAND_DISP16 : + print_address (cd, info, fields->f_disp16, 0|(1<f_simm16); + case M32R_OPERAND_DISP24 : + print_address (cd, info, fields->f_disp24, 0|(1<f_uimm4); + case M32R_OPERAND_DISP8 : + print_address (cd, info, fields->f_disp8, 0|(1<f_uimm5); + case M32R_OPERAND_DR : + print_keyword (cd, info, & m32r_cgen_opval_gr_names, fields->f_r1, 0); break; - case M32R_OPERAND_UIMM16 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_uimm16); + case M32R_OPERAND_HASH : + print_hash (cd, info, 0, 0|(1<f_hi16); - break; - case M32R_OPERAND_SLO16 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_simm16); + print_normal (cd, info, fields->f_hi16, 0|(1<f_uimm16); + case M32R_OPERAND_IMM1 : + print_unsigned_with_hash_prefix (cd, info, fields->f_imm1, 0, pc, length); break; - case M32R_OPERAND_UIMM24 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_uimm24); + case M32R_OPERAND_SCR : + print_keyword (cd, info, & m32r_cgen_opval_cr_names, fields->f_r2, 0); break; - case M32R_OPERAND_DISP8 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_disp8); + case M32R_OPERAND_SIMM16 : + print_signed_with_hash_prefix (cd, info, fields->f_simm16, 0|(1<f_disp16); + case M32R_OPERAND_SIMM8 : + print_signed_with_hash_prefix (cd, info, fields->f_simm8, 0|(1<f_disp24); + case M32R_OPERAND_SLO16 : + print_normal (cd, info, fields->f_simm16, 0|(1<f_r2, 0|(1<f_r1, 0|(1<f_r2, 0); break; case M32R_OPERAND_SRC1 : - print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r1, 0|(1<f_r1, 0); break; case M32R_OPERAND_SRC2 : - print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r2, 0|(1<f_r2, 0|(1<f_r2, 0); break; - case M32R_OPERAND_DCR : - print_keyword (info, & m32r_cgen_opval_h_cr, fields->f_r1, 0|(1<f_uimm16, 0, pc, length); break; - case M32R_OPERAND_SIMM8 : - print_normal (info, fields->f_simm8, 0, pc, length); + case M32R_OPERAND_UIMM24 : + print_address (cd, info, fields->f_uimm24, 0|(1<f_simm16, 0, pc, length); + case M32R_OPERAND_UIMM3 : + print_unsigned_with_hash_prefix (cd, info, fields->f_uimm3, 0, pc, length); break; case M32R_OPERAND_UIMM4 : - print_normal (info, fields->f_uimm4, 0|(1<f_uimm4, 0, pc, length); break; case M32R_OPERAND_UIMM5 : - print_normal (info, fields->f_uimm5, 0|(1<f_uimm5, 0, pc, length); break; - case M32R_OPERAND_UIMM16 : - print_normal (info, fields->f_uimm16, 0|(1<f_hi16, 0|(1<f_simm16, 0, pc, length); + case M32R_OPERAND_UIMM8 : + print_unsigned_with_hash_prefix (cd, info, fields->f_uimm8, 0, pc, length); break; case M32R_OPERAND_ULO16 : - print_normal (info, fields->f_uimm16, 0|(1<f_uimm24, 0|(1<f_disp8, 0|(1<f_disp16, 0|(1<f_disp24, 0|(1<f_uimm16, 0, pc, length); break; default : - fprintf (stderr, "Unrecognized field %d while printing insn.\n", - opindex); - abort (); + /* xgettext:c-format */ + opcodes_error_handler + (_("internal error: unrecognized field %d while printing insn"), + opindex); + abort (); } } -cgen_extract_fn * m32r_cgen_extract_handlers[] = -{ - 0, /* default */ - extract_insn_normal, -}; - -cgen_print_fn * m32r_cgen_print_handlers[] = +cgen_print_fn * const m32r_cgen_print_handlers[] = { - 0, /* default */ print_insn_normal, }; void -m32r_cgen_init_dis (mach, endian) - int mach; - enum cgen_endian endian; +m32r_cgen_init_dis (CGEN_CPU_DESC cd) { - m32r_cgen_init_tables (mach); - cgen_set_cpu (& m32r_cgen_opcode_data, mach, endian); - cgen_dis_init (); + m32r_cgen_init_opcode_table (cd); + m32r_cgen_init_ibld_table (cd); + cd->print_handlers = & m32r_cgen_print_handlers[0]; + cd->print_operand = m32r_cgen_print_operand; } -/* Default insn extractor. - - The extracted fields are stored in DIS_FLDS. - BUF_CTRL is used to handle reading variable length insns (FIXME: not done). - Return the length of the insn in bits, or 0 if no match. */ +/* Default print handler. */ -static int -extract_insn_normal (insn, buf_ctrl, insn_value, fields) - const CGEN_INSN *insn; - void *buf_ctrl; - cgen_insn_t insn_value; - CGEN_FIELDS *fields; +static void +print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void *dis_info, + long value, + unsigned int attrs, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) { - const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); - const unsigned char *syn; + disassemble_info *info = (disassemble_info *) dis_info; - CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); + /* Print the operand as directed by the attributes. */ + if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) + ; /* nothing to do */ + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) + (*info->fprintf_func) (info->stream, "%ld", value); + else + (*info->fprintf_func) (info->stream, "0x%lx", value); +} - CGEN_INIT_EXTRACT (); +/* Default address handler. */ - for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) - { - int length; +static void +print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void *dis_info, + bfd_vma value, + unsigned int attrs, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) +{ + disassemble_info *info = (disassemble_info *) dis_info; - if (CGEN_SYNTAX_CHAR_P (*syn)) - continue; + /* Print the operand as directed by the attributes. */ + if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) + ; /* Nothing to do. */ + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR)) + (*info->print_address_func) (value, info); + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR)) + (*info->print_address_func) (value, info); + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED)) + (*info->fprintf_func) (info->stream, "%ld", (long) value); + else + (*info->fprintf_func) (info->stream, "0x%lx", (long) value); +} - length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn), - buf_ctrl, insn_value, fields); - if (length == 0) - return 0; - } +/* Keyword print handler. */ - /* We recognized and successfully extracted this insn. */ - return CGEN_INSN_BITSIZE (insn); -} +static void +print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void *dis_info, + CGEN_KEYWORD *keyword_table, + long value, + unsigned int attrs ATTRIBUTE_UNUSED) +{ + disassemble_info *info = (disassemble_info *) dis_info; + const CGEN_KEYWORD_ENTRY *ke; + ke = cgen_keyword_lookup_value (keyword_table, value); + if (ke != NULL) + (*info->fprintf_func) (info->stream, "%s", ke->name); + else + (*info->fprintf_func) (info->stream, "???"); +} + /* Default insn printer. DIS_INFO is defined as `void *' so the disassembler needn't know anything - about disassemble_info. -*/ + about disassemble_info. */ static void -print_insn_normal (dis_info, insn, fields, pc, length) - void *dis_info; - const CGEN_INSN *insn; - CGEN_FIELDS *fields; - bfd_vma pc; - int length; +print_insn_normal (CGEN_CPU_DESC cd, + void *dis_info, + const CGEN_INSN *insn, + CGEN_FIELDS *fields, + bfd_vma pc, + int length) { const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); - disassemble_info *info = dis_info; - const unsigned char *syn; + disassemble_info *info = (disassemble_info *) dis_info; + const CGEN_SYNTAX_CHAR_TYPE *syn; - CGEN_INIT_PRINT (); + CGEN_INIT_PRINT (cd); for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) { @@ -451,78 +397,137 @@ print_insn_normal (dis_info, insn, fields, pc, length) } /* We have an operand. */ - m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (*syn), info, - fields, CGEN_INSN_ATTRS (insn), pc, length); + m32r_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info, + fields, CGEN_INSN_ATTRS (insn), pc, length); } } -/* Default value for CGEN_PRINT_INSN. - Given BUFLEN bits (target byte order) read into BUF, look up the - insn in the instruction table and disassemble it. +/* Subroutine of print_insn. Reads an insn into the given buffers and updates + the extract info. + Returns 0 if all is well, non-zero otherwise. */ - The result is the size of the insn in bytes. */ +static int +read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + bfd_vma pc, + disassemble_info *info, + bfd_byte *buf, + int buflen, + CGEN_EXTRACT_INFO *ex_info, + unsigned long *insn_value) +{ + int status = (*info->read_memory_func) (pc, buf, buflen, info); -#ifndef CGEN_PRINT_INSN -#define CGEN_PRINT_INSN print_insn -#endif + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return -1; + } + + ex_info->dis_info = info; + ex_info->valid = (1 << buflen) - 1; + ex_info->insn_bytes = buf; + + *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG); + return 0; +} + +/* Utility to print an insn. + BUF is the base part of the insn, target byte order, BUFLEN bytes long. + The result is the size of the insn in bytes or zero for an unknown insn + or -1 if an error occurs fetching data (memory_error_func will have + been called). */ static int -print_insn (pc, info, buf, buflen) - bfd_vma pc; - disassemble_info *info; - char *buf; - int buflen; +print_insn (CGEN_CPU_DESC cd, + bfd_vma pc, + disassemble_info *info, + bfd_byte *buf, + unsigned int buflen) { - int i; - unsigned long insn_value; + CGEN_INSN_INT insn_value; const CGEN_INSN_LIST *insn_list; + CGEN_EXTRACT_INFO ex_info; + int basesize; - switch (buflen) - { - case 8: - insn_value = buf[0]; - break; - case 16: - insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf); - break; - case 32: - insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf); - break; - default: - abort (); - } + /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */ + basesize = cd->base_insn_bitsize < buflen * 8 ? + cd->base_insn_bitsize : buflen * 8; + insn_value = cgen_get_insn_value (cd, buf, basesize); + + + /* Fill in ex_info fields like read_insn would. Don't actually call + read_insn, since the incoming buffer is already read (and possibly + modified a la m32r). */ + ex_info.valid = (1 << buflen) - 1; + ex_info.dis_info = info; + ex_info.insn_bytes = buf; /* The instructions are stored in hash lists. Pick the first one and keep trying until we find the right one. */ - insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value); + insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value); while (insn_list != NULL) { const CGEN_INSN *insn = insn_list->insn; - const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); CGEN_FIELDS fields; int length; + unsigned long insn_value_cropped; -#if 0 /* not needed as insn shouldn't be in hash lists if not supported */ +#ifdef CGEN_VALIDATE_INSN_SUPPORTED + /* Not needed as insn shouldn't be in hash lists if not supported. */ /* Supported by this cpu? */ - if (! m32r_cgen_insn_supported (insn)) - continue; + if (! m32r_cgen_insn_supported (cd, insn)) + { + insn_list = CGEN_DIS_NEXT_INSN (insn_list); + continue; + } #endif /* Basic bit mask must be correct. */ /* ??? May wish to allow target to defer this check until the extract handler. */ - if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn)) + + /* Base size may exceed this instruction's size. Extract the + relevant part from the buffer. */ + if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen && + (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) + insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), + info->endian == BFD_ENDIAN_BIG); + else + insn_value_cropped = insn_value; + + if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn)) + == CGEN_INSN_BASE_VALUE (insn)) { /* Printing is handled in two passes. The first pass parses the machine insn and extracts the fields. The second pass prints them. */ - length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields); + /* Make sure the entire insn is loaded into insn_value, if it + can fit. */ + if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) && + (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long)) + { + unsigned long full_insn_value; + int rc = read_insn (cd, pc, info, buf, + CGEN_INSN_BITSIZE (insn) / 8, + & ex_info, & full_insn_value); + if (rc != 0) + return rc; + length = CGEN_EXTRACT_FN (cd, insn) + (cd, insn, &ex_info, full_insn_value, &fields, pc); + } + else + length = CGEN_EXTRACT_FN (cd, insn) + (cd, insn, &ex_info, insn_value_cropped, &fields, pc); + + /* Length < 0 -> error. */ + if (length < 0) + return length; if (length > 0) { - (*CGEN_PRINT_FN (insn)) (info, insn, &fields, pc, length); - /* length is in bits, result is in bytes */ + CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length); + /* Length is in bits, result is in bytes. */ return length / 8; } } @@ -533,39 +538,151 @@ print_insn (pc, info, buf, buflen) return 0; } +/* Default value for CGEN_PRINT_INSN. + The result is the size of the insn in bytes or zero for an unknown insn + or -1 if an error occured fetching bytes. */ + +#ifndef CGEN_PRINT_INSN +#define CGEN_PRINT_INSN default_print_insn +#endif + +static int +default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) +{ + bfd_byte buf[CGEN_MAX_INSN_SIZE]; + int buflen; + int status; + + /* Attempt to read the base part of the insn. */ + buflen = cd->base_insn_bitsize / 8; + status = (*info->read_memory_func) (pc, buf, buflen, info); + + /* Try again with the minimum part, if min < base. */ + if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize)) + { + buflen = cd->min_insn_bitsize / 8; + status = (*info->read_memory_func) (pc, buf, buflen, info); + } + + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return -1; + } + + return print_insn (cd, pc, info, buf, buflen); +} + /* Main entry point. Print one instruction from PC on INFO->STREAM. Return the size of the instruction (in bytes). */ +typedef struct cpu_desc_list +{ + struct cpu_desc_list *next; + CGEN_BITSET *isa; + int mach; + int endian; + CGEN_CPU_DESC cd; +} cpu_desc_list; + int -print_insn_m32r (pc, info) - bfd_vma pc; - disassemble_info *info; +print_insn_m32r (bfd_vma pc, disassemble_info *info) { - char buffer[CGEN_MAX_INSN_SIZE]; - int status, length; - static int initialized = 0; - static int current_mach = 0; - static int current_big_p = 0; - int mach = info->mach; - int big_p = info->endian == BFD_ENDIAN_BIG; - - /* If we haven't initialized yet, or if we've switched cpu's, initialize. */ - if (!initialized || mach != current_mach || big_p != current_big_p) + static cpu_desc_list *cd_list = 0; + cpu_desc_list *cl = 0; + static CGEN_CPU_DESC cd = 0; + static CGEN_BITSET *prev_isa; + static int prev_mach; + static int prev_endian; + int length; + CGEN_BITSET *isa; + int mach; + int endian = (info->endian == BFD_ENDIAN_BIG + ? CGEN_ENDIAN_BIG + : CGEN_ENDIAN_LITTLE); + enum bfd_architecture arch; + + /* ??? gdb will set mach but leave the architecture as "unknown" */ +#ifndef CGEN_BFD_ARCH +#define CGEN_BFD_ARCH bfd_arch_m32r +#endif + arch = info->arch; + if (arch == bfd_arch_unknown) + arch = CGEN_BFD_ARCH; + + /* There's no standard way to compute the machine or isa number + so we leave it to the target. */ +#ifdef CGEN_COMPUTE_MACH + mach = CGEN_COMPUTE_MACH (info); +#else + mach = info->mach; +#endif + +#ifdef CGEN_COMPUTE_ISA + { + static CGEN_BITSET *permanent_isa; + + if (!permanent_isa) + permanent_isa = cgen_bitset_create (MAX_ISAS); + isa = permanent_isa; + cgen_bitset_clear (isa); + cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info)); + } +#else + isa = info->private_data; +#endif + + /* If we've switched cpu's, try to find a handle we've used before */ + if (cd + && (cgen_bitset_compare (isa, prev_isa) != 0 + || mach != prev_mach + || endian != prev_endian)) { - initialized = 1; - current_mach = mach; - current_big_p = big_p; - m32r_cgen_init_dis (mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE); + cd = 0; + for (cl = cd_list; cl; cl = cl->next) + { + if (cgen_bitset_compare (cl->isa, isa) == 0 && + cl->mach == mach && + cl->endian == endian) + { + cd = cl->cd; + prev_isa = cd->isas; + break; + } + } } - /* Read enough of the insn so we can look it up in the hash lists. */ - - status = (*info->read_memory_func) (pc, buffer, CGEN_BASE_INSN_SIZE, info); - if (status != 0) + /* If we haven't initialized yet, initialize the opcode table. */ + if (! cd) { - (*info->memory_error_func) (status, pc, info); - return -1; + const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach); + const char *mach_name; + + if (!arch_type) + abort (); + mach_name = arch_type->printable_name; + + prev_isa = cgen_bitset_copy (isa); + prev_mach = mach; + prev_endian = endian; + cd = m32r_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa, + CGEN_CPU_OPEN_BFDMACH, mach_name, + CGEN_CPU_OPEN_ENDIAN, prev_endian, + CGEN_CPU_OPEN_END); + if (!cd) + abort (); + + /* Save this away for future reference. */ + cl = xmalloc (sizeof (struct cpu_desc_list)); + cl->cd = cd; + cl->isa = prev_isa; + cl->mach = mach; + cl->endian = endian; + cl->next = cd_list; + cd_list = cl; + + m32r_cgen_init_dis (cd); } /* We try to have as much common code as possible. @@ -573,10 +690,12 @@ print_insn_m32r (pc, info) /* ??? Some targets may need a hook elsewhere. Try to avoid this, but if not possible try to move this hook elsewhere rather than have two hooks. */ - length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE); - if (length) + length = CGEN_PRINT_INSN (cd, pc, info); + if (length > 0) return length; + if (length < 0) + return -1; (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); - return CGEN_DEFAULT_INSN_SIZE; + return cd->default_insn_bitsize / 8; }