aboutsummaryrefslogtreecommitdiff
path: root/opcodes/cgen-asm.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/cgen-asm.c')
-rw-r--r--opcodes/cgen-asm.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/opcodes/cgen-asm.c b/opcodes/cgen-asm.c
new file mode 100644
index 0000000..bbc45da
--- /dev/null
+++ b/opcodes/cgen-asm.c
@@ -0,0 +1,276 @@
+/* CGEN generic assembler support code.
+
+Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+
+This file is part of the GNU Binutils and GDB, the GNU debugger.
+
+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 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.
+
+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. */
+
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include "ansidecl.h"
+#include "libiberty.h"
+#include "bfd.h"
+#include "opcode/cgen.h"
+
+/* This is not published as part of the public interface so we don't
+ declare this in cgen.h. */
+extern CGEN_OPCODE_DATA *cgen_current_opcode_data;
+
+/* Assembler instruction hash table. */
+static CGEN_INSN_LIST **asm_hash_table;
+
+void
+cgen_asm_init ()
+{
+ if (asm_hash_table)
+ {
+ free (asm_hash_table);
+ asm_hash_table = NULL;
+ }
+}
+
+/* Build the assembler instruction hash table. */
+
+static void
+build_asm_hash_table ()
+{
+ int i;
+ unsigned int hash;
+ int count = cgen_insn_count ();
+ CGEN_OPCODE_DATA *data = cgen_current_opcode_data;
+ CGEN_INSN_TABLE *insn_table = data->insn_table;
+ unsigned int hash_size = insn_table->asm_hash_table_size;
+ const CGEN_INSN *insn;
+ CGEN_INSN_LIST *insn_lists,*new_insns;
+
+ /* The space allocated for the hash table consists of two parts:
+ the hash table and the hash lists. */
+
+ asm_hash_table = (CGEN_INSN_LIST **)
+ xmalloc (hash_size * sizeof (CGEN_INSN_LIST *)
+ + count * sizeof (CGEN_INSN_LIST));
+ memset (asm_hash_table, 0,
+ hash_size * sizeof (CGEN_INSN_LIST *)
+ + count * sizeof (CGEN_INSN_LIST));
+ insn_lists = (CGEN_INSN_LIST *) (asm_hash_table + hash_size);
+
+ /* Add compiled in insns.
+ The table is scanned backwards as later additions are inserted in
+ front of earlier ones and we want earlier ones to be prefered.
+ We stop at the first one as it is a reserved entry. */
+
+ for (insn = insn_table->init_entries + insn_table->num_init_entries - 1;
+ insn > insn_table->init_entries;
+ --insn, ++insn_lists)
+ {
+ hash = (*insn_table->asm_hash) (insn->syntax.mnemonic);
+ insn_lists->next = asm_hash_table[hash];
+ insn_lists->insn = insn;
+ asm_hash_table[hash] = insn_lists;
+ }
+
+ /* Add runtime added insns.
+ ??? Currently later added insns will be prefered over earlier ones.
+ Not sure this is a bug or not. */
+ for (new_insns = insn_table->new_entries;
+ new_insns != NULL;
+ new_insns = new_insns->next, ++insn_lists)
+ {
+ hash = (*insn_table->asm_hash) (new_insns->insn->syntax.mnemonic);
+ insn_lists->next = asm_hash_table[hash];
+ insn_lists->insn = new_insns->insn;
+ asm_hash_table[hash] = insn_lists;
+ }
+}
+
+/* Return the first entry in the hash list for INSN. */
+
+CGEN_INSN_LIST *
+cgen_asm_lookup_insn (insn)
+ const char *insn;
+{
+ unsigned int hash;
+
+ if (asm_hash_table == NULL)
+ build_asm_hash_table ();
+
+ hash = (*cgen_current_opcode_data->insn_table->asm_hash) (insn);
+ return asm_hash_table[hash];
+}
+
+/* Keyword parser.
+ The result is NULL upon success or an error message.
+ If successful, *STRP is updated to point passed the keyword.
+
+ ??? At present we have a static notion of how to pick out a keyword.
+ Later we can allow a target to customize this if necessary [say by
+ recording something in the keyword table]. */
+
+const char *
+cgen_parse_keyword (strp, keyword_table, valuep)
+ const char **strp;
+ struct cgen_keyword *keyword_table;
+ long *valuep;
+{
+ const struct cgen_keyword_entry *ke;
+ char buf[256];
+ const char *p;
+
+ p = *strp;
+
+ /* Allow any first character. */
+ if (*p)
+ ++p;
+
+ /* Now allow letters, digits, and _. */
+ while (isalnum (*p) || *p == '_')
+ ++p;
+
+ if (p - *strp > 255)
+ return "unrecognized keyword/register name";
+
+ memcpy (buf, *strp, p - *strp);
+ buf[p - *strp] = 0;
+
+ ke = cgen_keyword_lookup_name (keyword_table, buf);
+
+ if (ke != NULL)
+ {
+ *valuep = ke->value;
+ *strp = p;
+ return NULL;
+ }
+
+ return "unrecognized keyword/register name";
+}
+
+/* Signed integer parser. */
+
+const char *
+cgen_parse_signed_integer (strp, opindex, min, max, valuep)
+ const char **strp;
+ int opindex;
+ long min, max;
+ long *valuep;
+{
+ long value;
+ enum cgen_asm_result result;
+ const char *errmsg;
+
+ errmsg = cgen_asm_parse_operand (strp, opindex, BFD_RELOC_NONE,
+ &result, &value);
+ /* FIXME: Examine `result'. */
+ if (!errmsg)
+ {
+ if (value < min || value > max)
+ return "integer operand out of range";
+ *valuep = value;
+ }
+ return errmsg;
+}
+
+/* Unsigned integer parser. */
+
+const char *
+cgen_parse_unsigned_integer (strp, opindex, min, max, valuep)
+ const char **strp;
+ int opindex;
+ unsigned long min, max;
+ unsigned long *valuep;
+{
+ unsigned long value;
+ enum cgen_asm_result result;
+ const char *errmsg;
+
+ errmsg = cgen_asm_parse_operand (strp, opindex, BFD_RELOC_NONE,
+ &result, &value);
+ /* FIXME: Examine `result'. */
+ if (!errmsg)
+ {
+ if (value < min || value > max)
+ return "integer operand out of range";
+ *valuep = value;
+ }
+ return errmsg;
+}
+
+/* Address parser. */
+
+const char *
+cgen_parse_address (strp, opindex, opinfo, valuep)
+ const char **strp;
+ int opindex;
+ int opinfo;
+ long *valuep;
+{
+ long value;
+ enum cgen_asm_result result;
+ const char *errmsg;
+
+ errmsg = cgen_asm_parse_operand (strp, opindex, opinfo, &result, &value);
+ /* FIXME: Examine `result'. */
+ if (!errmsg)
+ {
+ *valuep = value;
+ }
+ return errmsg;
+}
+
+/* Signed integer validation routine. */
+
+const char *
+cgen_validate_signed_integer (value, min, max)
+ long value, min, max;
+{
+ if (value < min || value > max)
+ {
+ const char *err =
+ "operand out of range (%ld not between %ld and %ld)";
+ static char buf[100];
+
+ sprintf (buf, err, value, min, max);
+ return buf;
+ }
+
+ return NULL;
+}
+
+/* Unsigned integer validation routine.
+ Supplying `min' here may seem unnecessary, but we also want to handle
+ cases where min != 0 (and max > LONG_MAX). */
+
+const char *
+cgen_validate_unsigned_integer (value, min, max)
+ unsigned long value, min, max;
+{
+ if (value < min || value > max)
+ {
+ const char *err =
+ "operand out of range (%lu not between %lu and %lu)";
+ static char buf[100];
+
+ sprintf (buf, err, value, min, max);
+ return buf;
+ }
+
+ return NULL;
+}