Back to index

cell-binutils  2.17cvs20070401
ip2k-asm.c
Go to the documentation of this file.
00001 /* Assembler interface for targets using CGEN. -*- C -*-
00002    CGEN: Cpu tools GENerator
00003 
00004    THIS FILE IS MACHINE GENERATED WITH CGEN.
00005    - the resultant file is machine generated, cgen-asm.in isn't
00006 
00007    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005
00008    Free Software Foundation, Inc.
00009 
00010    This file is part of the GNU Binutils and GDB, the GNU debugger.
00011 
00012    This program is free software; you can redistribute it and/or modify
00013    it under the terms of the GNU General Public License as published by
00014    the Free Software Foundation; either version 2, or (at your option)
00015    any later version.
00016 
00017    This program is distributed in the hope that it will be useful,
00018    but WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020    GNU General Public License for more details.
00021 
00022    You should have received a copy of the GNU General Public License
00023    along with this program; if not, write to the Free Software Foundation, Inc.,
00024    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00025 
00026 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
00027    Keep that in mind.  */
00028 
00029 #include "sysdep.h"
00030 #include <stdio.h>
00031 #include "ansidecl.h"
00032 #include "bfd.h"
00033 #include "symcat.h"
00034 #include "ip2k-desc.h"
00035 #include "ip2k-opc.h"
00036 #include "opintl.h"
00037 #include "xregex.h"
00038 #include "libiberty.h"
00039 #include "safe-ctype.h"
00040 
00041 #undef  min
00042 #define min(a,b) ((a) < (b) ? (a) : (b))
00043 #undef  max
00044 #define max(a,b) ((a) > (b) ? (a) : (b))
00045 
00046 static const char * parse_insn_normal
00047   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
00048 
00049 /* -- assembler routines inserted here.  */
00050 
00051 /* -- asm.c */
00052 
00053 static const char *
00054 parse_fr (CGEN_CPU_DESC cd,
00055          const char **strp,
00056          int opindex,
00057          unsigned long *valuep)
00058 {
00059   const char *errmsg;
00060   const char *old_strp;
00061   char *afteroffset; 
00062   enum cgen_parse_operand_result result_type;
00063   bfd_vma value;
00064   extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
00065   bfd_vma tempvalue;
00066 
00067   old_strp = *strp;
00068   afteroffset = NULL;
00069 
00070   /* Check here to see if you're about to try parsing a w as the first arg
00071      and return an error if you are.  */
00072   if ((strncmp (*strp, "w", 1) == 0) || (strncmp (*strp, "W", 1) == 0))
00073     {
00074       (*strp)++;
00075 
00076       if ((strncmp (*strp, ",", 1) == 0) || ISSPACE (**strp))
00077        {
00078          /* We've been passed a w.  Return with an error message so that
00079             cgen will try the next parsing option.  */
00080          errmsg = _("W keyword invalid in FR operand slot.");
00081          return errmsg;
00082        }
00083       *strp = old_strp;
00084     }
00085 
00086   /* Attempt parse as register keyword. */
00087   errmsg = cgen_parse_keyword (cd, strp, & ip2k_cgen_opval_register_names,
00088                             (long *) valuep);
00089   if (*strp != NULL
00090       && errmsg == NULL)
00091     return errmsg;
00092 
00093   /* Attempt to parse for "(IP)".  */
00094   afteroffset = strstr (*strp, "(IP)");
00095 
00096   if (afteroffset == NULL)
00097     /* Make sure it's not in lower case.  */
00098     afteroffset = strstr (*strp, "(ip)");
00099 
00100   if (afteroffset != NULL)
00101     {
00102       if (afteroffset != *strp)
00103        {
00104          /* Invalid offset present.  */
00105          errmsg = _("offset(IP) is not a valid form");
00106          return errmsg;
00107        }
00108       else
00109        {
00110          *strp += 4; 
00111          *valuep = 0;
00112          errmsg = NULL;
00113          return errmsg;
00114        }
00115     }
00116 
00117   /* Attempt to parse for DP. ex: mov w, offset(DP)
00118                                   mov offset(DP),w   */
00119 
00120   /* Try parsing it as an address and see what comes back.  */
00121   afteroffset = strstr (*strp, "(DP)");
00122 
00123   if (afteroffset == NULL)
00124     /* Maybe it's in lower case.  */
00125     afteroffset = strstr (*strp, "(dp)");
00126 
00127   if (afteroffset != NULL)
00128     {
00129       if (afteroffset == *strp)
00130        {
00131          /* No offset present. Use 0 by default.  */
00132          tempvalue = 0;
00133          errmsg = NULL;
00134        }
00135       else
00136        errmsg = cgen_parse_address (cd, strp, opindex,
00137                                  BFD_RELOC_IP2K_FR_OFFSET,
00138                                  & result_type, & tempvalue);
00139 
00140       if (errmsg == NULL)
00141        {
00142          if (tempvalue <= 127)
00143            {
00144              /* Value is ok.  Fix up the first 2 bits and return.  */
00145              *valuep = 0x0100 | tempvalue;
00146              *strp += 4; /* Skip over the (DP) in *strp.  */
00147              return errmsg;
00148            }
00149          else
00150            {
00151              /* Found something there in front of (DP) but it's out
00152                of range.  */
00153              errmsg = _("(DP) offset out of range.");
00154              return errmsg;
00155            }
00156        }
00157     }
00158 
00159 
00160   /* Attempt to parse for SP. ex: mov w, offset(SP)
00161                                   mov offset(SP), w.  */
00162   afteroffset = strstr (*strp, "(SP)");
00163 
00164   if (afteroffset == NULL)
00165     /* Maybe it's in lower case.  */
00166     afteroffset = strstr (*strp, "(sp)");
00167 
00168   if (afteroffset != NULL)
00169     {
00170       if (afteroffset == *strp)
00171        {
00172          /* No offset present. Use 0 by default.  */
00173          tempvalue = 0;
00174          errmsg = NULL;
00175        }
00176       else
00177        errmsg = cgen_parse_address (cd, strp, opindex,
00178                                  BFD_RELOC_IP2K_FR_OFFSET,
00179                                  & result_type, & tempvalue);
00180 
00181       if (errmsg == NULL)
00182        {
00183          if (tempvalue <= 127)
00184            {
00185              /* Value is ok.  Fix up the first 2 bits and return.  */
00186              *valuep = 0x0180 | tempvalue;
00187              *strp += 4; /* Skip over the (SP) in *strp.  */
00188              return errmsg;
00189            }
00190          else
00191            {
00192              /* Found something there in front of (SP) but it's out
00193                of range.  */
00194              errmsg = _("(SP) offset out of range.");
00195              return errmsg;
00196            }
00197        }
00198     }
00199 
00200   /* Attempt to parse as an address.  */
00201   *strp = old_strp;
00202   errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IP2K_FR9,
00203                             & result_type, & value);
00204   if (errmsg == NULL)
00205     {
00206       *valuep = value;
00207 
00208       /* If a parenthesis is found, warn about invalid form.  */
00209       if (**strp == '(')
00210        errmsg = _("illegal use of parentheses");
00211 
00212       /* If a numeric value is specified, ensure that it is between
00213         1 and 255.  */
00214       else if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
00215        {
00216          if (value < 0x1 || value > 0xff)
00217            errmsg = _("operand out of range (not between 1 and 255)");
00218        }
00219     }
00220   return errmsg;
00221 }
00222 
00223 static const char *
00224 parse_addr16 (CGEN_CPU_DESC cd,
00225              const char **strp,
00226              int opindex,
00227              unsigned long *valuep)
00228 {
00229   const char *errmsg;
00230   enum cgen_parse_operand_result result_type;
00231   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
00232   bfd_vma value;
00233 
00234   if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16H)
00235     code = BFD_RELOC_IP2K_HI8DATA;
00236   else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16L)
00237     code = BFD_RELOC_IP2K_LO8DATA;
00238   else
00239     {
00240       /* Something is very wrong. opindex has to be one of the above.  */
00241       errmsg = _("parse_addr16: invalid opindex.");
00242       return errmsg;
00243     }
00244   
00245   errmsg = cgen_parse_address (cd, strp, opindex, code,
00246                             & result_type, & value);
00247   if (errmsg == NULL)
00248     {
00249       /* We either have a relocation or a number now.  */
00250       if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
00251        {
00252          /* We got a number back.  */
00253          if (code == BFD_RELOC_IP2K_HI8DATA)
00254             value >>= 8;
00255          else
00256            /* code = BFD_RELOC_IP2K_LOW8DATA.  */
00257            value &= 0x00FF;
00258        }   
00259       *valuep = value;
00260     }
00261 
00262   return errmsg;
00263 }
00264 
00265 static const char *
00266 parse_addr16_cjp (CGEN_CPU_DESC cd,
00267                 const char **strp,
00268                 int opindex,
00269                 unsigned long *valuep)
00270 {
00271   const char *errmsg;
00272   enum cgen_parse_operand_result result_type;
00273   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
00274   bfd_vma value;
00275  
00276   if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16CJP)
00277     code = BFD_RELOC_IP2K_ADDR16CJP;
00278   else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16P)
00279     code = BFD_RELOC_IP2K_PAGE3;
00280 
00281   errmsg = cgen_parse_address (cd, strp, opindex, code,
00282                             & result_type, & value);
00283   if (errmsg == NULL)
00284     {
00285       if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
00286        {
00287          if ((value & 0x1) == 0)  /* If the address is even .... */
00288            {
00289              if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16CJP)
00290                 *valuep = (value >> 1) & 0x1FFF;  /* Should mask be 1FFF?  */
00291              else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16P)
00292                 *valuep = (value >> 14) & 0x7;
00293            }
00294           else
00295            errmsg = _("Byte address required. - must be even.");
00296        }
00297       else if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
00298        {
00299          /* This will happen for things like (s2-s1) where s2 and s1
00300             are labels.  */
00301          *valuep = value;
00302        }
00303       else 
00304         errmsg = _("cgen_parse_address returned a symbol. Literal required.");
00305     }
00306   return errmsg; 
00307 }
00308 
00309 static const char *
00310 parse_lit8 (CGEN_CPU_DESC cd,
00311            const char **strp,
00312            int opindex,
00313            long *valuep)
00314 {
00315   const char *errmsg;
00316   enum cgen_parse_operand_result result_type;
00317   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
00318   bfd_vma value;
00319 
00320   /* Parse %OP relocating operators.  */
00321   if (strncmp (*strp, "%bank", 5) == 0)
00322     {
00323       *strp += 5;
00324       code = BFD_RELOC_IP2K_BANK;
00325     }
00326   else if (strncmp (*strp, "%lo8data", 8) == 0)
00327     {
00328       *strp += 8;
00329       code = BFD_RELOC_IP2K_LO8DATA;
00330     }
00331   else if (strncmp (*strp, "%hi8data", 8) == 0)
00332     {
00333       *strp += 8;
00334       code = BFD_RELOC_IP2K_HI8DATA;
00335     }
00336   else if (strncmp (*strp, "%ex8data", 8) == 0)
00337     {
00338       *strp += 8;
00339       code = BFD_RELOC_IP2K_EX8DATA;
00340     }
00341   else if (strncmp (*strp, "%lo8insn", 8) == 0)
00342     {
00343       *strp += 8;
00344       code = BFD_RELOC_IP2K_LO8INSN;
00345     }
00346   else if (strncmp (*strp, "%hi8insn", 8) == 0)
00347     {
00348       *strp += 8;
00349       code = BFD_RELOC_IP2K_HI8INSN;
00350     }
00351 
00352   /* Parse %op operand.  */
00353   if (code != BFD_RELOC_NONE)
00354     {
00355       errmsg = cgen_parse_address (cd, strp, opindex, code, 
00356                                & result_type, & value);
00357       if ((errmsg == NULL) &&
00358          (result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED))
00359        errmsg = _("percent-operator operand is not a symbol");
00360 
00361       *valuep = value;
00362     }
00363   /* Parse as a number.  */
00364   else
00365     {
00366       errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
00367 
00368       /* Truncate to eight bits to accept both signed and unsigned input.  */
00369       if (errmsg == NULL)
00370        *valuep &= 0xFF;
00371     }
00372 
00373   return errmsg;
00374 }
00375 
00376 static const char *
00377 parse_bit3 (CGEN_CPU_DESC cd,
00378            const char **strp,
00379            int opindex,
00380            unsigned long *valuep)
00381 {
00382   const char *errmsg;
00383   char mode = 0;
00384   long count = 0;
00385   unsigned long value;
00386 
00387   if (strncmp (*strp, "%bit", 4) == 0)
00388     {
00389       *strp += 4;
00390       mode = 1;
00391     }
00392   else if (strncmp (*strp, "%msbbit", 7) == 0)
00393     {
00394       *strp += 7;
00395       mode = 1;
00396     }
00397   else if (strncmp (*strp, "%lsbbit", 7) == 0)
00398     {
00399       *strp += 7;
00400       mode = 2;
00401     }
00402 
00403   errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
00404   if (errmsg)
00405     return errmsg;
00406 
00407   if (mode)
00408     {
00409       value = * valuep;
00410       if (value == 0)
00411        {
00412          errmsg = _("Attempt to find bit index of 0");
00413          return errmsg;
00414        }
00415     
00416       if (mode == 1)
00417        {
00418          count = 31;
00419          while ((value & 0x80000000) == 0)
00420            {
00421              count--;
00422              value <<= 1;
00423            }
00424        }
00425       else if (mode == 2)
00426        {
00427          count = 0;
00428          while ((value & 0x00000001) == 0)
00429            {
00430              count++;
00431              value >>= 1;
00432            }
00433        }
00434     
00435       *valuep = count;
00436     }
00437 
00438   return errmsg;
00439 }
00440 
00441 /* -- dis.c */
00442 
00443 const char * ip2k_cgen_parse_operand
00444   (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
00445 
00446 /* Main entry point for operand parsing.
00447 
00448    This function is basically just a big switch statement.  Earlier versions
00449    used tables to look up the function to use, but
00450    - if the table contains both assembler and disassembler functions then
00451      the disassembler contains much of the assembler and vice-versa,
00452    - there's a lot of inlining possibilities as things grow,
00453    - using a switch statement avoids the function call overhead.
00454 
00455    This function could be moved into `parse_insn_normal', but keeping it
00456    separate makes clear the interface between `parse_insn_normal' and each of
00457    the handlers.  */
00458 
00459 const char *
00460 ip2k_cgen_parse_operand (CGEN_CPU_DESC cd,
00461                         int opindex,
00462                         const char ** strp,
00463                         CGEN_FIELDS * fields)
00464 {
00465   const char * errmsg = NULL;
00466   /* Used by scalar operands that still need to be parsed.  */
00467   long junk ATTRIBUTE_UNUSED;
00468 
00469   switch (opindex)
00470     {
00471     case IP2K_OPERAND_ADDR16CJP :
00472       errmsg = parse_addr16_cjp (cd, strp, IP2K_OPERAND_ADDR16CJP, (unsigned long *) (& fields->f_addr16cjp));
00473       break;
00474     case IP2K_OPERAND_ADDR16H :
00475       errmsg = parse_addr16 (cd, strp, IP2K_OPERAND_ADDR16H, (unsigned long *) (& fields->f_imm8));
00476       break;
00477     case IP2K_OPERAND_ADDR16L :
00478       errmsg = parse_addr16 (cd, strp, IP2K_OPERAND_ADDR16L, (unsigned long *) (& fields->f_imm8));
00479       break;
00480     case IP2K_OPERAND_ADDR16P :
00481       errmsg = parse_addr16_cjp (cd, strp, IP2K_OPERAND_ADDR16P, (unsigned long *) (& fields->f_page3));
00482       break;
00483     case IP2K_OPERAND_BITNO :
00484       errmsg = parse_bit3 (cd, strp, IP2K_OPERAND_BITNO, (unsigned long *) (& fields->f_bitno));
00485       break;
00486     case IP2K_OPERAND_CBIT :
00487       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_CBIT, (unsigned long *) (& junk));
00488       break;
00489     case IP2K_OPERAND_DCBIT :
00490       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_DCBIT, (unsigned long *) (& junk));
00491       break;
00492     case IP2K_OPERAND_FR :
00493       errmsg = parse_fr (cd, strp, IP2K_OPERAND_FR, (unsigned long *) (& fields->f_reg));
00494       break;
00495     case IP2K_OPERAND_LIT8 :
00496       errmsg = parse_lit8 (cd, strp, IP2K_OPERAND_LIT8, (long *) (& fields->f_imm8));
00497       break;
00498     case IP2K_OPERAND_PABITS :
00499       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_PABITS, (unsigned long *) (& junk));
00500       break;
00501     case IP2K_OPERAND_RETI3 :
00502       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_RETI3, (unsigned long *) (& fields->f_reti3));
00503       break;
00504     case IP2K_OPERAND_ZBIT :
00505       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_ZBIT, (unsigned long *) (& junk));
00506       break;
00507 
00508     default :
00509       /* xgettext:c-format */
00510       fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
00511       abort ();
00512   }
00513 
00514   return errmsg;
00515 }
00516 
00517 cgen_parse_fn * const ip2k_cgen_parse_handlers[] = 
00518 {
00519   parse_insn_normal,
00520 };
00521 
00522 void
00523 ip2k_cgen_init_asm (CGEN_CPU_DESC cd)
00524 {
00525   ip2k_cgen_init_opcode_table (cd);
00526   ip2k_cgen_init_ibld_table (cd);
00527   cd->parse_handlers = & ip2k_cgen_parse_handlers[0];
00528   cd->parse_operand = ip2k_cgen_parse_operand;
00529 #ifdef CGEN_ASM_INIT_HOOK
00530 CGEN_ASM_INIT_HOOK
00531 #endif
00532 }
00533 
00534 
00535 
00536 /* Regex construction routine.
00537 
00538    This translates an opcode syntax string into a regex string,
00539    by replacing any non-character syntax element (such as an
00540    opcode) with the pattern '.*'
00541 
00542    It then compiles the regex and stores it in the opcode, for
00543    later use by ip2k_cgen_assemble_insn
00544 
00545    Returns NULL for success, an error message for failure.  */
00546 
00547 char * 
00548 ip2k_cgen_build_insn_regex (CGEN_INSN *insn)
00549 {  
00550   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
00551   const char *mnem = CGEN_INSN_MNEMONIC (insn);
00552   char rxbuf[CGEN_MAX_RX_ELEMENTS];
00553   char *rx = rxbuf;
00554   const CGEN_SYNTAX_CHAR_TYPE *syn;
00555   int reg_err;
00556 
00557   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
00558 
00559   /* Mnemonics come first in the syntax string.  */
00560   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
00561     return _("missing mnemonic in syntax string");
00562   ++syn;
00563 
00564   /* Generate a case sensitive regular expression that emulates case
00565      insensitive matching in the "C" locale.  We cannot generate a case
00566      insensitive regular expression because in Turkish locales, 'i' and 'I'
00567      are not equal modulo case conversion.  */
00568 
00569   /* Copy the literal mnemonic out of the insn.  */
00570   for (; *mnem; mnem++)
00571     {
00572       char c = *mnem;
00573 
00574       if (ISALPHA (c))
00575        {
00576          *rx++ = '[';
00577          *rx++ = TOLOWER (c);
00578          *rx++ = TOUPPER (c);
00579          *rx++ = ']';
00580        }
00581       else
00582        *rx++ = c;
00583     }
00584 
00585   /* Copy any remaining literals from the syntax string into the rx.  */
00586   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
00587     {
00588       if (CGEN_SYNTAX_CHAR_P (* syn)) 
00589        {
00590          char c = CGEN_SYNTAX_CHAR (* syn);
00591 
00592          switch (c) 
00593            {
00594              /* Escape any regex metacharacters in the syntax.  */
00595            case '.': case '[': case '\\': 
00596            case '*': case '^': case '$': 
00597 
00598 #ifdef CGEN_ESCAPE_EXTENDED_REGEX
00599            case '?': case '{': case '}': 
00600            case '(': case ')': case '*':
00601            case '|': case '+': case ']':
00602 #endif
00603              *rx++ = '\\';
00604              *rx++ = c;
00605              break;
00606 
00607            default:
00608              if (ISALPHA (c))
00609               {
00610                 *rx++ = '[';
00611                 *rx++ = TOLOWER (c);
00612                 *rx++ = TOUPPER (c);
00613                 *rx++ = ']';
00614               }
00615              else
00616               *rx++ = c;
00617              break;
00618            }
00619        }
00620       else
00621        {
00622          /* Replace non-syntax fields with globs.  */
00623          *rx++ = '.';
00624          *rx++ = '*';
00625        }
00626     }
00627 
00628   /* Trailing whitespace ok.  */
00629   * rx++ = '['; 
00630   * rx++ = ' '; 
00631   * rx++ = '\t'; 
00632   * rx++ = ']'; 
00633   * rx++ = '*'; 
00634 
00635   /* But anchor it after that.  */
00636   * rx++ = '$'; 
00637   * rx = '\0';
00638 
00639   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
00640   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
00641 
00642   if (reg_err == 0) 
00643     return NULL;
00644   else
00645     {
00646       static char msg[80];
00647 
00648       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
00649       regfree ((regex_t *) CGEN_INSN_RX (insn));
00650       free (CGEN_INSN_RX (insn));
00651       (CGEN_INSN_RX (insn)) = NULL;
00652       return msg;
00653     }
00654 }
00655 
00656 
00657 /* Default insn parser.
00658 
00659    The syntax string is scanned and operands are parsed and stored in FIELDS.
00660    Relocs are queued as we go via other callbacks.
00661 
00662    ??? Note that this is currently an all-or-nothing parser.  If we fail to
00663    parse the instruction, we return 0 and the caller will start over from
00664    the beginning.  Backtracking will be necessary in parsing subexpressions,
00665    but that can be handled there.  Not handling backtracking here may get
00666    expensive in the case of the m68k.  Deal with later.
00667 
00668    Returns NULL for success, an error message for failure.  */
00669 
00670 static const char *
00671 parse_insn_normal (CGEN_CPU_DESC cd,
00672                  const CGEN_INSN *insn,
00673                  const char **strp,
00674                  CGEN_FIELDS *fields)
00675 {
00676   /* ??? Runtime added insns not handled yet.  */
00677   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
00678   const char *str = *strp;
00679   const char *errmsg;
00680   const char *p;
00681   const CGEN_SYNTAX_CHAR_TYPE * syn;
00682 #ifdef CGEN_MNEMONIC_OPERANDS
00683   /* FIXME: wip */
00684   int past_opcode_p;
00685 #endif
00686 
00687   /* For now we assume the mnemonic is first (there are no leading operands).
00688      We can parse it without needing to set up operand parsing.
00689      GAS's input scrubber will ensure mnemonics are lowercase, but we may
00690      not be called from GAS.  */
00691   p = CGEN_INSN_MNEMONIC (insn);
00692   while (*p && TOLOWER (*p) == TOLOWER (*str))
00693     ++p, ++str;
00694 
00695   if (* p)
00696     return _("unrecognized instruction");
00697 
00698 #ifndef CGEN_MNEMONIC_OPERANDS
00699   if (* str && ! ISSPACE (* str))
00700     return _("unrecognized instruction");
00701 #endif
00702 
00703   CGEN_INIT_PARSE (cd);
00704   cgen_init_parse_operand (cd);
00705 #ifdef CGEN_MNEMONIC_OPERANDS
00706   past_opcode_p = 0;
00707 #endif
00708 
00709   /* We don't check for (*str != '\0') here because we want to parse
00710      any trailing fake arguments in the syntax string.  */
00711   syn = CGEN_SYNTAX_STRING (syntax);
00712 
00713   /* Mnemonics come first for now, ensure valid string.  */
00714   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
00715     abort ();
00716 
00717   ++syn;
00718 
00719   while (* syn != 0)
00720     {
00721       /* Non operand chars must match exactly.  */
00722       if (CGEN_SYNTAX_CHAR_P (* syn))
00723        {
00724          /* FIXME: While we allow for non-GAS callers above, we assume the
00725             first char after the mnemonic part is a space.  */
00726          /* FIXME: We also take inappropriate advantage of the fact that
00727             GAS's input scrubber will remove extraneous blanks.  */
00728          if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
00729            {
00730 #ifdef CGEN_MNEMONIC_OPERANDS
00731              if (CGEN_SYNTAX_CHAR(* syn) == ' ')
00732               past_opcode_p = 1;
00733 #endif
00734              ++ syn;
00735              ++ str;
00736            }
00737          else if (*str)
00738            {
00739              /* Syntax char didn't match.  Can't be this insn.  */
00740              static char msg [80];
00741 
00742              /* xgettext:c-format */
00743              sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
00744                      CGEN_SYNTAX_CHAR(*syn), *str);
00745              return msg;
00746            }
00747          else
00748            {
00749              /* Ran out of input.  */
00750              static char msg [80];
00751 
00752              /* xgettext:c-format */
00753              sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
00754                      CGEN_SYNTAX_CHAR(*syn));
00755              return msg;
00756            }
00757          continue;
00758        }
00759 
00760       /* We have an operand of some sort.  */
00761       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
00762                                      &str, fields);
00763       if (errmsg)
00764        return errmsg;
00765 
00766       /* Done with this operand, continue with next one.  */
00767       ++ syn;
00768     }
00769 
00770   /* If we're at the end of the syntax string, we're done.  */
00771   if (* syn == 0)
00772     {
00773       /* FIXME: For the moment we assume a valid `str' can only contain
00774         blanks now.  IE: We needn't try again with a longer version of
00775         the insn and it is assumed that longer versions of insns appear
00776         before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
00777       while (ISSPACE (* str))
00778        ++ str;
00779 
00780       if (* str != '\0')
00781        return _("junk at end of line"); /* FIXME: would like to include `str' */
00782 
00783       return NULL;
00784     }
00785 
00786   /* We couldn't parse it.  */
00787   return _("unrecognized instruction");
00788 }
00789 
00790 /* Main entry point.
00791    This routine is called for each instruction to be assembled.
00792    STR points to the insn to be assembled.
00793    We assume all necessary tables have been initialized.
00794    The assembled instruction, less any fixups, is stored in BUF.
00795    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
00796    still needs to be converted to target byte order, otherwise BUF is an array
00797    of bytes in target byte order.
00798    The result is a pointer to the insn's entry in the opcode table,
00799    or NULL if an error occured (an error message will have already been
00800    printed).
00801 
00802    Note that when processing (non-alias) macro-insns,
00803    this function recurses.
00804 
00805    ??? It's possible to make this cpu-independent.
00806    One would have to deal with a few minor things.
00807    At this point in time doing so would be more of a curiosity than useful
00808    [for example this file isn't _that_ big], but keeping the possibility in
00809    mind helps keep the design clean.  */
00810 
00811 const CGEN_INSN *
00812 ip2k_cgen_assemble_insn (CGEN_CPU_DESC cd,
00813                         const char *str,
00814                         CGEN_FIELDS *fields,
00815                         CGEN_INSN_BYTES_PTR buf,
00816                         char **errmsg)
00817 {
00818   const char *start;
00819   CGEN_INSN_LIST *ilist;
00820   const char *parse_errmsg = NULL;
00821   const char *insert_errmsg = NULL;
00822   int recognized_mnemonic = 0;
00823 
00824   /* Skip leading white space.  */
00825   while (ISSPACE (* str))
00826     ++ str;
00827 
00828   /* The instructions are stored in hashed lists.
00829      Get the first in the list.  */
00830   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
00831 
00832   /* Keep looking until we find a match.  */
00833   start = str;
00834   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
00835     {
00836       const CGEN_INSN *insn = ilist->insn;
00837       recognized_mnemonic = 1;
00838 
00839 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
00840       /* Not usually needed as unsupported opcodes
00841         shouldn't be in the hash lists.  */
00842       /* Is this insn supported by the selected cpu?  */
00843       if (! ip2k_cgen_insn_supported (cd, insn))
00844        continue;
00845 #endif
00846       /* If the RELAXED attribute is set, this is an insn that shouldn't be
00847         chosen immediately.  Instead, it is used during assembler/linker
00848         relaxation if possible.  */
00849       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
00850        continue;
00851 
00852       str = start;
00853 
00854       /* Skip this insn if str doesn't look right lexically.  */
00855       if (CGEN_INSN_RX (insn) != NULL &&
00856          regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
00857        continue;
00858 
00859       /* Allow parse/insert handlers to obtain length of insn.  */
00860       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
00861 
00862       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
00863       if (parse_errmsg != NULL)
00864        continue;
00865 
00866       /* ??? 0 is passed for `pc'.  */
00867       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
00868                                            (bfd_vma) 0);
00869       if (insert_errmsg != NULL)
00870         continue;
00871 
00872       /* It is up to the caller to actually output the insn and any
00873          queued relocs.  */
00874       return insn;
00875     }
00876 
00877   {
00878     static char errbuf[150];
00879 #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
00880     const char *tmp_errmsg;
00881 
00882     /* If requesting verbose error messages, use insert_errmsg.
00883        Failing that, use parse_errmsg.  */
00884     tmp_errmsg = (insert_errmsg ? insert_errmsg :
00885                 parse_errmsg ? parse_errmsg :
00886                 recognized_mnemonic ?
00887                 _("unrecognized form of instruction") :
00888                 _("unrecognized instruction"));
00889 
00890     if (strlen (start) > 50)
00891       /* xgettext:c-format */
00892       sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
00893     else 
00894       /* xgettext:c-format */
00895       sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
00896 #else
00897     if (strlen (start) > 50)
00898       /* xgettext:c-format */
00899       sprintf (errbuf, _("bad instruction `%.50s...'"), start);
00900     else 
00901       /* xgettext:c-format */
00902       sprintf (errbuf, _("bad instruction `%.50s'"), start);
00903 #endif
00904       
00905     *errmsg = errbuf;
00906     return NULL;
00907   }
00908 }