cgen-asm.c revision 33965
133965Sjdp/* CGEN generic assembler support code. 233965Sjdp 333965SjdpCopyright (C) 1996, 1997 Free Software Foundation, Inc. 433965Sjdp 533965SjdpThis file is part of the GNU Binutils and GDB, the GNU debugger. 633965Sjdp 733965SjdpThis program is free software; you can redistribute it and/or modify 833965Sjdpit under the terms of the GNU General Public License as published by 933965Sjdpthe Free Software Foundation; either version 2, or (at your option) 1033965Sjdpany later version. 1133965Sjdp 1233965SjdpThis program is distributed in the hope that it will be useful, 1333965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1433965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1533965SjdpGNU General Public License for more details. 1633965Sjdp 1733965SjdpYou should have received a copy of the GNU General Public License along 1833965Sjdpwith this program; if not, write to the Free Software Foundation, Inc., 1933965Sjdp59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2033965Sjdp 2133965Sjdp#include "sysdep.h" 2233965Sjdp#include <stdio.h> 2333965Sjdp#include "ansidecl.h" 2433965Sjdp#include "libiberty.h" 2533965Sjdp#include "bfd.h" 2633965Sjdp#include "opcode/cgen.h" 2733965Sjdp 2833965Sjdp/* Operand parsing callback. */ 2933965Sjdpconst char * (*cgen_parse_operand_fn) 3033965Sjdp PARAMS ((enum cgen_parse_operand_type, const char **, int, int, 3133965Sjdp enum cgen_parse_operand_result *, bfd_vma *)); 3233965Sjdp 3333965Sjdp/* This is not published as part of the public interface so we don't 3433965Sjdp declare this in cgen.h. */ 3533965Sjdpextern CGEN_OPCODE_DATA *cgen_current_opcode_data; 3633965Sjdp 3733965Sjdp/* Assembler instruction hash table. */ 3833965Sjdpstatic CGEN_INSN_LIST **asm_hash_table; 3933965Sjdp 4033965Sjdp/* Called once at startup and whenever machine/endian change. */ 4133965Sjdp 4233965Sjdpvoid 4333965Sjdpcgen_asm_init () 4433965Sjdp{ 4533965Sjdp if (asm_hash_table) 4633965Sjdp { 4733965Sjdp free (asm_hash_table); 4833965Sjdp asm_hash_table = NULL; 4933965Sjdp } 5033965Sjdp} 5133965Sjdp 5233965Sjdp/* Called whenever starting to parse an insn. */ 5333965Sjdp 5433965Sjdpvoid 5533965Sjdpcgen_init_parse_operand () 5633965Sjdp{ 5733965Sjdp /* This tells the callback to re-initialize. */ 5833965Sjdp (void) (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INIT, NULL, 0, 0, 5933965Sjdp NULL, NULL); 6033965Sjdp} 6133965Sjdp 6233965Sjdp/* Build the assembler instruction hash table. */ 6333965Sjdp 6433965Sjdpstatic void 6533965Sjdpbuild_asm_hash_table () 6633965Sjdp{ 6733965Sjdp int i; 6833965Sjdp unsigned int hash; 6933965Sjdp int count = cgen_insn_count (); 7033965Sjdp CGEN_OPCODE_DATA *data = cgen_current_opcode_data; 7133965Sjdp CGEN_INSN_TABLE *insn_table = data->insn_table; 7233965Sjdp unsigned int hash_size = insn_table->asm_hash_table_size; 7333965Sjdp const CGEN_INSN *insn; 7433965Sjdp CGEN_INSN_LIST *insn_lists,*new_insns; 7533965Sjdp 7633965Sjdp /* The space allocated for the hash table consists of two parts: 7733965Sjdp the hash table and the hash lists. */ 7833965Sjdp 7933965Sjdp asm_hash_table = (CGEN_INSN_LIST **) 8033965Sjdp xmalloc (hash_size * sizeof (CGEN_INSN_LIST *) 8133965Sjdp + count * sizeof (CGEN_INSN_LIST)); 8233965Sjdp memset (asm_hash_table, 0, 8333965Sjdp hash_size * sizeof (CGEN_INSN_LIST *) 8433965Sjdp + count * sizeof (CGEN_INSN_LIST)); 8533965Sjdp insn_lists = (CGEN_INSN_LIST *) (asm_hash_table + hash_size); 8633965Sjdp 8733965Sjdp /* Add compiled in insns. 8833965Sjdp The table is scanned backwards as later additions are inserted in 8933965Sjdp front of earlier ones and we want earlier ones to be prefered. 9033965Sjdp We stop at the first one as it is a reserved entry. */ 9133965Sjdp 9233965Sjdp for (insn = insn_table->init_entries + insn_table->num_init_entries - 1; 9333965Sjdp insn > insn_table->init_entries; 9433965Sjdp --insn, ++insn_lists) 9533965Sjdp { 9633965Sjdp hash = (*insn_table->asm_hash) (insn->syntax.mnemonic); 9733965Sjdp insn_lists->next = asm_hash_table[hash]; 9833965Sjdp insn_lists->insn = insn; 9933965Sjdp asm_hash_table[hash] = insn_lists; 10033965Sjdp } 10133965Sjdp 10233965Sjdp /* Add runtime added insns. 10333965Sjdp ??? Currently later added insns will be prefered over earlier ones. 10433965Sjdp Not sure this is a bug or not. */ 10533965Sjdp for (new_insns = insn_table->new_entries; 10633965Sjdp new_insns != NULL; 10733965Sjdp new_insns = new_insns->next, ++insn_lists) 10833965Sjdp { 10933965Sjdp hash = (*insn_table->asm_hash) (new_insns->insn->syntax.mnemonic); 11033965Sjdp insn_lists->next = asm_hash_table[hash]; 11133965Sjdp insn_lists->insn = new_insns->insn; 11233965Sjdp asm_hash_table[hash] = insn_lists; 11333965Sjdp } 11433965Sjdp} 11533965Sjdp 11633965Sjdp/* Return the first entry in the hash list for INSN. */ 11733965Sjdp 11833965SjdpCGEN_INSN_LIST * 11933965Sjdpcgen_asm_lookup_insn (insn) 12033965Sjdp const char *insn; 12133965Sjdp{ 12233965Sjdp unsigned int hash; 12333965Sjdp 12433965Sjdp if (asm_hash_table == NULL) 12533965Sjdp build_asm_hash_table (); 12633965Sjdp 12733965Sjdp hash = (*cgen_current_opcode_data->insn_table->asm_hash) (insn); 12833965Sjdp return asm_hash_table[hash]; 12933965Sjdp} 13033965Sjdp 13133965Sjdp/* Keyword parser. 13233965Sjdp The result is NULL upon success or an error message. 13333965Sjdp If successful, *STRP is updated to point passed the keyword. 13433965Sjdp 13533965Sjdp ??? At present we have a static notion of how to pick out a keyword. 13633965Sjdp Later we can allow a target to customize this if necessary [say by 13733965Sjdp recording something in the keyword table]. */ 13833965Sjdp 13933965Sjdpconst char * 14033965Sjdpcgen_parse_keyword (strp, keyword_table, valuep) 14133965Sjdp const char **strp; 14233965Sjdp struct cgen_keyword *keyword_table; 14333965Sjdp long *valuep; 14433965Sjdp{ 14533965Sjdp const struct cgen_keyword_entry *ke; 14633965Sjdp char buf[256]; 14733965Sjdp const char *p; 14833965Sjdp 14933965Sjdp p = *strp; 15033965Sjdp 15133965Sjdp /* Allow any first character. */ 15233965Sjdp if (*p) 15333965Sjdp ++p; 15433965Sjdp 15533965Sjdp /* Now allow letters, digits, and _. */ 15633965Sjdp while (isalnum (*p) || *p == '_') 15733965Sjdp ++p; 15833965Sjdp 15933965Sjdp if (p - *strp > 255) 16033965Sjdp return "unrecognized keyword/register name"; 16133965Sjdp 16233965Sjdp memcpy (buf, *strp, p - *strp); 16333965Sjdp buf[p - *strp] = 0; 16433965Sjdp 16533965Sjdp ke = cgen_keyword_lookup_name (keyword_table, buf); 16633965Sjdp 16733965Sjdp if (ke != NULL) 16833965Sjdp { 16933965Sjdp *valuep = ke->value; 17033965Sjdp *strp = p; 17133965Sjdp return NULL; 17233965Sjdp } 17333965Sjdp 17433965Sjdp return "unrecognized keyword/register name"; 17533965Sjdp} 17633965Sjdp 17733965Sjdp/* Signed integer parser. */ 17833965Sjdp 17933965Sjdpconst char * 18033965Sjdpcgen_parse_signed_integer (strp, opindex, min, max, valuep) 18133965Sjdp const char **strp; 18233965Sjdp int opindex; 18333965Sjdp long min, max; 18433965Sjdp long *valuep; 18533965Sjdp{ 18633965Sjdp long value; 18733965Sjdp enum cgen_parse_operand_result result; 18833965Sjdp const char *errmsg; 18933965Sjdp 19033965Sjdp errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp, 19133965Sjdp opindex, BFD_RELOC_NONE, 19233965Sjdp &result, &value); 19333965Sjdp /* FIXME: Examine `result'. */ 19433965Sjdp if (!errmsg) 19533965Sjdp { 19633965Sjdp if (value < min || value > max) 19733965Sjdp return "integer operand out of range"; 19833965Sjdp *valuep = value; 19933965Sjdp } 20033965Sjdp return errmsg; 20133965Sjdp} 20233965Sjdp 20333965Sjdp/* Unsigned integer parser. */ 20433965Sjdp 20533965Sjdpconst char * 20633965Sjdpcgen_parse_unsigned_integer (strp, opindex, min, max, valuep) 20733965Sjdp const char **strp; 20833965Sjdp int opindex; 20933965Sjdp unsigned long min, max; 21033965Sjdp unsigned long *valuep; 21133965Sjdp{ 21233965Sjdp unsigned long value; 21333965Sjdp enum cgen_parse_operand_result result; 21433965Sjdp const char *errmsg; 21533965Sjdp 21633965Sjdp errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp, 21733965Sjdp opindex, BFD_RELOC_NONE, 21833965Sjdp &result, &value); 21933965Sjdp /* FIXME: Examine `result'. */ 22033965Sjdp if (!errmsg) 22133965Sjdp { 22233965Sjdp if (value < min || value > max) 22333965Sjdp return "integer operand out of range"; 22433965Sjdp *valuep = value; 22533965Sjdp } 22633965Sjdp return errmsg; 22733965Sjdp} 22833965Sjdp 22933965Sjdp/* Address parser. */ 23033965Sjdp 23133965Sjdpconst char * 23233965Sjdpcgen_parse_address (strp, opindex, opinfo, valuep) 23333965Sjdp const char **strp; 23433965Sjdp int opindex; 23533965Sjdp int opinfo; 23633965Sjdp long *valuep; 23733965Sjdp{ 23833965Sjdp long value; 23933965Sjdp enum cgen_parse_operand_result result; 24033965Sjdp const char *errmsg; 24133965Sjdp 24233965Sjdp errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp, 24333965Sjdp opindex, opinfo, 24433965Sjdp &result, &value); 24533965Sjdp /* FIXME: Examine `result'. */ 24633965Sjdp if (!errmsg) 24733965Sjdp { 24833965Sjdp *valuep = value; 24933965Sjdp } 25033965Sjdp return errmsg; 25133965Sjdp} 25233965Sjdp 25333965Sjdp/* Signed integer validation routine. */ 25433965Sjdp 25533965Sjdpconst char * 25633965Sjdpcgen_validate_signed_integer (value, min, max) 25733965Sjdp long value, min, max; 25833965Sjdp{ 25933965Sjdp if (value < min || value > max) 26033965Sjdp { 26133965Sjdp const char *err = 26233965Sjdp "operand out of range (%ld not between %ld and %ld)"; 26333965Sjdp static char buf[100]; 26433965Sjdp 26533965Sjdp sprintf (buf, err, value, min, max); 26633965Sjdp return buf; 26733965Sjdp } 26833965Sjdp 26933965Sjdp return NULL; 27033965Sjdp} 27133965Sjdp 27233965Sjdp/* Unsigned integer validation routine. 27333965Sjdp Supplying `min' here may seem unnecessary, but we also want to handle 27433965Sjdp cases where min != 0 (and max > LONG_MAX). */ 27533965Sjdp 27633965Sjdpconst char * 27733965Sjdpcgen_validate_unsigned_integer (value, min, max) 27833965Sjdp unsigned long value, min, max; 27933965Sjdp{ 28033965Sjdp if (value < min || value > max) 28133965Sjdp { 28233965Sjdp const char *err = 28333965Sjdp "operand out of range (%lu not between %lu and %lu)"; 28433965Sjdp static char buf[100]; 28533965Sjdp 28633965Sjdp sprintf (buf, err, value, min, max); 28733965Sjdp return buf; 28833965Sjdp } 28933965Sjdp 29033965Sjdp return NULL; 29133965Sjdp} 292