X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=opcodes%2Fcgen-opc.c;h=06544ca057d0c1e2d4e0dad07a5e42b2c30df677;hb=6a51a8a8d34f57a9b88de4961c67d0a4cb7026e3;hp=56840a6a6f9f100706312e9d243313368504962a;hpb=5b64ad42d36e6d487e1f7287d37fbc243a178e72;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/cgen-opc.c b/opcodes/cgen-opc.c index 56840a6a6f..06544ca057 100644 --- a/opcodes/cgen-opc.c +++ b/opcodes/cgen-opc.c @@ -1,6 +1,7 @@ /* CGEN generic opcode support. - Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Copyright 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. This file is part of the GNU Binutils and GDB, the GNU debugger. @@ -19,14 +20,18 @@ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sysdep.h" -#include #include #include "ansidecl.h" #include "libiberty.h" +#include "safe-ctype.h" #include "bfd.h" #include "symcat.h" #include "opcode/cgen.h" +#ifdef HAVE_ALLOCA_H +#include +#endif + static unsigned int hash_keyword_name PARAMS ((const CGEN_KEYWORD *, const char *, int)); static unsigned int hash_keyword_value @@ -64,9 +69,7 @@ cgen_keyword_lookup_name (kt, name) while (*p && (*p == *n - || (isalpha ((unsigned char) *p) - && (tolower ((unsigned char) *p) - == tolower ((unsigned char) *n))))) + || (ISALPHA (*p) && (TOLOWER (*p) == TOLOWER (*n))))) ++n, ++p; if (!*p && !*n) @@ -113,6 +116,7 @@ cgen_keyword_add (kt, ke) CGEN_KEYWORD_ENTRY *ke; { unsigned int hash; + size_t i; if (kt->name_hash_table == NULL) build_keyword_hash_tables (kt); @@ -127,6 +131,21 @@ cgen_keyword_add (kt, ke) if (ke->name[0] == 0) kt->null_entry = ke; + + for (i = 1; i < strlen (ke->name); i++) + if (! ISALNUM (ke->name[i]) + && ! strchr (kt->nonalpha_chars, ke->name[i])) + { + size_t idx = strlen (kt->nonalpha_chars); + + /* If you hit this limit, please don't just + increase the size of the field, instead + look for a better algorithm. */ + if (idx >= sizeof (kt->nonalpha_chars) - 1) + abort (); + kt->nonalpha_chars[idx] = ke->name[i]; + kt->nonalpha_chars[idx+1] = 0; + } } /* FIXME: Need function to return count of keywords. */ @@ -211,7 +230,7 @@ hash_keyword_name (kt, name, case_sensitive_p) hash = (hash * 97) + (unsigned char) *name; else for (hash = 0; *name; ++name) - hash = (hash * 97) + (unsigned char) tolower (*name); + hash = (hash * 97) + (unsigned char) TOLOWER (*name); return hash % kt->hash_table_size; } @@ -263,7 +282,7 @@ cgen_hw_lookup_by_name (cd, name) CGEN_CPU_DESC cd; const char *name; { - int i; + unsigned int i; const CGEN_HW_ENTRY **hw = cd->hw_table.entries; for (i = 0; i < cd->hw_table.num_entries; ++i) @@ -281,9 +300,9 @@ cgen_hw_lookup_by_name (cd, name) const CGEN_HW_ENTRY * cgen_hw_lookup_by_num (cd, hwnum) CGEN_CPU_DESC cd; - int hwnum; + unsigned int hwnum; { - int i; + unsigned int i; const CGEN_HW_ENTRY **hw = cd->hw_table.entries; /* ??? This can be speeded up. */ @@ -305,7 +324,7 @@ cgen_operand_lookup_by_name (cd, name) CGEN_CPU_DESC cd; const char *name; { - int i; + unsigned int i; const CGEN_OPERAND **op = cd->operand_table.entries; for (i = 0; i < cd->operand_table.num_entries; ++i) @@ -370,27 +389,32 @@ cgen_get_insn_value (cd, buf, length) unsigned char *buf; int length; { - CGEN_INSN_INT value; + int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG); + int insn_chunk_bitsize = cd->insn_chunk_bitsize; + CGEN_INSN_INT value = 0; - switch (length) + if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length) { - case 8: - value = *buf; - break; - case 16: - if (cd->insn_endian == CGEN_ENDIAN_BIG) - value = bfd_getb16 (buf); - else - value = bfd_getl16 (buf); - break; - case 32: - if (cd->insn_endian == CGEN_ENDIAN_BIG) - value = bfd_getb32 (buf); - else - value = bfd_getl32 (buf); - break; - default: - abort (); + /* We need to divide up the incoming value into insn_chunk_bitsize-length + segments, and endian-convert them, one at a time. */ + int i; + + /* Enforce divisibility. */ + if ((length % insn_chunk_bitsize) != 0) + abort (); + + for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */ + { + int index; + bfd_vma this_value; + index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */ + this_value = bfd_get_bits (& buf[index / 8], insn_chunk_bitsize, big_p); + value = (value << insn_chunk_bitsize) | this_value; + } + } + else + { + value = bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG); } return value; @@ -405,25 +429,30 @@ cgen_put_insn_value (cd, buf, length, value) int length; CGEN_INSN_INT value; { - switch (length) + int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG); + int insn_chunk_bitsize = cd->insn_chunk_bitsize; + + if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length) { - case 8: - buf[0] = value; - break; - case 16: - if (cd->insn_endian == CGEN_ENDIAN_BIG) - bfd_putb16 (value, buf); - else - bfd_putl16 (value, buf); - break; - case 32: - if (cd->insn_endian == CGEN_ENDIAN_BIG) - bfd_putb32 (value, buf); - else - bfd_putl32 (value, buf); - break; - default: - abort (); + /* We need to divide up the incoming value into insn_chunk_bitsize-length + segments, and endian-convert them, one at a time. */ + int i; + + /* Enforce divisibility. */ + if ((length % insn_chunk_bitsize) != 0) + abort (); + + for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */ + { + int index; + index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */ + bfd_put_bits ((bfd_vma) value, & buf[index / 8], insn_chunk_bitsize, big_p); + value >>= insn_chunk_bitsize; + } + } + else + { + bfd_put_bits ((bfd_vma) value, buf, length, big_p); } } @@ -595,3 +624,27 @@ cgen_lookup_get_insn_operands (cd, insn, insn_int_value, insn_bytes_value, cgen_get_insn_operands (cd, insn, fields, indices); return insn; } + +/* Allow signed overflow of instruction fields. */ +void +cgen_set_signed_overflow_ok (cd) + CGEN_CPU_DESC cd; +{ + cd->signed_overflow_ok_p = 1; +} + +/* Generate an error message if a signed field in an instruction overflows. */ +void +cgen_clear_signed_overflow_ok (cd) + CGEN_CPU_DESC cd; +{ + cd->signed_overflow_ok_p = 0; +} + +/* Will an error message be generated if a signed field in an instruction overflows ? */ +unsigned int +cgen_signed_overflow_ok_p (cd) + CGEN_CPU_DESC cd; +{ + return cd->signed_overflow_ok_p; +}