* arm-dis.c (print_insn_arm): Constify "insn". Formatting.
[deliverable/binutils-gdb.git] / opcodes / cgen-opc.c
index 56840a6a6f9f100706312e9d243313368504962a..06544ca057d0c1e2d4e0dad07a5e42b2c30df677 100644 (file)
@@ -1,6 +1,7 @@
 /* CGEN generic opcode support.
 
 /* 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.
 
 
    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"
    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 <stdio.h>
 #include "ansidecl.h"
 #include "libiberty.h"
+#include "safe-ctype.h"
 #include "bfd.h"
 #include "symcat.h"
 #include "opcode/cgen.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
 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
 
       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)
        ++n, ++p;
 
       if (!*p && !*n)
@@ -113,6 +116,7 @@ cgen_keyword_add (kt, ke)
      CGEN_KEYWORD_ENTRY *ke;
 {
   unsigned int hash;
      CGEN_KEYWORD_ENTRY *ke;
 {
   unsigned int hash;
+  size_t i;
 
   if (kt->name_hash_table == NULL)
     build_keyword_hash_tables (kt);
 
   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;
 
   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.  */
 }
 
 /* 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) *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;
 }
 
   return hash % kt->hash_table_size;
 }
 
@@ -263,7 +282,7 @@ cgen_hw_lookup_by_name (cd, name)
      CGEN_CPU_DESC cd;
      const char *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)
   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;
 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.  */
   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;
 {
      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)
   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;
 {
      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;
     }
 
   return value;
@@ -405,25 +429,30 @@ cgen_put_insn_value (cd, buf, length, value)
      int length;
      CGEN_INSN_INT 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
     }
 }
 \f
@@ -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;
 }
   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;
+}
This page took 0.02748 seconds and 4 git commands to generate.