From: Doug Evans Date: Tue, 10 Nov 1998 19:11:04 +0000 (+0000) Subject: * cgen-dis.in (print_normal): CGEN_OPERAND_FAKE renamed to X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1c8f439ec6f8f43fa3a6e1987fb5ea23ebd910f8;p=binutils-gdb.git * cgen-dis.in (print_normal): CGEN_OPERAND_FAKE renamed to CGEN_OPERAND_SEM_ONLY. * m32r-dis.c,m32r-opc.c,m32r-opc.h: Rebuild. * fr30-dis.c,fr30-opc.c,fr30-opc.h: Rebuild. --- diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index efe5070a3d2..4c1d5876501 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,14 @@ +Tue Nov 10 11:00:04 1998 Doug Evans + +start-sanitize-cygnus + * cgen-dis.in (print_normal): CGEN_OPERAND_FAKE renamed to + CGEN_OPERAND_SEM_ONLY. +end-sanitize-cygnus + * m32r-dis.c,m32r-opc.c,m32r-opc.h: Rebuild. +start-sanitize-fr30 + * fr30-dis.c,fr30-opc.c,fr30-opc.h: Rebuild. +end-sanitize-fr30 + start-sanitize-fr30 Mon Nov 9 18:22:55 1998 Dave Brolley diff --git a/opcodes/cgen-dis.in b/opcodes/cgen-dis.in index 06e22eb72f6..77edb9a210f 100644 --- a/opcodes/cgen-dis.in +++ b/opcodes/cgen-dis.in @@ -1,9 +1,9 @@ /* Disassembler interface for targets using CGEN. -*- C -*- CGEN: Cpu tools GENerator -This file is used to generate @arch@-dis.c. +THIS FILE IS USED TO GENERATE @prefix@-dis.c. -Copyright (C) 1996, 1997 Free Software Foundation, Inc. +Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU Binutils and GDB, the GNU debugger. @@ -18,8 +18,8 @@ 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. */ +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sysdep.h" #include @@ -27,65 +27,215 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "dis-asm.h" #include "bfd.h" #include "symcat.h" -#include "@arch@-opc.h" +#include "@prefix@-opc.h" +#include "opintl.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. -*/ - -/* 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 +#undef INLINE +#ifdef __GNUC__ +#define INLINE __inline__ +#else +#define INLINE #endif -static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int)); - +/* Default text to print if an instruction isn't recognized. */ +#define UNKNOWN_INSN_MSG _("*unknown*") + +static int extract_normal + PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_BYTES, + unsigned int, int, int, int, long *)); +static void print_normal + PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int)); +static void print_address + PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int)); +static void print_keyword + PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int)); static int extract_insn_normal - PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *)); + PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *, + unsigned long, CGEN_FIELDS *, bfd_vma)); static void print_insn_normal - PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int)); + PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *, + bfd_vma, int)); +static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma, + disassemble_info *, char *, int)); +static int default_print_insn + PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *)); + +/* -- disassembler routines inserted here */ +#if ! CGEN_INT_INSN_P + +/* Subroutine of extract_normal. */ + +static INLINE long +extract_1 (od, ex_info, start, length, word_length, bufp) + CGEN_OPCODE_DESC od; + CGEN_EXTRACT_INFO *info; + int start,length,word_length; + unsigned char *bufp; +{ + unsigned long x,mask; + int shift; + int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG; + + /* FIXME: Need to use ex_info to ensure bytes have been fetched. */ + + switch (word_length) + { + case 8: + x = *bufp; + break; + case 16: + if (big_p) + x = bfd_getb16 (bufp); + else + x = bfd_getl16 (bufp); + break; + case 24: + /* ??? This may need reworking as these cases don't necessarily + want the first byte and the last two bytes handled like this. */ + if (big_p) + x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1); + else + x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16); + break; + case 32: + if (big_p) + x = bfd_getb32 (bufp); + else + x = bfd_getl32 (bufp); + break; + default : + abort (); + } + + /* Written this way to avoid undefined behaviour. */ + mask = (((1L << (length - 1)) - 1) << 1) | 1; + if (CGEN_INSN_LSB0_P) + shift = start; + else + shift = (word_length - (start + length)); + return (x >> shift) & mask; +} + +#endif /* ! CGEN_INT_INSN_P */ + /* 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. */ +/* ??? This doesn't handle bfd_vma's. Create another function when + necessary. */ + static int -extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep) - PTR buf_ctrl; - cgen_insn_t insn_value; +extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep) + CGEN_OPCODE_DESC od; + CGEN_EXTRACT_INFO *ex_info; + CGEN_INSN_BYTES insn_value; unsigned int attrs; - int start, length, shift, total_length; + int start, length, total_length; long *valuep; { - long value; + unsigned long value; + + /* If LENGTH is zero, this operand doesn't contribute to the value + so give it a standard value of zero. */ + if (length == 0) + { + *valuep = 0; + return 1; + } + +#if CGEN_INT_INSN_P + + { + /* Written this way to avoid undefined behaviour. */ + unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1; + + if (CGEN_INSN_LSB0_P) + value = insn_value >> start; + else + value = insn_value >> (total_length - (start + length)); + value &= mask; + /* sign extend? */ + if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) + && (value & (1L << (length - 1)))) + value |= ~mask; + } -#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 - /* This is backwards as we undo the effects of insert_normal. */ - if (shift < 0) - value >>= -shift; + /* The hard case is probably too slow for the normal cases. + It's certainly more difficult to understand than the normal case. + Thus this is split into two. Keep it that way. The hard case is defined + to be when a field straddles a (loosely defined) word boundary + (??? which may require target specific help to determine). */ + +#if 0 /*wip*/ + +#define HARD_CASE_P 0 /* FIXME:wip */ + + if (HARD_CASE_P) + { + } +#endif else - value <<= shift; + { + unsigned char *bufp = (unsigned char *) insn_value; + + if (length > 32) + abort (); + + /* Adjust start,total_length,bufp to point to the pseudo-word that holds + the value. For example in a 48 bit insn where the value to insert + (say an immediate value) is the last 16 bits then word_length here + would be 16. To handle a 24 bit insn with an 18 bit immediate, + extract_1 handles 24 bits (using a combination of bfd_get8,16). */ + + if (total_length > 32) + { + int needed_width = start % 8 + length; + int fetch_length = (needed_width <= 8 ? 8 + : needed_width <= 16 ? 16 + : 32); + + if (CGEN_INSN_LSB0_P) + { + if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG) + { + abort (); /* wip */ + } + else + { + int offset = start & ~7; + + bufp += offset / 8; + start -= offset; + total_length -= offset; + } + } + else + { + if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG) + { + int offset = start & ~7; + + bufp += offset / 8; + start -= offset; + total_length -= offset; + } + else + { + abort (); /* wip */ + } + } + } + + /* FIXME: which bytes are being extracted have been lost. */ + value = extract_1 (od, ex_info, start, length, total_length, bufp); + } + +#endif /* ! CGEN_INT_INSN_P */ *valuep = value; @@ -96,40 +246,70 @@ extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, /* Default print handler. */ static void -print_normal (dis_info, value, attrs, pc, length) +print_normal (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; PTR dis_info; long value; unsigned int attrs; - unsigned long pc; /* FIXME: should be bfd_vma */ + bfd_vma pc; int length; { - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; + +#ifdef CGEN_PRINT_NORMAL + CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length); +#endif /* 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)) + if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) + ; /* nothing to do */ + else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED)) (*info->fprintf_func) (info->stream, "0x%lx", value); else (*info->fprintf_func) (info->stream, "%ld", value); } +/* Default address handler. */ + +static void +print_address (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; + PTR dis_info; + bfd_vma value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + +#ifdef CGEN_PRINT_ADDRESS + CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length); +#endif + + /* 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_UNSIGNED)) + (*info->fprintf_func) (info->stream, "0x%lx", (long) value); + else + (*info->fprintf_func) (info->stream, "%ld", (long) value); +} + /* Keyword print handler. */ static void -print_keyword (dis_info, keyword_table, value, attrs) +print_keyword (od, dis_info, keyword_table, value, attrs) + CGEN_OPCODE_DESC od; PTR dis_info; CGEN_KEYWORD *keyword_table; long value; - CGEN_ATTR *attrs; + unsigned int attrs; { - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; const CGEN_KEYWORD_ENTRY *ke; ke = cgen_keyword_lookup_value (keyword_table, value); @@ -139,27 +319,30 @@ print_keyword (dis_info, keyword_table, value, attrs) (*info->fprintf_func) (info->stream, "???"); } -/* -- disassembler routines inserted here */ - /* 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. */ + INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order. + The extracted fields are stored in FIELDS. + EX_INFO is used to handle reading variable length insns. + Return the length of the insn in bits, or 0 if no match, + or -1 if an error occurs fetching data (memory_error_func will have + been called). */ static int -extract_insn_normal (insn, buf_ctrl, insn_value, fields) +extract_insn_normal (od, insn, ex_info, insn_value, fields, pc) + CGEN_OPCODE_DESC od; const CGEN_INSN *insn; - PTR buf_ctrl; - cgen_insn_t insn_value; + CGEN_EXTRACT_INFO *ex_info; + unsigned long insn_value; CGEN_FIELDS *fields; + bfd_vma pc; { const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); const unsigned char *syn; CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); - CGEN_INIT_EXTRACT (); + CGEN_INIT_EXTRACT (od); for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) { @@ -168,10 +351,10 @@ extract_insn_normal (insn, buf_ctrl, insn_value, fields) if (CGEN_SYNTAX_CHAR_P (*syn)) continue; - length = @arch@_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn), - buf_ctrl, insn_value, fields); - if (length == 0) - return 0; + length = @arch@_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn), + ex_info, insn_value, fields, pc); + if (length <= 0) + return length; } /* We recognized and successfully extracted this insn. */ @@ -181,11 +364,11 @@ extract_insn_normal (insn, buf_ctrl, insn_value, fields) /* Default insn printer. DIS_INFO is defined as `PTR' so the disassembler needn't know anything - about disassemble_info. -*/ + about disassemble_info. */ static void -print_insn_normal (dis_info, insn, fields, pc, length) +print_insn_normal (od, dis_info, insn, fields, pc, length) + CGEN_OPCODE_DESC od; PTR dis_info; const CGEN_INSN *insn; CGEN_FIELDS *fields; @@ -193,10 +376,10 @@ print_insn_normal (dis_info, insn, fields, pc, length) int length; { const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; const unsigned char *syn; - CGEN_INIT_PRINT (); + CGEN_INIT_PRINT (od); for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) { @@ -212,23 +395,20 @@ print_insn_normal (dis_info, insn, fields, pc, length) } /* We have an operand. */ - @arch@_cgen_print_operand (CGEN_SYNTAX_FIELD (*syn), info, - fields, CGEN_INSN_ATTRS (insn), pc, length); + @arch@_cgen_print_operand (od, 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. - - The result is the size of the insn in bytes. */ - -#ifndef CGEN_PRINT_INSN -#define CGEN_PRINT_INSN print_insn -#endif +/* 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) +print_insn (od, pc, info, buf, buflen) + CGEN_OPCODE_DESC od; bfd_vma pc; disassemble_info *info; char *buf; @@ -236,16 +416,21 @@ print_insn (pc, info, buf, buflen) { unsigned long insn_value; const CGEN_INSN_LIST *insn_list; + CGEN_EXTRACT_INFO ex_info; + + ex_info.dis_info = info; + ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1; + ex_info.bytes = buf; switch (buflen) { - case 8: + case 1: insn_value = buf[0]; break; - case 16: + case 2: insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf); break; - case 32: + case 4: insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf); break; default: @@ -255,7 +440,7 @@ print_insn (pc, info, buf, buflen) /* 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 (od, buf, insn_value); while (insn_list != NULL) { const CGEN_INSN *insn = insn_list->insn; @@ -264,7 +449,7 @@ print_insn (pc, info, buf, buflen) #if 0 /* not needed as insn shouldn't be in hash lists if not supported */ /* Supported by this cpu? */ - if (! @arch@_cgen_insn_supported (insn)) + if (! @arch@_cgen_insn_supported (od, insn)) continue; #endif @@ -277,10 +462,14 @@ print_insn (pc, info, buf, buflen) machine insn and extracts the fields. The second pass prints them. */ - length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields); + length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value, + &fields, pc); + /* length < 0 -> error */ + if (length < 0) + return length; if (length > 0) { - (*CGEN_PRINT_FN (insn)) (info, insn, &fields, pc, length); + (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length); /* length is in bits, result is in bytes */ return length / 8; } @@ -292,6 +481,35 @@ 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 (od, pc, info) + CGEN_OPCODE_DESC od; + bfd_vma pc; + disassemble_info *info; +{ + char buf[CGEN_MAX_INSN_SIZE]; + int status; + + /* Read the base part of the insn. */ + + status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info); + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return -1; + } + + return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE); +} + /* Main entry point. Print one instruction from PC on INFO->STREAM. Return the size of the instruction (in bytes). */ @@ -301,30 +519,27 @@ print_insn_@arch@ (pc, info) 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 length; + static CGEN_OPCODE_DESC od = 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) + /* If we haven't initialized yet, initialize the opcode table. */ + if (! od) { - initialized = 1; - current_mach = mach; - current_big_p = big_p; - @arch@_cgen_init_dis (mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE); + od = @arch@_cgen_opcode_open (mach, + big_p ? + CGEN_ENDIAN_BIG + : CGEN_ENDIAN_LITTLE); + @arch@_cgen_init_dis (od); } - - /* 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've switched cpu's, re-initialize. */ + /* ??? Perhaps we should use BFD_ENDIAN. */ + else if (mach != CGEN_OPCODE_MACH (od) + || (CGEN_OPCODE_ENDIAN (od) + != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE))) { - (*info->memory_error_func) (status, pc, info); - return -1; + cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE); } /* We try to have as much common code as possible. @@ -332,9 +547,11 @@ print_insn_@arch@ (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 (od, 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; diff --git a/opcodes/fr30-dis.c b/opcodes/fr30-dis.c index 4ab7d39f41d..d2cbab3d167 100644 --- a/opcodes/fr30-dis.c +++ b/opcodes/fr30-dis.c @@ -366,7 +366,7 @@ print_normal (od, dis_info, value, attrs, pc, length) #endif /* Print the operand as directed by the attributes. */ - if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_FAKE)) + if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) ; /* nothing to do */ else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED)) (*info->fprintf_func) (info->stream, "0x%lx", value); @@ -392,7 +392,7 @@ print_address (od, dis_info, value, attrs, pc, length) #endif /* Print the operand as directed by the attributes. */ - if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_FAKE)) + 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); diff --git a/opcodes/fr30-opc.c b/opcodes/fr30-opc.c index 333aeb328e6..04d8df935b2 100644 --- a/opcodes/fr30-opc.c +++ b/opcodes/fr30-opc.c @@ -286,10 +286,10 @@ const CGEN_ATTR_TABLE fr30_cgen_hardware_attr_table[] = const CGEN_ATTR_TABLE fr30_cgen_operand_attr_table[] = { { "ABS-ADDR", NULL }, - { "FAKE", NULL }, { "NEGATIVE", NULL }, { "PCREL-ADDR", NULL }, { "RELAX", NULL }, + { "SEM-ONLY", NULL }, { "SIGN-OPT", NULL }, { "UNSIGNED", NULL }, { 0, 0 } @@ -407,7 +407,7 @@ const CGEN_OPERAND fr30_cgen_operand_table[MAX_OPERANDS] = { /* pc: program counter */ { "pc", & HW_ENT (HW_H_PC), 0, 0, - { 0, 0|(1< @@ -28,41 +28,44 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "symcat.h" #include "m32r-opc.h" +#include "opintl.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. -*/ - -/* 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 +#undef INLINE +#ifdef __GNUC__ +#define INLINE __inline__ +#else +#define INLINE #endif -static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int)); +/* Default text to print if an instruction isn't recognized. */ +#define UNKNOWN_INSN_MSG _("*unknown*") static int extract_normal - PARAMS ((PTR, cgen_insn_t, unsigned int, int, int, int, long *)); + PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_BYTES, + unsigned int, int, int, int, long *)); static void print_normal - PARAMS ((PTR, long, unsigned int, unsigned long, int)); + PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int)); +static void print_address + PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int)); static void print_keyword - PARAMS ((PTR, CGEN_KEYWORD *, long, unsigned int)); + PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int)); static int extract_insn_normal - PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *)); + PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *, + unsigned long, CGEN_FIELDS *, bfd_vma)); static void print_insn_normal - PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int)); + PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *, + bfd_vma, int)); +static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma, + disassemble_info *, char *, int)); +static int default_print_insn + PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *)); /* -- disassembler routines inserted here */ /* -- dis.c */ /* Immediate values are prefixed with '#'. */ -#define CGEN_PRINT_NORMAL(info, value, attrs, pc, length) \ +#define CGEN_PRINT_NORMAL(od, info, value, attrs, pc, length) \ do { \ if ((attrs) & (1 << CGEN_OPERAND_HASH_PREFIX)) \ (*info->fprintf_func) (info->stream, "#"); \ @@ -71,11 +74,12 @@ do { \ /* Handle '#' prefixes as operands. */ static void -print_hash (dis_info, value, attrs, pc, length) +print_hash (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; PTR dis_info; long value; unsigned int attrs; - unsigned long pc; /* FIXME: should be bfd_vma */ + bfd_vma pc; int length; { disassemble_info *info = dis_info; @@ -86,20 +90,33 @@ print_hash (dis_info, value, attrs, pc, length) #define CGEN_PRINT_INSN my_print_insn static int -my_print_insn (pc, info, buf, buflen) +my_print_insn (od, pc, info) + CGEN_OPCODE_DESC od; bfd_vma pc; disassemble_info *info; - char *buf; - int buflen; { + char buffer[CGEN_MAX_INSN_SIZE]; + char *buf = buffer; + int status; + int buflen = (pc & 3) == 0 ? 4 : 2; + + /* Read the base part of the insn. */ + + status = (*info->read_memory_func) (pc, 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); + return print_insn (od, pc, info, buf, buflen); /* Print the first insn. */ if ((pc & 3) == 0) { - if (print_insn (pc, info, buf, 16) == 0) + if (print_insn (od, pc, info, buf, 2) == 0) (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); buf += 2; } @@ -113,9 +130,10 @@ my_print_insn (pc, info, buf, buflen) 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 (od, pc & ~ (bfd_vma) 3, info, buf, 2) == 0) (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); return (pc & 3) ? 2 : 4; @@ -138,112 +156,119 @@ my_print_insn (pc, info, buf, buflen) */ int -m32r_cgen_extract_operand (opindex, buf_ctrl, insn_value, fields) +m32r_cgen_extract_operand (od, opindex, ex_info, insn_value, fields, pc) + CGEN_OPCODE_DESC od; int opindex; - PTR buf_ctrl; - cgen_insn_t insn_value; + CGEN_EXTRACT_INFO *ex_info; + CGEN_INSN_BYTES insn_value; CGEN_FIELDS * fields; + bfd_vma pc; { int length; switch (opindex) { case M32R_OPERAND_SR : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r2); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_r2); break; case M32R_OPERAND_DR : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r1); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_r1); break; case M32R_OPERAND_SRC1 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r1); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_r1); break; case M32R_OPERAND_SRC2 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r2); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_r2); break; case M32R_OPERAND_SCR : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r2); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_r2); break; case M32R_OPERAND_DCR : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_r1); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_r1); break; case M32R_OPERAND_SIMM8 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_simm8); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_simm8); break; case M32R_OPERAND_SIMM16 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_simm16); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_simm16); break; case M32R_OPERAND_UIMM4 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_uimm4); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_uimm4); break; case M32R_OPERAND_UIMM5 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_uimm5); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_uimm5); break; case M32R_OPERAND_UIMM16 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_uimm16); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_uimm16); break; /* start-sanitize-m32rx */ case M32R_OPERAND_IMM1 : { long value; - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_imm1 = ((value) + (1)); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_imm1 = value; } break; /* end-sanitize-m32rx */ /* start-sanitize-m32rx */ case M32R_OPERAND_ACCD : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_accd); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_accd); break; /* end-sanitize-m32rx */ /* start-sanitize-m32rx */ case M32R_OPERAND_ACCS : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_accs); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_accs); break; /* end-sanitize-m32rx */ /* start-sanitize-m32rx */ case M32R_OPERAND_ACC : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_acc); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_acc); break; /* end-sanitize-m32rx */ case M32R_OPERAND_HASH : - length = extract_normal (NULL /*FIXME*/, insn_value, 0, 0, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_nil); + length = extract_normal (od, ex_info, insn_value, 0, 0, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_nil); break; case M32R_OPERAND_HI16 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_hi16); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_hi16); break; case M32R_OPERAND_SLO16 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0, 16, 16, CGEN_FIELDS_BITSIZE (fields), & fields->f_simm16); + length = extract_normal (od, ex_info, insn_value, 0, 16, 16, CGEN_FIELDS_BITSIZE (fields), & fields->f_simm16); break; case M32R_OPERAND_ULO16 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_uimm16); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_uimm16); break; case M32R_OPERAND_UIMM24 : - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_uimm24); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_uimm24); break; case M32R_OPERAND_DISP8 : { long value; - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_disp8 = ((value) << (2)); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_disp8 = value; } break; case M32R_OPERAND_DISP16 : { long value; - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_disp16 = ((value) << (2)); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_disp16 = value; } break; case M32R_OPERAND_DISP24 : { long value; - length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<f_disp24 = ((value) << (2)); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_disp24 = value; } break; default : - fprintf (stderr, "Unrecognized field %d while decoding insn.\n", + /* xgettext:c-format */ + fprintf (stderr, _("Unrecognized field %d while decoding insn.\n"), opindex); abort (); } @@ -266,7 +291,8 @@ m32r_cgen_extract_operand (opindex, buf_ctrl, insn_value, fields) */ void -m32r_cgen_print_operand (opindex, info, fields, attrs, pc, length) +m32r_cgen_print_operand (od, opindex, info, fields, attrs, pc, length) + CGEN_OPCODE_DESC od; int opindex; disassemble_info * info; CGEN_FIELDS * fields; @@ -277,97 +303,98 @@ m32r_cgen_print_operand (opindex, info, fields, attrs, pc, length) switch (opindex) { case M32R_OPERAND_SR : - print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r2, 0|(1<f_r2, 0|(1<f_r1, 0|(1<f_r1, 0|(1<f_r1, 0|(1<f_r1, 0|(1<f_r2, 0|(1<f_r2, 0|(1<f_r2, 0|(1<f_r2, 0|(1<f_r1, 0|(1<f_r1, 0|(1<f_simm8, 0|(1<f_simm8, 0|(1<f_simm16, 0|(1<f_simm16, 0|(1<f_uimm4, 0|(1<f_uimm4, 0|(1<f_uimm5, 0|(1<f_uimm5, 0|(1<f_uimm16, 0|(1<f_uimm16, 0|(1<f_imm1, 0|(1<f_imm1, 0|(1<f_accd, 0|(1<f_accd, 0|(1<f_accs, 0|(1<f_accs, 0|(1<f_acc, 0|(1<f_acc, 0|(1<f_nil, 0, pc, length); + print_hash (od, info, fields->f_nil, 0, pc, length); break; case M32R_OPERAND_HI16 : - print_normal (info, fields->f_hi16, 0|(1<f_hi16, 0|(1<f_simm16, 0, pc, length); + print_normal (od, info, fields->f_simm16, 0, pc, length); break; case M32R_OPERAND_ULO16 : - print_normal (info, fields->f_uimm16, 0|(1<f_uimm16, 0|(1<f_uimm24, 0|(1<f_uimm24, 0|(1<f_disp8, 0|(1<f_disp8, 0|(1<f_disp16, 0|(1<f_disp16, 0|(1<f_disp24, 0|(1<f_disp24, 0|(1<> shift) & mask; +} + +#endif /* ! CGEN_INT_INSN_P */ + /* 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. */ +/* ??? This doesn't handle bfd_vma's. Create another function when + necessary. */ + static int -extract_normal (buf_ctrl, insn_value, attrs, start, length, total_length, valuep) - PTR buf_ctrl; - cgen_insn_t insn_value; +extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep) + CGEN_OPCODE_DESC od; + CGEN_EXTRACT_INFO *ex_info; + CGEN_INSN_BYTES insn_value; unsigned int attrs; int start, length, total_length; long *valuep; { - long value; + unsigned long value; + + /* If LENGTH is zero, this operand doesn't contribute to the value + so give it a standard value of zero. */ + if (length == 0) + { + *valuep = 0; + return 1; + } + +#if CGEN_INT_INSN_P + + { + /* Written this way to avoid undefined behaviour. */ + unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1; + + if (CGEN_INSN_LSB0_P) + value = insn_value >> start; + else + value = insn_value >> (total_length - (start + length)); + value &= mask; + /* sign extend? */ + if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) + && (value & (1L << (length - 1)))) + value |= ~mask; + } -#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 */ + + /* The hard case is probably too slow for the normal cases. + It's certainly more difficult to understand than the normal case. + Thus this is split into two. Keep it that way. The hard case is defined + to be when a field straddles a (loosely defined) word boundary + (??? which may require target specific help to determine). */ + +#if 0 /*wip*/ + +#define HARD_CASE_P 0 /* FIXME:wip */ + + if (HARD_CASE_P) + { + } #endif + else + { + unsigned char *bufp = (unsigned char *) insn_value; + + if (length > 32) + abort (); + + /* Adjust start,total_length,bufp to point to the pseudo-word that holds + the value. For example in a 48 bit insn where the value to insert + (say an immediate value) is the last 16 bits then word_length here + would be 16. To handle a 24 bit insn with an 18 bit immediate, + extract_1 handles 24 bits (using a combination of bfd_get8,16). */ + + if (total_length > 32) + { + int needed_width = start % 8 + length; + int fetch_length = (needed_width <= 8 ? 8 + : needed_width <= 16 ? 16 + : 32); + + if (CGEN_INSN_LSB0_P) + { + if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG) + { + abort (); /* wip */ + } + else + { + int offset = start & ~7; + + bufp += offset / 8; + start -= offset; + total_length -= offset; + } + } + else + { + if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG) + { + int offset = start & ~7; + + bufp += offset / 8; + start -= offset; + total_length -= offset; + } + else + { + abort (); /* wip */ + } + } + } + + /* FIXME: which bytes are being extracted have been lost. */ + value = extract_1 (od, ex_info, start, length, total_length, bufp); + } + +#endif /* ! CGEN_INT_INSN_P */ *valuep = value; @@ -424,44 +592,70 @@ extract_normal (buf_ctrl, insn_value, attrs, start, length, total_length, valuep /* Default print handler. */ static void -print_normal (dis_info, value, attrs, pc, length) +print_normal (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; PTR dis_info; long value; unsigned int attrs; - unsigned long pc; /* FIXME: should be bfd_vma */ + bfd_vma pc; int length; { - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; #ifdef CGEN_PRINT_NORMAL - CGEN_PRINT_NORMAL (info, value, attrs, pc, length); + CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length); #endif /* Print the operand as directed by the attributes. */ - if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_FAKE)) - ; /* nothing to do (??? at least not yet) */ - else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR)) - (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info); - /* ??? Not all cases of this are currently caught. */ - else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR)) - /* FIXME: Why & 0xffffffff? */ - (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); + if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY)) + ; /* nothing to do */ else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED)) (*info->fprintf_func) (info->stream, "0x%lx", value); else (*info->fprintf_func) (info->stream, "%ld", value); } +/* Default address handler. */ + +static void +print_address (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; + PTR dis_info; + bfd_vma value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + +#ifdef CGEN_PRINT_ADDRESS + CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length); +#endif + + /* 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_UNSIGNED)) + (*info->fprintf_func) (info->stream, "0x%lx", (long) value); + else + (*info->fprintf_func) (info->stream, "%ld", (long) value); +} + /* Keyword print handler. */ static void -print_keyword (dis_info, keyword_table, value, attrs) +print_keyword (od, dis_info, keyword_table, value, attrs) + CGEN_OPCODE_DESC od; PTR dis_info; CGEN_KEYWORD *keyword_table; long value; unsigned int attrs; { - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; const CGEN_KEYWORD_ENTRY *ke; ke = cgen_keyword_lookup_value (keyword_table, value); @@ -473,23 +667,28 @@ print_keyword (dis_info, keyword_table, value, attrs) /* 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. */ + INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order. + The extracted fields are stored in FIELDS. + EX_INFO is used to handle reading variable length insns. + Return the length of the insn in bits, or 0 if no match, + or -1 if an error occurs fetching data (memory_error_func will have + been called). */ static int -extract_insn_normal (insn, buf_ctrl, insn_value, fields) +extract_insn_normal (od, insn, ex_info, insn_value, fields, pc) + CGEN_OPCODE_DESC od; const CGEN_INSN *insn; - PTR buf_ctrl; - cgen_insn_t insn_value; + CGEN_EXTRACT_INFO *ex_info; + unsigned long insn_value; CGEN_FIELDS *fields; + bfd_vma pc; { const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); const unsigned char *syn; CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); - CGEN_INIT_EXTRACT (); + CGEN_INIT_EXTRACT (od); for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) { @@ -498,10 +697,10 @@ extract_insn_normal (insn, buf_ctrl, insn_value, fields) if (CGEN_SYNTAX_CHAR_P (*syn)) continue; - length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn), - buf_ctrl, insn_value, fields); - if (length == 0) - return 0; + length = m32r_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn), + ex_info, insn_value, fields, pc); + if (length <= 0) + return length; } /* We recognized and successfully extracted this insn. */ @@ -511,11 +710,11 @@ extract_insn_normal (insn, buf_ctrl, insn_value, fields) /* Default insn printer. DIS_INFO is defined as `PTR' so the disassembler needn't know anything - about disassemble_info. -*/ + about disassemble_info. */ static void -print_insn_normal (dis_info, insn, fields, pc, length) +print_insn_normal (od, dis_info, insn, fields, pc, length) + CGEN_OPCODE_DESC od; PTR dis_info; const CGEN_INSN *insn; CGEN_FIELDS *fields; @@ -523,10 +722,10 @@ print_insn_normal (dis_info, insn, fields, pc, length) int length; { const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); - disassemble_info *info = dis_info; + disassemble_info *info = (disassemble_info *) dis_info; const unsigned char *syn; - CGEN_INIT_PRINT (); + CGEN_INIT_PRINT (od); for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) { @@ -542,23 +741,20 @@ 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 (od, 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. - - The result is the size of the insn in bytes. */ - -#ifndef CGEN_PRINT_INSN -#define CGEN_PRINT_INSN print_insn -#endif +/* 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) +print_insn (od, pc, info, buf, buflen) + CGEN_OPCODE_DESC od; bfd_vma pc; disassemble_info *info; char *buf; @@ -566,16 +762,21 @@ print_insn (pc, info, buf, buflen) { unsigned long insn_value; const CGEN_INSN_LIST *insn_list; + CGEN_EXTRACT_INFO ex_info; + + ex_info.dis_info = info; + ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1; + ex_info.bytes = buf; switch (buflen) { - case 8: + case 1: insn_value = buf[0]; break; - case 16: + case 2: insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf); break; - case 32: + case 4: insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf); break; default: @@ -585,7 +786,7 @@ print_insn (pc, info, buf, buflen) /* 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 (od, buf, insn_value); while (insn_list != NULL) { const CGEN_INSN *insn = insn_list->insn; @@ -594,7 +795,7 @@ print_insn (pc, info, buf, buflen) #if 0 /* not needed as insn shouldn't be in hash lists if not supported */ /* Supported by this cpu? */ - if (! m32r_cgen_insn_supported (insn)) + if (! m32r_cgen_insn_supported (od, insn)) continue; #endif @@ -607,10 +808,14 @@ print_insn (pc, info, buf, buflen) machine insn and extracts the fields. The second pass prints them. */ - length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields); + length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value, + &fields, pc); + /* length < 0 -> error */ + if (length < 0) + return length; if (length > 0) { - (*CGEN_PRINT_FN (insn)) (info, insn, &fields, pc, length); + (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length); /* length is in bits, result is in bytes */ return length / 8; } @@ -622,6 +827,35 @@ 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 (od, pc, info) + CGEN_OPCODE_DESC od; + bfd_vma pc; + disassemble_info *info; +{ + char buf[CGEN_MAX_INSN_SIZE]; + int status; + + /* Read the base part of the insn. */ + + status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info); + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return -1; + } + + return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE); +} + /* Main entry point. Print one instruction from PC on INFO->STREAM. Return the size of the instruction (in bytes). */ @@ -631,30 +865,27 @@ print_insn_m32r (pc, info) 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 length; + static CGEN_OPCODE_DESC od = 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) + /* If we haven't initialized yet, initialize the opcode table. */ + if (! od) { - initialized = 1; - current_mach = mach; - current_big_p = big_p; - m32r_cgen_init_dis (mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE); + od = m32r_cgen_opcode_open (mach, + big_p ? + CGEN_ENDIAN_BIG + : CGEN_ENDIAN_LITTLE); + m32r_cgen_init_dis (od); } - - /* 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've switched cpu's, re-initialize. */ + /* ??? Perhaps we should use BFD_ENDIAN. */ + else if (mach != CGEN_OPCODE_MACH (od) + || (CGEN_OPCODE_ENDIAN (od) + != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE))) { - (*info->memory_error_func) (status, pc, info); - return -1; + cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE); } /* We try to have as much common code as possible. @@ -662,9 +893,11 @@ 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 (od, 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; diff --git a/opcodes/m32r-opc.c b/opcodes/m32r-opc.c index 27a1869579f..67ff11e7bcb 100644 --- a/opcodes/m32r-opc.c +++ b/opcodes/m32r-opc.c @@ -303,12 +303,12 @@ const CGEN_ATTR_TABLE m32r_cgen_hardware_attr_table[] = const CGEN_ATTR_TABLE m32r_cgen_operand_attr_table[] = { { "ABS-ADDR", NULL }, - { "FAKE", NULL }, { "HASH-PREFIX", NULL }, { "NEGATIVE", NULL }, { "PCREL-ADDR", NULL }, { "RELAX", NULL }, { "RELOC", NULL }, + { "SEM-ONLY", NULL }, { "SIGN-OPT", NULL }, { "UNSIGNED", NULL }, { 0, 0 } @@ -447,7 +447,7 @@ const CGEN_OPERAND m32r_cgen_operand_table[MAX_OPERANDS] = { /* pc: program counter */ { "pc", & HW_ENT (HW_H_PC), 0, 0, - { 0, 0|(1<