summaryrefslogtreecommitdiff
path: root/opcodes/cgen-asm.in
diff options
context:
space:
mode:
authorDoug Evans <dje@google.com>1998-02-23 21:17:29 +0000
committerDoug Evans <dje@google.com>1998-02-23 21:17:29 +0000
commit833d2990732cdaa8b2eb90707d79be8410ec6320 (patch)
tree39f10588f07aef4c9553a64865048cc05b9e199a /opcodes/cgen-asm.in
parent677c3439a78142128a56f699159fb5ff617f88b9 (diff)
downloadbinutils-gdb-833d2990732cdaa8b2eb90707d79be8410ec6320.tar.gz
* cgen-asm.c: Include symcat.h.
* cgen-dis.c,cgen-opc.c,cgen-asm.in,cgen-dis.in: Ditto.
Diffstat (limited to 'opcodes/cgen-asm.in')
-rw-r--r--opcodes/cgen-asm.in190
1 files changed, 114 insertions, 76 deletions
diff --git a/opcodes/cgen-asm.in b/opcodes/cgen-asm.in
index 8a5099b4ed7..37250da97d5 100644
--- a/opcodes/cgen-asm.in
+++ b/opcodes/cgen-asm.in
@@ -3,7 +3,7 @@
This file is used to generate @arch@-asm.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.
@@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include "ansidecl.h"
#include "bfd.h"
+#include "symcat.h"
#include "@arch@-opc.h"
/* ??? The layout of this stuff is still work in progress.
@@ -35,33 +36,66 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
compiled with GCC), or switch to macros, or use something else.
*/
-static const char *parse_insn_normal
+static const char * parse_insn_normal
PARAMS ((const CGEN_INSN *, const char **, CGEN_FIELDS *));
-static void insert_insn_normal
+static const char * insert_insn_normal
PARAMS ((const CGEN_INSN *, CGEN_FIELDS *, cgen_insn_t *));
/* Default insertion routine.
- SHIFT is negative for left shifts, positive for right shifts.
- All bits of VALUE to be inserted must be valid as we don't handle
- signed vs unsigned shifts.
+ ATTRS is a mask of the boolean attributes.
+ LENGTH is the length of VALUE in bits.
+ TOTAL_LENGTH is the total length of the insn (currently 8,16,32).
- ATTRS is a mask of the boolean attributes. We don't need any at the
- moment, but for consistency with extract_normal we have them. */
+ The result is an error message or NULL if success. */
-/* FIXME: This duplicates functionality with bfd's howto table and
+/* ??? This duplicates functionality with bfd's howto table and
bfd_install_relocation. */
-/* FIXME: For architectures where insns can be representable as ints,
- store insn in `field' struct and add registers, etc. while parsing. */
+/* ??? For architectures where insns can be representable as ints,
+ store insn in `field' struct and add registers, etc. while parsing? */
-static CGEN_INLINE void
+static const char *
insert_normal (value, attrs, start, length, shift, total_length, buffer)
long value;
unsigned int attrs;
- int start, length, shift, total_length;
- char *buffer;
+ int start;
+ int length;
+ int shift;
+ int total_length;
+ char * buffer;
{
bfd_vma x;
+ static char buf[100];
+
+ if (shift < 0)
+ value <<= -shift;
+ else
+ value >>= shift;
+
+ /* Ensure VALUE will fit. */
+ if ((attrs & (1 << CGEN_OPERAND_UNSIGNED)) != 0)
+ {
+ unsigned long max = (1 << length) - 1;
+ if ((unsigned long) value > max)
+ {
+ const char *err = "operand out of range (%lu not between 0 and %lu)";
+
+ sprintf (buf, err, value, max);
+ return buf;
+ }
+ }
+ else
+ {
+ long min = - (1 << (length - 1));
+ long max = (1 << (length - 1)) - 1;
+ if (value < min || value > max)
+ {
+ const char *err = "operand out of range (%ld not between %ld and %ld)";
+
+ sprintf (buf, err, value, min, max);
+ return buf;
+ }
+ }
#if 0 /*def CGEN_INT_INSN*/
*buffer |= ((value & ((1 << length) - 1))
@@ -70,7 +104,7 @@ insert_normal (value, attrs, start, length, shift, total_length, buffer)
switch (total_length)
{
case 8:
- x = *(unsigned char *) buffer;
+ x = * (unsigned char *) buffer;
break;
case 16:
if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
@@ -88,18 +122,13 @@ insert_normal (value, attrs, start, length, shift, total_length, buffer)
abort ();
}
- if (shift < 0)
- value <<= -shift;
- else
- value >>= shift;
-
x |= ((value & ((1 << length) - 1))
<< (total_length - (start + length)));
switch (total_length)
{
case 8:
- *buffer = value;
+ * buffer = value;
break;
case 16:
if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
@@ -117,6 +146,8 @@ insert_normal (value, attrs, start, length, shift, total_length, buffer)
abort ();
}
#endif
+
+ return NULL;
}
/* -- assembler routines inserted here */
@@ -137,15 +168,15 @@ insert_normal (value, attrs, start, length, shift, total_length, buffer)
static const char *
parse_insn_normal (insn, strp, fields)
- const CGEN_INSN *insn;
- const char **strp;
- CGEN_FIELDS *fields;
+ const CGEN_INSN * insn;
+ const char ** strp;
+ CGEN_FIELDS * fields;
{
- const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
- const char *str = *strp;
- const char *errmsg;
- const char *p;
- const unsigned char *syn;
+ const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
+ const char * str = *strp;
+ const char * errmsg;
+ const char * p;
+ const unsigned char * syn;
#ifdef CGEN_MNEMONIC_OPERANDS
int past_opcode_p;
#endif
@@ -153,9 +184,9 @@ parse_insn_normal (insn, strp, fields)
/* For now we assume the mnemonic is first (there are no leading operands).
We can parse it without needing to set up operand parsing. */
p = CGEN_INSN_MNEMONIC (insn);
- while (*p && *p == *str)
- ++p, ++str;
- if (*p || (*str && !isspace (*str)))
+ while (* p && * p == * str)
+ ++ p, ++ str;
+ if (* p || (* str && !isspace (* str)))
return "unrecognized instruction";
CGEN_INIT_PARSE ();
@@ -167,29 +198,33 @@ parse_insn_normal (insn, strp, fields)
/* We don't check for (*str != '\0') here because we want to parse
any trailing fake arguments in the syntax string. */
syn = CGEN_SYNTAX_STRING (CGEN_INSN_SYNTAX (insn));
+
/* Mnemonics come first for now, ensure valid string. */
- if (! CGEN_SYNTAX_MNEMONIC_P (*syn))
+ if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
abort ();
+
++syn;
- while (*syn != 0)
+
+ while (* syn != 0)
{
/* Non operand chars must match exactly. */
/* FIXME: Need to better handle whitespace. */
- if (CGEN_SYNTAX_CHAR_P (*syn))
+ if (CGEN_SYNTAX_CHAR_P (* syn))
{
- if (*str == CGEN_SYNTAX_CHAR (*syn))
+ if (*str == CGEN_SYNTAX_CHAR (* syn))
{
#ifdef CGEN_MNEMONIC_OPERANDS
- if (*syn == ' ')
+ if (* syn == ' ')
past_opcode_p = 1;
#endif
- ++syn;
- ++str;
+ ++ syn;
+ ++ str;
}
else
{
/* Syntax char didn't match. Can't be this insn. */
- /* FIXME: would like to return "expected char `c'" */
+ /* FIXME: would like to return something like
+ "expected char `c'" */
return "syntax error";
}
continue;
@@ -202,20 +237,20 @@ parse_insn_normal (insn, strp, fields)
return errmsg;
/* Done with this operand, continue with next one. */
- ++syn;
+ ++ syn;
}
/* If we're at the end of the syntax string, we're done. */
- if (*syn == '\0')
+ if (* syn == '\0')
{
/* FIXME: For the moment we assume a valid `str' can only contain
blanks now. IE: We needn't try again with a longer version of
the insn and it is assumed that longer versions of insns appear
before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */
- while (isspace (*str))
- ++str;
+ while (isspace (* str))
+ ++ str;
- if (*str != '\0')
+ if (* str != '\0')
return "junk at end of line"; /* FIXME: would like to include `str' */
return NULL;
@@ -226,17 +261,19 @@ parse_insn_normal (insn, strp, fields)
}
/* Default insn builder (insert handler).
- The instruction is recorded in target byte order. */
+ The instruction is recorded in target byte order.
+ The result is an error message or NULL if success. */
+/* FIXME: change buffer to char *? */
-static void
+static const char *
insert_insn_normal (insn, fields, buffer)
- const CGEN_INSN *insn;
- CGEN_FIELDS *fields;
- cgen_insn_t *buffer;
+ const CGEN_INSN * insn;
+ CGEN_FIELDS * fields;
+ cgen_insn_t * buffer;
{
- const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
+ const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
bfd_vma value;
- const unsigned char *syn;
+ const unsigned char * syn;
CGEN_INIT_INSERT ();
value = CGEN_INSN_VALUE (insn);
@@ -251,7 +288,7 @@ insert_insn_normal (insn, fields, buffer)
switch (min (CGEN_BASE_INSN_BITSIZE, CGEN_FIELDS_BITSIZE (fields)))
{
case 8:
- *buffer = value;
+ * buffer = value;
break;
case 16:
if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
@@ -273,13 +310,20 @@ insert_insn_normal (insn, fields, buffer)
/* ??? Rather than scanning the syntax string again, we could store
in `fields' a null terminated list of the fields that are present. */
- for (syn = CGEN_SYNTAX_STRING (syntax); *syn != '\0'; ++syn)
+ for (syn = CGEN_SYNTAX_STRING (syntax); * syn != '\0'; ++ syn)
{
- if (CGEN_SYNTAX_CHAR_P (*syn))
+ const char *errmsg;
+
+ if (CGEN_SYNTAX_CHAR_P (* syn))
continue;
- @arch@_cgen_insert_operand (CGEN_SYNTAX_FIELD (*syn), fields, buffer);
+ errmsg = @arch@_cgen_insert_operand (CGEN_SYNTAX_FIELD (*syn), fields,
+ (char *) buffer);
+ if (errmsg)
+ return errmsg;
}
+
+ return NULL;
}
/* Main entry point.
@@ -292,17 +336,17 @@ insert_insn_normal (insn, fields, buffer)
const CGEN_INSN *
@arch@_cgen_assemble_insn (str, fields, buf, errmsg)
- const char *str;
- CGEN_FIELDS *fields;
- cgen_insn_t *buf;
- char **errmsg;
+ const char * str;
+ CGEN_FIELDS * fields;
+ cgen_insn_t * buf;
+ char ** errmsg;
{
- const char *start;
- CGEN_INSN_LIST *ilist;
+ const char * start;
+ CGEN_INSN_LIST * ilist;
/* Skip leading white space. */
- while (isspace (*str))
- ++str;
+ while (isspace (* str))
+ ++ str;
/* The instructions are stored in hashed lists.
Get the first in the list. */
@@ -336,16 +380,10 @@ const CGEN_INSN *
/* FIXME: wip */
CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
- /* ??? The extent to which moving the parse and insert handlers into
- this function (thus removing the function call) will speed things up
- is unclear. The simplicity and flexibility of the current scheme is
- appropriate for now. One could have the best of both worlds with
- inline functions but of course that would only work for gcc. Since
- we're machine generating some code we could do that here too. Maybe
- later. */
- if (! (*CGEN_PARSE_FN (insn)) (insn, &str, fields))
+ if (! CGEN_PARSE_FN (insn) (insn, & str, fields))
{
- (*CGEN_INSERT_FN (insn)) (insn, fields, buf);
+ if (CGEN_INSERT_FN (insn) (insn, fields, buf) != NULL)
+ continue;
/* It is up to the caller to actually output the insn and any
queued relocs. */
return insn;
@@ -376,12 +414,12 @@ const CGEN_INSN *
void
@arch@_cgen_asm_hash_keywords (opvals)
- CGEN_KEYWORD *opvals;
+ CGEN_KEYWORD * opvals;
{
CGEN_KEYWORD_SEARCH search = cgen_keyword_search_init (opvals, NULL);
- const CGEN_KEYWORD_ENTRY *ke;
+ const CGEN_KEYWORD_ENTRY * ke;
- while ((ke = cgen_keyword_search_next (&search)) != NULL)
+ while ((ke = cgen_keyword_search_next (& search)) != NULL)
{
#if 0 /* Unnecessary, should be done in the search routine. */
if (! @arch@_cgen_opval_supported (ke))