133965Sjdp/* CGEN generic assembler support code. 233965Sjdp 3218822Sdim Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 4218822Sdim Free Software Foundation, Inc. 533965Sjdp 638889Sjdp This file is part of the GNU Binutils and GDB, the GNU debugger. 733965Sjdp 838889Sjdp This program is free software; you can redistribute it and/or modify 938889Sjdp it under the terms of the GNU General Public License as published by 1038889Sjdp the Free Software Foundation; either version 2, or (at your option) 1138889Sjdp any later version. 1233965Sjdp 1338889Sjdp This program is distributed in the hope that it will be useful, 1438889Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1538889Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1638889Sjdp GNU General Public License for more details. 1733965Sjdp 1838889Sjdp You should have received a copy of the GNU General Public License along 1938889Sjdp with this program; if not, write to the Free Software Foundation, Inc., 20218822Sdim 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2133965Sjdp 2233965Sjdp#include "sysdep.h" 2333965Sjdp#include <stdio.h> 2433965Sjdp#include "ansidecl.h" 2533965Sjdp#include "libiberty.h" 2689857Sobrien#include "safe-ctype.h" 2733965Sjdp#include "bfd.h" 2838889Sjdp#include "symcat.h" 2933965Sjdp#include "opcode/cgen.h" 3060484Sobrien#include "opintl.h" 3133965Sjdp 32130561Sobrienstatic CGEN_INSN_LIST * hash_insn_array (CGEN_CPU_DESC, const CGEN_INSN *, int, int, CGEN_INSN_LIST **, CGEN_INSN_LIST *); 33130561Sobrienstatic CGEN_INSN_LIST * hash_insn_list (CGEN_CPU_DESC, const CGEN_INSN_LIST *, CGEN_INSN_LIST **, CGEN_INSN_LIST *); 34130561Sobrienstatic void build_asm_hash_table (CGEN_CPU_DESC); 3589857Sobrien 3660484Sobrien/* Set the cgen_parse_operand_fn callback. */ 3733965Sjdp 3860484Sobrienvoid 39130561Sobriencgen_set_parse_operand_fn (CGEN_CPU_DESC cd, cgen_parse_operand_fn fn) 4060484Sobrien{ 4160484Sobrien cd->parse_operand_fn = fn; 4260484Sobrien} 4333965Sjdp 4460484Sobrien/* Called whenever starting to parse an insn. */ 4533965Sjdp 4633965Sjdpvoid 47130561Sobriencgen_init_parse_operand (CGEN_CPU_DESC cd) 4833965Sjdp{ 4960484Sobrien /* This tells the callback to re-initialize. */ 5060484Sobrien (void) (* cd->parse_operand_fn) 5160484Sobrien (cd, CGEN_PARSE_OPERAND_INIT, NULL, 0, 0, NULL, NULL); 5260484Sobrien} 5360484Sobrien 5460484Sobrien/* Subroutine of build_asm_hash_table to add INSNS to the hash table. 5560484Sobrien 5660484Sobrien COUNT is the number of elements in INSNS. 5760484Sobrien ENTSIZE is sizeof (CGEN_IBASE) for the target. 5860484Sobrien ??? No longer used but leave in for now. 5960484Sobrien HTABLE points to the hash table. 6060484Sobrien HENTBUF is a pointer to sufficiently large buffer of hash entries. 6160484Sobrien The result is a pointer to the next entry to use. 6260484Sobrien 6360484Sobrien The table is scanned backwards as additions are made to the front of the 6460484Sobrien list and we want earlier ones to be prefered. */ 6560484Sobrien 6660484Sobrienstatic CGEN_INSN_LIST * 67130561Sobrienhash_insn_array (CGEN_CPU_DESC cd, 68130561Sobrien const CGEN_INSN *insns, 69130561Sobrien int count, 70130561Sobrien int entsize ATTRIBUTE_UNUSED, 71130561Sobrien CGEN_INSN_LIST **htable, 72130561Sobrien CGEN_INSN_LIST *hentbuf) 7360484Sobrien{ 7460484Sobrien int i; 7560484Sobrien 7660484Sobrien for (i = count - 1; i >= 0; --i, ++hentbuf) 7733965Sjdp { 7860484Sobrien unsigned int hash; 7960484Sobrien const CGEN_INSN *insn = &insns[i]; 8060484Sobrien 8160484Sobrien if (! (* cd->asm_hash_p) (insn)) 8260484Sobrien continue; 8360484Sobrien hash = (* cd->asm_hash) (CGEN_INSN_MNEMONIC (insn)); 8460484Sobrien hentbuf->next = htable[hash]; 8560484Sobrien hentbuf->insn = insn; 8660484Sobrien htable[hash] = hentbuf; 8733965Sjdp } 8860484Sobrien 8960484Sobrien return hentbuf; 9033965Sjdp} 9133965Sjdp 9260484Sobrien/* Subroutine of build_asm_hash_table to add INSNS to the hash table. 9360484Sobrien This function is identical to hash_insn_array except the insns are 9460484Sobrien in a list. */ 9533965Sjdp 9660484Sobrienstatic CGEN_INSN_LIST * 97130561Sobrienhash_insn_list (CGEN_CPU_DESC cd, 98130561Sobrien const CGEN_INSN_LIST *insns, 99130561Sobrien CGEN_INSN_LIST **htable, 100130561Sobrien CGEN_INSN_LIST *hentbuf) 10133965Sjdp{ 10260484Sobrien const CGEN_INSN_LIST *ilist; 10360484Sobrien 10460484Sobrien for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf) 10560484Sobrien { 10660484Sobrien unsigned int hash; 10760484Sobrien 10860484Sobrien if (! (* cd->asm_hash_p) (ilist->insn)) 10960484Sobrien continue; 11060484Sobrien hash = (* cd->asm_hash) (CGEN_INSN_MNEMONIC (ilist->insn)); 11160484Sobrien hentbuf->next = htable[hash]; 11260484Sobrien hentbuf->insn = ilist->insn; 11360484Sobrien htable[hash] = hentbuf; 11460484Sobrien } 11560484Sobrien 11660484Sobrien return hentbuf; 11733965Sjdp} 11833965Sjdp 11933965Sjdp/* Build the assembler instruction hash table. */ 12033965Sjdp 12133965Sjdpstatic void 122130561Sobrienbuild_asm_hash_table (CGEN_CPU_DESC cd) 12333965Sjdp{ 12460484Sobrien int count = cgen_insn_count (cd) + cgen_macro_insn_count (cd); 12560484Sobrien CGEN_INSN_TABLE *insn_table = &cd->insn_table; 12660484Sobrien CGEN_INSN_TABLE *macro_insn_table = &cd->macro_insn_table; 12760484Sobrien unsigned int hash_size = cd->asm_hash_size; 12860484Sobrien CGEN_INSN_LIST *hash_entry_buf; 12960484Sobrien CGEN_INSN_LIST **asm_hash_table; 13060484Sobrien CGEN_INSN_LIST *asm_hash_table_entries; 13133965Sjdp 13233965Sjdp /* The space allocated for the hash table consists of two parts: 13333965Sjdp the hash table and the hash lists. */ 13433965Sjdp 13533965Sjdp asm_hash_table = (CGEN_INSN_LIST **) 13660484Sobrien xmalloc (hash_size * sizeof (CGEN_INSN_LIST *)); 13760484Sobrien memset (asm_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *)); 13860484Sobrien asm_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *) 13960484Sobrien xmalloc (count * sizeof (CGEN_INSN_LIST)); 14033965Sjdp 14133965Sjdp /* Add compiled in insns. 14260484Sobrien Don't include the first one as it is a reserved entry. */ 14360484Sobrien /* ??? It was the end of all hash chains, and also the special 14460484Sobrien "invalid insn" marker. May be able to do it differently now. */ 14533965Sjdp 14660484Sobrien hash_entry_buf = hash_insn_array (cd, 14760484Sobrien insn_table->init_entries + 1, 14860484Sobrien insn_table->num_init_entries - 1, 14960484Sobrien insn_table->entry_size, 15060484Sobrien asm_hash_table, hash_entry_buf); 15133965Sjdp 15260484Sobrien /* Add compiled in macro-insns. */ 15360484Sobrien 15460484Sobrien hash_entry_buf = hash_insn_array (cd, macro_insn_table->init_entries, 15560484Sobrien macro_insn_table->num_init_entries, 15660484Sobrien macro_insn_table->entry_size, 15760484Sobrien asm_hash_table, hash_entry_buf); 15860484Sobrien 15933965Sjdp /* Add runtime added insns. 16060484Sobrien Later added insns will be prefered over earlier ones. */ 16160484Sobrien 16260484Sobrien hash_entry_buf = hash_insn_list (cd, insn_table->new_entries, 16360484Sobrien asm_hash_table, hash_entry_buf); 16460484Sobrien 16560484Sobrien /* Add runtime added macro-insns. */ 16660484Sobrien 16760484Sobrien hash_insn_list (cd, macro_insn_table->new_entries, 16860484Sobrien asm_hash_table, hash_entry_buf); 16960484Sobrien 17060484Sobrien cd->asm_hash_table = asm_hash_table; 17160484Sobrien cd->asm_hash_table_entries = asm_hash_table_entries; 17233965Sjdp} 17333965Sjdp 17433965Sjdp/* Return the first entry in the hash list for INSN. */ 17533965Sjdp 17633965SjdpCGEN_INSN_LIST * 177130561Sobriencgen_asm_lookup_insn (CGEN_CPU_DESC cd, const char *insn) 17833965Sjdp{ 17933965Sjdp unsigned int hash; 18033965Sjdp 18160484Sobrien if (cd->asm_hash_table == NULL) 18260484Sobrien build_asm_hash_table (cd); 18333965Sjdp 18460484Sobrien hash = (* cd->asm_hash) (insn); 18560484Sobrien return cd->asm_hash_table[hash]; 18633965Sjdp} 18733965Sjdp 18833965Sjdp/* Keyword parser. 18933965Sjdp The result is NULL upon success or an error message. 19033965Sjdp If successful, *STRP is updated to point passed the keyword. 19133965Sjdp 19233965Sjdp ??? At present we have a static notion of how to pick out a keyword. 19333965Sjdp Later we can allow a target to customize this if necessary [say by 19433965Sjdp recording something in the keyword table]. */ 19533965Sjdp 19633965Sjdpconst char * 197130561Sobriencgen_parse_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 198130561Sobrien const char **strp, 199130561Sobrien CGEN_KEYWORD *keyword_table, 200130561Sobrien long *valuep) 20133965Sjdp{ 20238889Sjdp const CGEN_KEYWORD_ENTRY *ke; 20333965Sjdp char buf[256]; 20438889Sjdp const char *p,*start; 20533965Sjdp 20689857Sobrien if (keyword_table->name_hash_table == NULL) 20789857Sobrien (void) cgen_keyword_search_init (keyword_table, NULL); 20889857Sobrien 20938889Sjdp p = start = *strp; 21033965Sjdp 21189857Sobrien /* Allow any first character. This is to make life easier for 21289857Sobrien the fairly common case of suffixes, eg. 'ld.b.w', where the first 21389857Sobrien character of the suffix ('.') is special. */ 21433965Sjdp if (*p) 21533965Sjdp ++p; 21689857Sobrien 21789857Sobrien /* Allow letters, digits, and any special characters. */ 21838889Sjdp while (((p - start) < (int) sizeof (buf)) 21989857Sobrien && *p 220130561Sobrien && (ISALNUM (*p) 221130561Sobrien || *p == '_' 222130561Sobrien || strchr (keyword_table->nonalpha_chars, *p))) 22333965Sjdp ++p; 22433965Sjdp 22538889Sjdp if (p - start >= (int) sizeof (buf)) 22689857Sobrien { 22789857Sobrien /* All non-empty CGEN keywords can fit into BUF. The only thing 22889857Sobrien we can match here is the empty keyword. */ 22989857Sobrien buf[0] = 0; 23089857Sobrien } 23189857Sobrien else 23289857Sobrien { 23389857Sobrien memcpy (buf, start, p - start); 23489857Sobrien buf[p - start] = 0; 23589857Sobrien } 23633965Sjdp 23733965Sjdp ke = cgen_keyword_lookup_name (keyword_table, buf); 23833965Sjdp 23933965Sjdp if (ke != NULL) 24033965Sjdp { 24133965Sjdp *valuep = ke->value; 24238889Sjdp /* Don't advance pointer if we recognized the null keyword. */ 24338889Sjdp if (ke->name[0] != 0) 24438889Sjdp *strp = p; 24533965Sjdp return NULL; 24633965Sjdp } 24733965Sjdp 24833965Sjdp return "unrecognized keyword/register name"; 24933965Sjdp} 25033965Sjdp 25160484Sobrien/* Parse a small signed integer parser. 25260484Sobrien ??? VALUEP is not a bfd_vma * on purpose, though this is confusing. 25360484Sobrien Note that if the caller expects a bfd_vma result, it should call 25460484Sobrien cgen_parse_address. */ 25533965Sjdp 25633965Sjdpconst char * 257130561Sobriencgen_parse_signed_integer (CGEN_CPU_DESC cd, 258130561Sobrien const char **strp, 259130561Sobrien int opindex, 260130561Sobrien long *valuep) 26133965Sjdp{ 26238889Sjdp bfd_vma value; 26333965Sjdp enum cgen_parse_operand_result result; 26433965Sjdp const char *errmsg; 26533965Sjdp 26660484Sobrien errmsg = (* cd->parse_operand_fn) 26760484Sobrien (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE, 26860484Sobrien &result, &value); 26933965Sjdp /* FIXME: Examine `result'. */ 27033965Sjdp if (!errmsg) 27138889Sjdp *valuep = value; 27233965Sjdp return errmsg; 27333965Sjdp} 27433965Sjdp 27560484Sobrien/* Parse a small unsigned integer parser. 27660484Sobrien ??? VALUEP is not a bfd_vma * on purpose, though this is confusing. 27760484Sobrien Note that if the caller expects a bfd_vma result, it should call 27860484Sobrien cgen_parse_address. */ 27933965Sjdp 28033965Sjdpconst char * 281130561Sobriencgen_parse_unsigned_integer (CGEN_CPU_DESC cd, 282130561Sobrien const char **strp, 283130561Sobrien int opindex, 284130561Sobrien unsigned long *valuep) 28533965Sjdp{ 28638889Sjdp bfd_vma value; 28733965Sjdp enum cgen_parse_operand_result result; 28833965Sjdp const char *errmsg; 28933965Sjdp 29060484Sobrien errmsg = (* cd->parse_operand_fn) 29160484Sobrien (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE, 29260484Sobrien &result, &value); 29333965Sjdp /* FIXME: Examine `result'. */ 29433965Sjdp if (!errmsg) 29538889Sjdp *valuep = value; 29633965Sjdp return errmsg; 29733965Sjdp} 29833965Sjdp 29933965Sjdp/* Address parser. */ 30033965Sjdp 30133965Sjdpconst char * 302130561Sobriencgen_parse_address (CGEN_CPU_DESC cd, 303130561Sobrien const char **strp, 304130561Sobrien int opindex, 305130561Sobrien int opinfo, 306130561Sobrien enum cgen_parse_operand_result *resultp, 307130561Sobrien bfd_vma *valuep) 30833965Sjdp{ 30938889Sjdp bfd_vma value; 31038889Sjdp enum cgen_parse_operand_result result_type; 31133965Sjdp const char *errmsg; 31233965Sjdp 31360484Sobrien errmsg = (* cd->parse_operand_fn) 31460484Sobrien (cd, CGEN_PARSE_OPERAND_ADDRESS, strp, opindex, opinfo, 31560484Sobrien &result_type, &value); 31633965Sjdp /* FIXME: Examine `result'. */ 31733965Sjdp if (!errmsg) 31833965Sjdp { 31938889Sjdp if (resultp != NULL) 32038889Sjdp *resultp = result_type; 32133965Sjdp *valuep = value; 32233965Sjdp } 32333965Sjdp return errmsg; 32433965Sjdp} 32533965Sjdp 32633965Sjdp/* Signed integer validation routine. */ 32733965Sjdp 32833965Sjdpconst char * 329130561Sobriencgen_validate_signed_integer (long value, long min, long max) 33033965Sjdp{ 33133965Sjdp if (value < min || value > max) 33233965Sjdp { 33333965Sjdp static char buf[100]; 33433965Sjdp 33560484Sobrien /* xgettext:c-format */ 33660484Sobrien sprintf (buf, _("operand out of range (%ld not between %ld and %ld)"), 33760484Sobrien value, min, max); 33833965Sjdp return buf; 33933965Sjdp } 34033965Sjdp 34133965Sjdp return NULL; 34233965Sjdp} 34333965Sjdp 34433965Sjdp/* Unsigned integer validation routine. 34533965Sjdp Supplying `min' here may seem unnecessary, but we also want to handle 34633965Sjdp cases where min != 0 (and max > LONG_MAX). */ 34733965Sjdp 34833965Sjdpconst char * 349130561Sobriencgen_validate_unsigned_integer (unsigned long value, 350130561Sobrien unsigned long min, 351130561Sobrien unsigned long max) 35233965Sjdp{ 35333965Sjdp if (value < min || value > max) 35433965Sjdp { 35533965Sjdp static char buf[100]; 35633965Sjdp 35760484Sobrien /* xgettext:c-format */ 35860484Sobrien sprintf (buf, _("operand out of range (%lu not between %lu and %lu)"), 35960484Sobrien value, min, max); 36033965Sjdp return buf; 36133965Sjdp } 36233965Sjdp 36333965Sjdp return NULL; 36433965Sjdp} 365