diff options
author | Doug Evans <dje@google.com> | 1998-02-23 21:17:29 +0000 |
---|---|---|
committer | Doug Evans <dje@google.com> | 1998-02-23 21:17:29 +0000 |
commit | 833d2990732cdaa8b2eb90707d79be8410ec6320 (patch) | |
tree | 39f10588f07aef4c9553a64865048cc05b9e199a /opcodes/cgen-asm.in | |
parent | 677c3439a78142128a56f699159fb5ff617f88b9 (diff) | |
download | gdb-833d2990732cdaa8b2eb90707d79be8410ec6320.zip gdb-833d2990732cdaa8b2eb90707d79be8410ec6320.tar.gz gdb-833d2990732cdaa8b2eb90707d79be8410ec6320.tar.bz2 |
* 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.in | 190 |
1 files changed, 114 insertions, 76 deletions
diff --git a/opcodes/cgen-asm.in b/opcodes/cgen-asm.in index 8a5099b..37250da 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)) |