/* 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.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "sysdep.h"
-#include <ctype.h>
#include <stdio.h>
#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 <alloca.h>
+#endif
+
static unsigned int hash_keyword_name
PARAMS ((const CGEN_KEYWORD *, const char *, int));
static unsigned int hash_keyword_value
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)
CGEN_KEYWORD_ENTRY *ke;
{
unsigned int hash;
+ size_t i;
if (kt->name_hash_table == NULL)
build_keyword_hash_tables (kt);
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. */
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;
}
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)
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. */
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)
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;
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);
}
}
\f
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;
+}