Home | History | Annotate | Line # | Download | only in opcodes
or1k-asm.c revision 1.4.2.2
      1      1.4  christos /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
      2      1.1      matt /* Assembler interface for targets using CGEN. -*- C -*-
      3      1.1      matt    CGEN: Cpu tools GENerator
      4      1.1      matt 
      5      1.1      matt    THIS FILE IS MACHINE GENERATED WITH CGEN.
      6      1.1      matt    - the resultant file is machine generated, cgen-asm.in isn't
      7      1.1      matt 
      8  1.4.2.2    martin    Copyright (C) 1996-2020 Free Software Foundation, Inc.
      9      1.1      matt 
     10      1.1      matt    This file is part of libopcodes.
     11      1.1      matt 
     12      1.1      matt    This library is free software; you can redistribute it and/or modify
     13      1.1      matt    it under the terms of the GNU General Public License as published by
     14      1.1      matt    the Free Software Foundation; either version 3, or (at your option)
     15      1.1      matt    any later version.
     16      1.1      matt 
     17      1.1      matt    It is distributed in the hope that it will be useful, but WITHOUT
     18      1.1      matt    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     19      1.1      matt    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     20      1.1      matt    License for more details.
     21      1.1      matt 
     22      1.1      matt    You should have received a copy of the GNU General Public License
     23      1.1      matt    along with this program; if not, write to the Free Software Foundation, Inc.,
     24      1.1      matt    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
     25      1.1      matt 
     26      1.1      matt 
     27      1.1      matt /* ??? Eventually more and more of this stuff can go to cpu-independent files.
     28      1.1      matt    Keep that in mind.  */
     29      1.1      matt 
     30      1.1      matt #include "sysdep.h"
     31      1.1      matt #include <stdio.h>
     32      1.1      matt #include "ansidecl.h"
     33      1.1      matt #include "bfd.h"
     34      1.1      matt #include "symcat.h"
     35      1.1      matt #include "or1k-desc.h"
     36      1.1      matt #include "or1k-opc.h"
     37      1.1      matt #include "opintl.h"
     38      1.1      matt #include "xregex.h"
     39      1.1      matt #include "libiberty.h"
     40      1.1      matt #include "safe-ctype.h"
     41      1.1      matt 
     42      1.1      matt #undef  min
     43      1.1      matt #define min(a,b) ((a) < (b) ? (a) : (b))
     44      1.1      matt #undef  max
     45      1.1      matt #define max(a,b) ((a) > (b) ? (a) : (b))
     46      1.1      matt 
     47      1.1      matt static const char * parse_insn_normal
     48      1.1      matt   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
     49      1.1      matt 
     50      1.1      matt /* -- assembler routines inserted here.  */
     52      1.1      matt 
     53      1.1      matt /* -- asm.c */
     54      1.1      matt 
     55  1.4.2.2    martin static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
     56  1.4.2.2    martin static const char * INVALID_STORE_RELOC = N_("relocation invalid for store");
     57      1.1      matt static const char * INVALID_RELOC_TYPE = N_("internal relocation type invalid");
     58      1.1      matt 
     59      1.1      matt #define CGEN_VERBOSE_ASSEMBLER_ERRORS
     60      1.1      matt 
     61      1.1      matt static const char *
     62      1.1      matt parse_disp26 (CGEN_CPU_DESC cd,
     63      1.1      matt 	      const char ** strp,
     64  1.4.2.2    martin 	      int opindex,
     65      1.1      matt 	      int opinfo ATTRIBUTE_UNUSED,
     66      1.1      matt 	      enum cgen_parse_operand_result * resultp,
     67      1.1      matt 	      bfd_vma * valuep)
     68  1.4.2.2    martin {
     69      1.1      matt   const char *str = *strp;
     70  1.4.2.2    martin   const char *errmsg = NULL;
     71      1.1      matt   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
     72  1.4.2.2    martin 
     73      1.1      matt   if (strncasecmp (str, "plta(", 5) == 0)
     74  1.4.2.2    martin     {
     75  1.4.2.2    martin       *strp = str + 5;
     76  1.4.2.2    martin       reloc = BFD_RELOC_OR1K_PLTA26;
     77  1.4.2.2    martin     }
     78  1.4.2.2    martin   else if (strncasecmp (str, "plt(", 4) == 0)
     79  1.4.2.2    martin     {
     80  1.4.2.2    martin       *strp = str + 4;
     81      1.1      matt       reloc = BFD_RELOC_OR1K_PLT26;
     82      1.1      matt     }
     83  1.4.2.2    martin 
     84      1.1      matt   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
     85  1.4.2.2    martin 
     86      1.1      matt   if (reloc != BFD_RELOC_OR1K_REL_26)
     87      1.1      matt     {
     88      1.1      matt       if (**strp != ')')
     89  1.4.2.2    martin 	errmsg = MISSING_CLOSING_PARENTHESIS;
     90  1.4.2.2    martin       else
     91      1.1      matt 	++*strp;
     92      1.1      matt     }
     93  1.4.2.2    martin 
     94  1.4.2.2    martin   return errmsg;
     95      1.1      matt }
     96  1.4.2.2    martin 
     97  1.4.2.2    martin static const char *
     98  1.4.2.2    martin parse_disp21 (CGEN_CPU_DESC cd,
     99  1.4.2.2    martin 	      const char ** strp,
    100  1.4.2.2    martin 	      int opindex,
    101  1.4.2.2    martin 	      int opinfo ATTRIBUTE_UNUSED,
    102  1.4.2.2    martin 	      enum cgen_parse_operand_result * resultp,
    103  1.4.2.2    martin 	      bfd_vma * valuep)
    104  1.4.2.2    martin {
    105  1.4.2.2    martin   const char *str = *strp;
    106  1.4.2.2    martin   const char *errmsg = NULL;
    107      1.1      matt   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
    108  1.4.2.2    martin 
    109      1.1      matt   if (strncasecmp (str, "got(", 4) == 0)
    110  1.4.2.2    martin     {
    111  1.4.2.2    martin       *strp = str + 4;
    112      1.1      matt       reloc = BFD_RELOC_OR1K_GOT_PG21;
    113  1.4.2.2    martin     }
    114      1.1      matt   else if (strncasecmp (str, "tlsgd(", 6) == 0)
    115  1.4.2.2    martin     {
    116  1.4.2.2    martin       *strp = str + 6;
    117      1.1      matt       reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
    118  1.4.2.2    martin     }
    119      1.1      matt   else if (strncasecmp (str, "tlsldm(", 7) == 0)
    120  1.4.2.2    martin     {
    121  1.4.2.2    martin       *strp = str + 7;
    122      1.1      matt       reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
    123  1.4.2.2    martin     }
    124      1.1      matt   else if (strncasecmp (str, "gottp(", 6) == 0)
    125  1.4.2.2    martin     {
    126  1.4.2.2    martin       *strp = str + 6;
    127  1.4.2.2    martin       reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
    128      1.1      matt     }
    129  1.4.2.2    martin 
    130      1.1      matt   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
    131  1.4.2.2    martin 
    132      1.1      matt   if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
    133      1.1      matt     {
    134  1.4.2.2    martin       if (**strp != ')')
    135  1.4.2.2    martin 	errmsg = MISSING_CLOSING_PARENTHESIS;
    136  1.4.2.2    martin       else
    137      1.1      matt 	++*strp;
    138      1.1      matt     }
    139  1.4.2.2    martin 
    140  1.4.2.2    martin   return errmsg;
    141      1.1      matt }
    142  1.4.2.2    martin 
    143  1.4.2.2    martin enum or1k_rclass
    144  1.4.2.2    martin {
    145  1.4.2.2    martin   RCLASS_DIRECT   = 0,
    146  1.4.2.2    martin   RCLASS_GOT      = 1,
    147  1.4.2.2    martin   RCLASS_GOTPC    = 2,
    148  1.4.2.2    martin   RCLASS_GOTOFF   = 3,
    149  1.4.2.2    martin   RCLASS_TLSGD    = 4,
    150  1.4.2.2    martin   RCLASS_TLSLDM   = 5,
    151  1.4.2.2    martin   RCLASS_DTPOFF   = 6,
    152  1.4.2.2    martin   RCLASS_GOTTPOFF = 7,
    153  1.4.2.2    martin   RCLASS_TPOFF    = 8,
    154      1.1      matt };
    155  1.4.2.2    martin 
    156  1.4.2.2    martin enum or1k_rtype
    157  1.4.2.2    martin {
    158  1.4.2.2    martin   RTYPE_LO = 0,
    159  1.4.2.2    martin   RTYPE_SLO = 1,
    160  1.4.2.2    martin   RTYPE_PO = 2,
    161  1.4.2.2    martin   RTYPE_SPO = 3,
    162  1.4.2.2    martin   RTYPE_HI = 4,
    163  1.4.2.2    martin   RTYPE_AHI = 5,
    164      1.1      matt };
    165  1.4.2.2    martin 
    166  1.4.2.2    martin #define RCLASS_SHIFT 3
    167      1.1      matt #define RTYPE_MASK   7
    168  1.4.2.2    martin 
    169  1.4.2.2    martin static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
    170  1.4.2.2    martin   { BFD_RELOC_LO16,
    171  1.4.2.2    martin     BFD_RELOC_OR1K_SLO16,
    172  1.4.2.2    martin     BFD_RELOC_OR1K_LO13,
    173  1.4.2.2    martin     BFD_RELOC_OR1K_SLO13,
    174  1.4.2.2    martin     BFD_RELOC_HI16,
    175  1.4.2.2    martin     BFD_RELOC_HI16_S, },
    176  1.4.2.2    martin   { BFD_RELOC_OR1K_GOT16,
    177  1.4.2.2    martin     BFD_RELOC_UNUSED,
    178  1.4.2.2    martin     BFD_RELOC_OR1K_GOT_LO13,
    179  1.4.2.2    martin     BFD_RELOC_UNUSED,
    180  1.4.2.2    martin     BFD_RELOC_UNUSED,
    181  1.4.2.2    martin     BFD_RELOC_UNUSED },
    182  1.4.2.2    martin   { BFD_RELOC_OR1K_GOTPC_LO16,
    183  1.4.2.2    martin     BFD_RELOC_UNUSED,
    184  1.4.2.2    martin     BFD_RELOC_UNUSED,
    185  1.4.2.2    martin     BFD_RELOC_UNUSED,
    186  1.4.2.2    martin     BFD_RELOC_OR1K_GOTPC_HI16,
    187  1.4.2.2    martin     BFD_RELOC_UNUSED },
    188  1.4.2.2    martin   { BFD_RELOC_LO16_GOTOFF,
    189  1.4.2.2    martin     BFD_RELOC_OR1K_GOTOFF_SLO16,
    190  1.4.2.2    martin     BFD_RELOC_UNUSED,
    191  1.4.2.2    martin     BFD_RELOC_UNUSED,
    192  1.4.2.2    martin     BFD_RELOC_HI16_GOTOFF,
    193  1.4.2.2    martin     BFD_RELOC_HI16_S_GOTOFF },
    194  1.4.2.2    martin   { BFD_RELOC_OR1K_TLS_GD_LO16,
    195  1.4.2.2    martin     BFD_RELOC_UNUSED,
    196  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_GD_LO13,
    197  1.4.2.2    martin     BFD_RELOC_UNUSED,
    198  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_GD_HI16,
    199  1.4.2.2    martin     BFD_RELOC_UNUSED },
    200  1.4.2.2    martin   { BFD_RELOC_OR1K_TLS_LDM_LO16,
    201  1.4.2.2    martin     BFD_RELOC_UNUSED,
    202  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_LDM_LO13,
    203  1.4.2.2    martin     BFD_RELOC_UNUSED,
    204  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_LDM_HI16,
    205  1.4.2.2    martin     BFD_RELOC_UNUSED },
    206  1.4.2.2    martin   { BFD_RELOC_OR1K_TLS_LDO_LO16,
    207  1.4.2.2    martin     BFD_RELOC_UNUSED,
    208  1.4.2.2    martin     BFD_RELOC_UNUSED,
    209  1.4.2.2    martin     BFD_RELOC_UNUSED,
    210  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_LDO_HI16,
    211  1.4.2.2    martin     BFD_RELOC_UNUSED },
    212  1.4.2.2    martin   { BFD_RELOC_OR1K_TLS_IE_LO16,
    213  1.4.2.2    martin     BFD_RELOC_UNUSED,
    214  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_IE_LO13,
    215  1.4.2.2    martin     BFD_RELOC_UNUSED,
    216  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_IE_HI16,
    217  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_IE_AHI16 },
    218  1.4.2.2    martin   { BFD_RELOC_OR1K_TLS_LE_LO16,
    219  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_LE_SLO16,
    220  1.4.2.2    martin     BFD_RELOC_UNUSED,
    221  1.4.2.2    martin     BFD_RELOC_UNUSED,
    222  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_LE_HI16,
    223  1.4.2.2    martin     BFD_RELOC_OR1K_TLS_LE_AHI16 },
    224      1.1      matt };
    225  1.4.2.2    martin 
    226  1.4.2.2    martin static int
    227  1.4.2.2    martin parse_reloc (const char **strp)
    228  1.4.2.2    martin {
    229  1.4.2.2    martin     const char *str = *strp;
    230  1.4.2.2    martin     enum or1k_rclass cls = RCLASS_DIRECT;
    231      1.1      matt     enum or1k_rtype typ;
    232  1.4.2.2    martin 
    233  1.4.2.2    martin     if (strncasecmp (str, "got(", 4) == 0)
    234  1.4.2.2    martin       {
    235  1.4.2.2    martin 	*strp = str + 4;
    236  1.4.2.2    martin 	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
    237  1.4.2.2    martin       }
    238  1.4.2.2    martin     if (strncasecmp (str, "gotpo(", 6) == 0)
    239  1.4.2.2    martin       {
    240  1.4.2.2    martin 	*strp = str + 6;
    241  1.4.2.2    martin 	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
    242  1.4.2.2    martin       }
    243  1.4.2.2    martin     if (strncasecmp (str, "gottppo(", 8) == 0)
    244  1.4.2.2    martin       {
    245  1.4.2.2    martin 	*strp = str + 8;
    246  1.4.2.2    martin 	return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
    247      1.1      matt       }
    248  1.4.2.2    martin 
    249  1.4.2.2    martin     if (strncasecmp (str, "gotpc", 5) == 0)
    250  1.4.2.2    martin       {
    251  1.4.2.2    martin 	str += 5;
    252  1.4.2.2    martin 	cls = RCLASS_GOTPC;
    253  1.4.2.2    martin       }
    254  1.4.2.2    martin     else if (strncasecmp (str, "gotoff", 6) == 0)
    255  1.4.2.2    martin       {
    256  1.4.2.2    martin 	str += 6;
    257  1.4.2.2    martin 	cls = RCLASS_GOTOFF;
    258  1.4.2.2    martin       }
    259  1.4.2.2    martin     else if (strncasecmp (str, "tlsgd", 5) == 0)
    260  1.4.2.2    martin       {
    261  1.4.2.2    martin 	str += 5;
    262  1.4.2.2    martin 	cls = RCLASS_TLSGD;
    263  1.4.2.2    martin       }
    264  1.4.2.2    martin     else if (strncasecmp (str, "tlsldm", 6) == 0)
    265  1.4.2.2    martin       {
    266  1.4.2.2    martin 	str += 6;
    267  1.4.2.2    martin 	cls = RCLASS_TLSLDM;
    268  1.4.2.2    martin       }
    269  1.4.2.2    martin     else if (strncasecmp (str, "dtpoff", 6) == 0)
    270  1.4.2.2    martin       {
    271  1.4.2.2    martin 	str += 6;
    272  1.4.2.2    martin 	cls = RCLASS_DTPOFF;
    273  1.4.2.2    martin       }
    274  1.4.2.2    martin     else if (strncasecmp (str, "gottpoff", 8) == 0)
    275  1.4.2.2    martin       {
    276  1.4.2.2    martin 	str += 8;
    277  1.4.2.2    martin 	cls = RCLASS_GOTTPOFF;
    278  1.4.2.2    martin       }
    279  1.4.2.2    martin     else if (strncasecmp (str, "tpoff", 5) == 0)
    280  1.4.2.2    martin       {
    281  1.4.2.2    martin 	str += 5;
    282  1.4.2.2    martin 	cls = RCLASS_TPOFF;
    283      1.1      matt       }
    284  1.4.2.2    martin 
    285  1.4.2.2    martin     if (strncasecmp (str, "hi(", 3) == 0)
    286  1.4.2.2    martin       {
    287  1.4.2.2    martin 	str += 3;
    288  1.4.2.2    martin 	typ = RTYPE_HI;
    289  1.4.2.2    martin       }
    290  1.4.2.2    martin     else if (strncasecmp (str, "lo(", 3) == 0)
    291  1.4.2.2    martin       {
    292  1.4.2.2    martin 	str += 3;
    293  1.4.2.2    martin 	typ = RTYPE_LO;
    294  1.4.2.2    martin       }
    295  1.4.2.2    martin     else if (strncasecmp (str, "ha(", 3) == 0)
    296  1.4.2.2    martin       {
    297  1.4.2.2    martin 	str += 3;
    298  1.4.2.2    martin 	typ = RTYPE_AHI;
    299  1.4.2.2    martin       }
    300  1.4.2.2    martin     else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
    301  1.4.2.2    martin       {
    302  1.4.2.2    martin 	str += 3;
    303  1.4.2.2    martin 	typ = RTYPE_PO;
    304  1.4.2.2    martin       }
    305  1.4.2.2    martin     else
    306      1.1      matt       return -1;
    307  1.4.2.2    martin 
    308  1.4.2.2    martin     *strp = str;
    309  1.4.2.2    martin     return (cls << RCLASS_SHIFT) | typ;
    310      1.1      matt }
    311  1.4.2.2    martin 
    312  1.4.2.2    martin static const char *
    313  1.4.2.2    martin parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
    314  1.4.2.2    martin 	     long *valuep, int splitp)
    315  1.4.2.2    martin {
    316  1.4.2.2    martin   const char *errmsg;
    317  1.4.2.2    martin   enum cgen_parse_operand_result result_type;
    318  1.4.2.2    martin   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
    319  1.4.2.2    martin   enum or1k_rtype reloc_type;
    320  1.4.2.2    martin   int reloc_code;
    321      1.1      matt   bfd_vma ret;
    322  1.4.2.2    martin 
    323  1.4.2.2    martin   if (**strp == '#')
    324      1.1      matt     ++*strp;
    325  1.4.2.2    martin 
    326  1.4.2.2    martin   reloc_code = parse_reloc (strp);
    327  1.4.2.2    martin   reloc_type = reloc_code & RTYPE_MASK;
    328  1.4.2.2    martin   if (reloc_code >= 0)
    329  1.4.2.2    martin     {
    330  1.4.2.2    martin       enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
    331  1.4.2.2    martin       if (splitp)
    332  1.4.2.2    martin 	{
    333  1.4.2.2    martin 	  if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
    334  1.4.2.2    martin 	      && reloc_class != RCLASS_GOT)
    335  1.4.2.2    martin 	    /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
    336  1.4.2.2    martin 	    reloc_type |= 1;
    337  1.4.2.2    martin 	  else
    338  1.4.2.2    martin 	    return INVALID_STORE_RELOC;
    339  1.4.2.2    martin 	}
    340      1.1      matt       reloc = or1k_imm16_relocs[reloc_class][reloc_type];
    341  1.4.2.2    martin     }
    342  1.4.2.2    martin 
    343      1.1      matt   if (reloc != BFD_RELOC_UNUSED)
    344      1.1      matt     {
    345      1.1      matt       bfd_vma value;
    346  1.4.2.2    martin 
    347      1.1      matt       errmsg = cgen_parse_address (cd, strp, opindex, reloc,
    348      1.1      matt 				   &result_type, &value);
    349  1.4.2.2    martin       if (**strp != ')')
    350      1.1      matt 	errmsg = MISSING_CLOSING_PARENTHESIS;
    351  1.4.2.2    martin       ++*strp;
    352  1.4.2.2    martin 
    353  1.4.2.2    martin       ret = value;
    354  1.4.2.2    martin 
    355  1.4.2.2    martin       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    356  1.4.2.2    martin 	switch (reloc_type)
    357  1.4.2.2    martin 	  {
    358  1.4.2.2    martin 	  case RTYPE_AHI:
    359  1.4.2.2    martin 	    ret += 0x8000;
    360  1.4.2.2    martin 	    /* FALLTHRU */
    361  1.4.2.2    martin 	  case RTYPE_HI:
    362  1.4.2.2    martin 	    ret >>= 16;
    363  1.4.2.2    martin 	    /* FALLTHRU */
    364  1.4.2.2    martin 	  case RTYPE_LO:
    365  1.4.2.2    martin 	  case RTYPE_SLO:
    366  1.4.2.2    martin 	    ret &= 0xffff;
    367  1.4.2.2    martin 	    ret = (ret ^ 0x8000) - 0x8000;
    368  1.4.2.2    martin 	    break;
    369  1.4.2.2    martin 	  case RTYPE_PO:
    370  1.4.2.2    martin 	  case RTYPE_SPO:
    371  1.4.2.2    martin 	    ret &= 0x1fff;
    372  1.4.2.2    martin 	    break;
    373  1.4.2.2    martin 	  default:
    374  1.4.2.2    martin 	    errmsg = INVALID_RELOC_TYPE;
    375      1.1      matt 	  }
    376      1.1      matt     }
    377      1.1      matt   else
    378      1.1      matt     {
    379      1.1      matt       long value;
    380      1.1      matt       errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
    381      1.1      matt       ret = value;
    382      1.1      matt     }
    383      1.1      matt 
    384      1.1      matt   if (errmsg == NULL)
    385      1.1      matt     *valuep = ret;
    386      1.1      matt 
    387      1.1      matt   return errmsg;
    388      1.1      matt }
    389      1.1      matt 
    390  1.4.2.2    martin static const char *
    391  1.4.2.2    martin parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
    392  1.4.2.2    martin {
    393  1.4.2.2    martin   return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
    394  1.4.2.2    martin }
    395  1.4.2.2    martin 
    396  1.4.2.2    martin static const char *
    397  1.4.2.2    martin parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
    398      1.1      matt 		    long *valuep)
    399  1.4.2.2    martin {
    400  1.4.2.2    martin   return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
    401  1.4.2.2    martin }
    402  1.4.2.2    martin 
    403  1.4.2.2    martin static const char *
    404  1.4.2.2    martin parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
    405  1.4.2.2    martin 	      unsigned long *valuep)
    406  1.4.2.2    martin {
    407  1.4.2.2    martin   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
    408  1.4.2.2    martin   if (errmsg == NULL)
    409  1.4.2.2    martin     *valuep &= 0xffff;
    410  1.4.2.2    martin   return errmsg;
    411      1.1      matt }
    412  1.4.2.2    martin 
    413  1.4.2.2    martin static const char *
    414  1.4.2.2    martin parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
    415  1.4.2.2    martin 		    unsigned long *valuep)
    416  1.4.2.2    martin {
    417      1.1      matt   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
    418      1.1      matt   if (errmsg == NULL)
    419      1.1      matt     *valuep &= 0xffff;
    420      1.1      matt   return errmsg;
    421      1.1      matt }
    422  1.4.2.2    martin 
    423  1.4.2.2    martin /* Parse register pairs with syntax rA,rB to a flag + rA value.  */
    424  1.4.2.2    martin 
    425  1.4.2.2    martin static const char *
    426  1.4.2.2    martin parse_regpair (CGEN_CPU_DESC cd, const char **strp,
    427  1.4.2.2    martin 	       int opindex ATTRIBUTE_UNUSED, unsigned long *valuep)
    428  1.4.2.2    martin {
    429  1.4.2.2    martin   long reg1_index;
    430  1.4.2.2    martin   long reg2_index;
    431  1.4.2.2    martin   const char *errmsg;
    432  1.4.2.2    martin 
    433  1.4.2.2    martin   /* The first part should just be a register.  */
    434  1.4.2.2    martin   errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
    435  1.4.2.2    martin 			       &reg1_index);
    436  1.4.2.2    martin 
    437  1.4.2.2    martin   /* If that worked skip the comma separator.  */
    438  1.4.2.2    martin   if (errmsg == NULL)
    439  1.4.2.2    martin     {
    440  1.4.2.2    martin       if (**strp == ',')
    441  1.4.2.2    martin 	++*strp;
    442  1.4.2.2    martin       else
    443  1.4.2.2    martin 	errmsg = "Unexpected character, expected ','";
    444  1.4.2.2    martin     }
    445  1.4.2.2    martin 
    446  1.4.2.2    martin   /* If that worked the next part is just another register.  */
    447  1.4.2.2    martin   if (errmsg == NULL)
    448  1.4.2.2    martin     errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
    449  1.4.2.2    martin 				 &reg2_index);
    450  1.4.2.2    martin 
    451  1.4.2.2    martin   /* Validate the register pair is valid and create the output value.  */
    452  1.4.2.2    martin   if (errmsg == NULL)
    453  1.4.2.2    martin     {
    454  1.4.2.2    martin       int regoffset = reg2_index - reg1_index;
    455  1.4.2.2    martin 
    456  1.4.2.2    martin       if (regoffset == 1 || regoffset == 2)
    457  1.4.2.2    martin 	{
    458  1.4.2.2    martin 	  unsigned short offsetmask;
    459  1.4.2.2    martin 	  unsigned short value;
    460  1.4.2.2    martin 
    461  1.4.2.2    martin 	  offsetmask = ((regoffset == 2 ? 1 : 0) << 5);
    462  1.4.2.2    martin 	  value = offsetmask | reg1_index;
    463  1.4.2.2    martin 
    464  1.4.2.2    martin 	  *valuep = value;
    465  1.4.2.2    martin 	}
    466  1.4.2.2    martin       else
    467  1.4.2.2    martin 	errmsg = "Invalid register pair, offset not 1 or 2.";
    468  1.4.2.2    martin     }
    469  1.4.2.2    martin 
    470  1.4.2.2    martin   return errmsg;
    471  1.4.2.2    martin }
    472      1.1      matt 
    473      1.1      matt /* -- */
    474      1.1      matt 
    475      1.1      matt const char * or1k_cgen_parse_operand
    476      1.1      matt   (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
    477      1.1      matt 
    478      1.1      matt /* Main entry point for operand parsing.
    479      1.1      matt 
    480      1.1      matt    This function is basically just a big switch statement.  Earlier versions
    481      1.1      matt    used tables to look up the function to use, but
    482      1.1      matt    - if the table contains both assembler and disassembler functions then
    483      1.1      matt      the disassembler contains much of the assembler and vice-versa,
    484      1.1      matt    - there's a lot of inlining possibilities as things grow,
    485      1.1      matt    - using a switch statement avoids the function call overhead.
    486      1.1      matt 
    487      1.1      matt    This function could be moved into `parse_insn_normal', but keeping it
    488      1.1      matt    separate makes clear the interface between `parse_insn_normal' and each of
    489      1.1      matt    the handlers.  */
    490      1.1      matt 
    491      1.1      matt const char *
    492      1.1      matt or1k_cgen_parse_operand (CGEN_CPU_DESC cd,
    493      1.1      matt 			   int opindex,
    494      1.1      matt 			   const char ** strp,
    495      1.1      matt 			   CGEN_FIELDS * fields)
    496      1.1      matt {
    497      1.1      matt   const char * errmsg = NULL;
    498      1.1      matt   /* Used by scalar operands that still need to be parsed.  */
    499      1.1      matt   long junk ATTRIBUTE_UNUSED;
    500      1.1      matt 
    501      1.1      matt   switch (opindex)
    502  1.4.2.2    martin     {
    503  1.4.2.2    martin     case OR1K_OPERAND_DISP21 :
    504  1.4.2.2    martin       {
    505  1.4.2.2    martin         bfd_vma value = 0;
    506  1.4.2.2    martin         errmsg = parse_disp21 (cd, strp, OR1K_OPERAND_DISP21, 0, NULL,  & value);
    507  1.4.2.2    martin         fields->f_disp21 = value;
    508  1.4.2.2    martin       }
    509      1.1      matt       break;
    510      1.1      matt     case OR1K_OPERAND_DISP26 :
    511      1.1      matt       {
    512      1.1      matt         bfd_vma value = 0;
    513      1.1      matt         errmsg = parse_disp26 (cd, strp, OR1K_OPERAND_DISP26, 0, NULL,  & value);
    514      1.1      matt         fields->f_disp26 = value;
    515      1.1      matt       }
    516      1.1      matt       break;
    517      1.1      matt     case OR1K_OPERAND_RA :
    518      1.1      matt       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r2);
    519  1.4.2.2    martin       break;
    520  1.4.2.2    martin     case OR1K_OPERAND_RAD32F :
    521  1.4.2.2    martin       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RAD32F, (unsigned long *) (& fields->f_rad32));
    522      1.1      matt       break;
    523  1.4.2.2    martin     case OR1K_OPERAND_RADF :
    524  1.4.2.2    martin       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fdr, & fields->f_r2);
    525  1.4.2.2    martin       break;
    526  1.4.2.2    martin     case OR1K_OPERAND_RADI :
    527      1.1      matt       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RADI, (unsigned long *) (& fields->f_rad32));
    528      1.1      matt       break;
    529      1.1      matt     case OR1K_OPERAND_RASF :
    530      1.1      matt       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r2);
    531      1.1      matt       break;
    532      1.1      matt     case OR1K_OPERAND_RB :
    533      1.1      matt       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r3);
    534  1.4.2.2    martin       break;
    535  1.4.2.2    martin     case OR1K_OPERAND_RBD32F :
    536  1.4.2.2    martin       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RBD32F, (unsigned long *) (& fields->f_rbd32));
    537      1.1      matt       break;
    538  1.4.2.2    martin     case OR1K_OPERAND_RBDF :
    539  1.4.2.2    martin       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fdr, & fields->f_r3);
    540  1.4.2.2    martin       break;
    541  1.4.2.2    martin     case OR1K_OPERAND_RBDI :
    542      1.1      matt       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RBDI, (unsigned long *) (& fields->f_rbd32));
    543      1.1      matt       break;
    544      1.1      matt     case OR1K_OPERAND_RBSF :
    545      1.1      matt       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r3);
    546      1.1      matt       break;
    547      1.1      matt     case OR1K_OPERAND_RD :
    548      1.1      matt       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r1);
    549  1.4.2.2    martin       break;
    550  1.4.2.2    martin     case OR1K_OPERAND_RDD32F :
    551  1.4.2.2    martin       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RDD32F, (unsigned long *) (& fields->f_rdd32));
    552      1.1      matt       break;
    553      1.1      matt     case OR1K_OPERAND_RDDF :
    554      1.1      matt       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fdr, & fields->f_r1);
    555  1.4.2.2    martin       break;
    556  1.4.2.2    martin     case OR1K_OPERAND_RDDI :
    557  1.4.2.2    martin       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RDDI, (unsigned long *) (& fields->f_rdd32));
    558      1.1      matt       break;
    559      1.1      matt     case OR1K_OPERAND_RDSF :
    560      1.1      matt       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r1);
    561      1.1      matt       break;
    562      1.1      matt     case OR1K_OPERAND_SIMM16 :
    563      1.1      matt       errmsg = parse_simm16 (cd, strp, OR1K_OPERAND_SIMM16, (long *) (& fields->f_simm16));
    564      1.1      matt       break;
    565  1.4.2.2    martin     case OR1K_OPERAND_SIMM16_SPLIT :
    566      1.1      matt       errmsg = parse_simm16_split (cd, strp, OR1K_OPERAND_SIMM16_SPLIT, (long *) (& fields->f_simm16_split));
    567      1.1      matt       break;
    568      1.1      matt     case OR1K_OPERAND_UIMM16 :
    569      1.1      matt       errmsg = parse_uimm16 (cd, strp, OR1K_OPERAND_UIMM16, (unsigned long *) (& fields->f_uimm16));
    570      1.1      matt       break;
    571  1.4.2.2    martin     case OR1K_OPERAND_UIMM16_SPLIT :
    572      1.1      matt       errmsg = parse_uimm16_split (cd, strp, OR1K_OPERAND_UIMM16_SPLIT, (unsigned long *) (& fields->f_uimm16_split));
    573      1.1      matt       break;
    574      1.1      matt     case OR1K_OPERAND_UIMM6 :
    575      1.1      matt       errmsg = cgen_parse_unsigned_integer (cd, strp, OR1K_OPERAND_UIMM6, (unsigned long *) (& fields->f_uimm6));
    576      1.1      matt       break;
    577      1.1      matt 
    578      1.1      matt     default :
    579  1.4.2.1  christos       /* xgettext:c-format */
    580  1.4.2.1  christos       opcodes_error_handler
    581  1.4.2.1  christos 	(_("internal error: unrecognized field %d while parsing"),
    582      1.1      matt 	 opindex);
    583      1.1      matt       abort ();
    584      1.1      matt   }
    585      1.1      matt 
    586      1.1      matt   return errmsg;
    587      1.1      matt }
    588      1.2  christos 
    589      1.1      matt cgen_parse_fn * const or1k_cgen_parse_handlers[] =
    590      1.1      matt {
    591      1.1      matt   parse_insn_normal,
    592      1.1      matt };
    593      1.1      matt 
    594      1.1      matt void
    595      1.1      matt or1k_cgen_init_asm (CGEN_CPU_DESC cd)
    596      1.1      matt {
    597      1.1      matt   or1k_cgen_init_opcode_table (cd);
    598      1.1      matt   or1k_cgen_init_ibld_table (cd);
    599      1.1      matt   cd->parse_handlers = & or1k_cgen_parse_handlers[0];
    600      1.1      matt   cd->parse_operand = or1k_cgen_parse_operand;
    601      1.1      matt #ifdef CGEN_ASM_INIT_HOOK
    602      1.1      matt CGEN_ASM_INIT_HOOK
    603      1.1      matt #endif
    604      1.1      matt }
    605      1.1      matt 
    606      1.1      matt 
    607      1.1      matt 
    609      1.1      matt /* Regex construction routine.
    610      1.1      matt 
    611      1.1      matt    This translates an opcode syntax string into a regex string,
    612      1.1      matt    by replacing any non-character syntax element (such as an
    613      1.1      matt    opcode) with the pattern '.*'
    614      1.1      matt 
    615      1.1      matt    It then compiles the regex and stores it in the opcode, for
    616      1.1      matt    later use by or1k_cgen_assemble_insn
    617      1.1      matt 
    618      1.2  christos    Returns NULL for success, an error message for failure.  */
    619      1.1      matt 
    620      1.2  christos char *
    621      1.1      matt or1k_cgen_build_insn_regex (CGEN_INSN *insn)
    622      1.1      matt {
    623      1.1      matt   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
    624      1.1      matt   const char *mnem = CGEN_INSN_MNEMONIC (insn);
    625      1.1      matt   char rxbuf[CGEN_MAX_RX_ELEMENTS];
    626      1.1      matt   char *rx = rxbuf;
    627      1.1      matt   const CGEN_SYNTAX_CHAR_TYPE *syn;
    628      1.1      matt   int reg_err;
    629      1.1      matt 
    630      1.1      matt   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
    631      1.1      matt 
    632      1.1      matt   /* Mnemonics come first in the syntax string.  */
    633      1.1      matt   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
    634      1.1      matt     return _("missing mnemonic in syntax string");
    635      1.1      matt   ++syn;
    636      1.1      matt 
    637      1.1      matt   /* Generate a case sensitive regular expression that emulates case
    638      1.1      matt      insensitive matching in the "C" locale.  We cannot generate a case
    639      1.1      matt      insensitive regular expression because in Turkish locales, 'i' and 'I'
    640      1.1      matt      are not equal modulo case conversion.  */
    641      1.1      matt 
    642      1.1      matt   /* Copy the literal mnemonic out of the insn.  */
    643      1.1      matt   for (; *mnem; mnem++)
    644      1.1      matt     {
    645      1.1      matt       char c = *mnem;
    646      1.1      matt 
    647      1.1      matt       if (ISALPHA (c))
    648      1.1      matt 	{
    649      1.1      matt 	  *rx++ = '[';
    650      1.1      matt 	  *rx++ = TOLOWER (c);
    651      1.1      matt 	  *rx++ = TOUPPER (c);
    652      1.1      matt 	  *rx++ = ']';
    653      1.1      matt 	}
    654      1.1      matt       else
    655      1.1      matt 	*rx++ = c;
    656      1.1      matt     }
    657      1.1      matt 
    658      1.1      matt   /* Copy any remaining literals from the syntax string into the rx.  */
    659      1.2  christos   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
    660      1.1      matt     {
    661      1.1      matt       if (CGEN_SYNTAX_CHAR_P (* syn))
    662      1.1      matt 	{
    663      1.2  christos 	  char c = CGEN_SYNTAX_CHAR (* syn);
    664      1.1      matt 
    665      1.1      matt 	  switch (c)
    666      1.2  christos 	    {
    667      1.2  christos 	      /* Escape any regex metacharacters in the syntax.  */
    668      1.1      matt 	    case '.': case '[': case '\\':
    669      1.1      matt 	    case '*': case '^': case '$':
    670      1.2  christos 
    671      1.1      matt #ifdef CGEN_ESCAPE_EXTENDED_REGEX
    672      1.1      matt 	    case '?': case '{': case '}':
    673      1.1      matt 	    case '(': case ')': case '*':
    674      1.1      matt 	    case '|': case '+': case ']':
    675      1.1      matt #endif
    676      1.1      matt 	      *rx++ = '\\';
    677      1.1      matt 	      *rx++ = c;
    678      1.1      matt 	      break;
    679      1.1      matt 
    680      1.1      matt 	    default:
    681      1.1      matt 	      if (ISALPHA (c))
    682      1.1      matt 		{
    683      1.1      matt 		  *rx++ = '[';
    684      1.1      matt 		  *rx++ = TOLOWER (c);
    685      1.1      matt 		  *rx++ = TOUPPER (c);
    686      1.1      matt 		  *rx++ = ']';
    687      1.1      matt 		}
    688      1.1      matt 	      else
    689      1.1      matt 		*rx++ = c;
    690      1.1      matt 	      break;
    691      1.1      matt 	    }
    692      1.1      matt 	}
    693      1.1      matt       else
    694      1.1      matt 	{
    695      1.1      matt 	  /* Replace non-syntax fields with globs.  */
    696      1.1      matt 	  *rx++ = '.';
    697      1.1      matt 	  *rx++ = '*';
    698      1.1      matt 	}
    699      1.1      matt     }
    700      1.2  christos 
    701      1.2  christos   /* Trailing whitespace ok.  */
    702      1.2  christos   * rx++ = '[';
    703      1.2  christos   * rx++ = ' ';
    704      1.2  christos   * rx++ = '\t';
    705      1.1      matt   * rx++ = ']';
    706      1.1      matt   * rx++ = '*';
    707      1.2  christos 
    708      1.1      matt   /* But anchor it after that.  */
    709      1.1      matt   * rx++ = '$';
    710      1.1      matt   * rx = '\0';
    711      1.1      matt 
    712      1.1      matt   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
    713      1.2  christos   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
    714      1.1      matt 
    715      1.1      matt   if (reg_err == 0)
    716      1.1      matt     return NULL;
    717      1.1      matt   else
    718      1.1      matt     {
    719      1.1      matt       static char msg[80];
    720      1.1      matt 
    721      1.1      matt       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
    722      1.1      matt       regfree ((regex_t *) CGEN_INSN_RX (insn));
    723      1.1      matt       free (CGEN_INSN_RX (insn));
    724      1.1      matt       (CGEN_INSN_RX (insn)) = NULL;
    725      1.1      matt       return msg;
    726      1.1      matt     }
    727      1.1      matt }
    728      1.1      matt 
    729      1.1      matt 
    730      1.1      matt /* Default insn parser.
    732      1.1      matt 
    733      1.1      matt    The syntax string is scanned and operands are parsed and stored in FIELDS.
    734      1.1      matt    Relocs are queued as we go via other callbacks.
    735      1.1      matt 
    736      1.1      matt    ??? Note that this is currently an all-or-nothing parser.  If we fail to
    737      1.1      matt    parse the instruction, we return 0 and the caller will start over from
    738      1.1      matt    the beginning.  Backtracking will be necessary in parsing subexpressions,
    739      1.1      matt    but that can be handled there.  Not handling backtracking here may get
    740      1.1      matt    expensive in the case of the m68k.  Deal with later.
    741      1.1      matt 
    742      1.1      matt    Returns NULL for success, an error message for failure.  */
    743      1.1      matt 
    744      1.1      matt static const char *
    745      1.1      matt parse_insn_normal (CGEN_CPU_DESC cd,
    746      1.1      matt 		   const CGEN_INSN *insn,
    747      1.1      matt 		   const char **strp,
    748      1.1      matt 		   CGEN_FIELDS *fields)
    749      1.1      matt {
    750      1.1      matt   /* ??? Runtime added insns not handled yet.  */
    751      1.1      matt   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
    752      1.1      matt   const char *str = *strp;
    753      1.1      matt   const char *errmsg;
    754      1.1      matt   const char *p;
    755      1.1      matt   const CGEN_SYNTAX_CHAR_TYPE * syn;
    756      1.1      matt #ifdef CGEN_MNEMONIC_OPERANDS
    757      1.1      matt   /* FIXME: wip */
    758      1.1      matt   int past_opcode_p;
    759      1.1      matt #endif
    760      1.1      matt 
    761      1.1      matt   /* For now we assume the mnemonic is first (there are no leading operands).
    762      1.1      matt      We can parse it without needing to set up operand parsing.
    763      1.1      matt      GAS's input scrubber will ensure mnemonics are lowercase, but we may
    764      1.1      matt      not be called from GAS.  */
    765      1.1      matt   p = CGEN_INSN_MNEMONIC (insn);
    766      1.1      matt   while (*p && TOLOWER (*p) == TOLOWER (*str))
    767      1.1      matt     ++p, ++str;
    768      1.1      matt 
    769      1.1      matt   if (* p)
    770      1.1      matt     return _("unrecognized instruction");
    771      1.1      matt 
    772      1.1      matt #ifndef CGEN_MNEMONIC_OPERANDS
    773      1.1      matt   if (* str && ! ISSPACE (* str))
    774      1.1      matt     return _("unrecognized instruction");
    775      1.1      matt #endif
    776      1.1      matt 
    777      1.1      matt   CGEN_INIT_PARSE (cd);
    778      1.1      matt   cgen_init_parse_operand (cd);
    779      1.1      matt #ifdef CGEN_MNEMONIC_OPERANDS
    780      1.1      matt   past_opcode_p = 0;
    781      1.1      matt #endif
    782      1.1      matt 
    783      1.1      matt   /* We don't check for (*str != '\0') here because we want to parse
    784      1.1      matt      any trailing fake arguments in the syntax string.  */
    785      1.1      matt   syn = CGEN_SYNTAX_STRING (syntax);
    786      1.1      matt 
    787      1.1      matt   /* Mnemonics come first for now, ensure valid string.  */
    788      1.1      matt   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
    789      1.1      matt     abort ();
    790      1.1      matt 
    791      1.1      matt   ++syn;
    792      1.1      matt 
    793      1.1      matt   while (* syn != 0)
    794      1.1      matt     {
    795      1.1      matt       /* Non operand chars must match exactly.  */
    796      1.1      matt       if (CGEN_SYNTAX_CHAR_P (* syn))
    797      1.1      matt 	{
    798      1.1      matt 	  /* FIXME: While we allow for non-GAS callers above, we assume the
    799      1.1      matt 	     first char after the mnemonic part is a space.  */
    800      1.1      matt 	  /* FIXME: We also take inappropriate advantage of the fact that
    801      1.1      matt 	     GAS's input scrubber will remove extraneous blanks.  */
    802      1.1      matt 	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
    803      1.1      matt 	    {
    804      1.1      matt #ifdef CGEN_MNEMONIC_OPERANDS
    805      1.1      matt 	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
    806      1.1      matt 		past_opcode_p = 1;
    807      1.1      matt #endif
    808      1.1      matt 	      ++ syn;
    809      1.1      matt 	      ++ str;
    810      1.1      matt 	    }
    811      1.1      matt 	  else if (*str)
    812      1.1      matt 	    {
    813      1.1      matt 	      /* Syntax char didn't match.  Can't be this insn.  */
    814      1.1      matt 	      static char msg [80];
    815      1.1      matt 
    816      1.1      matt 	      /* xgettext:c-format */
    817      1.1      matt 	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
    818      1.1      matt 		       CGEN_SYNTAX_CHAR(*syn), *str);
    819      1.1      matt 	      return msg;
    820      1.1      matt 	    }
    821      1.1      matt 	  else
    822      1.1      matt 	    {
    823      1.1      matt 	      /* Ran out of input.  */
    824      1.1      matt 	      static char msg [80];
    825      1.1      matt 
    826      1.1      matt 	      /* xgettext:c-format */
    827      1.1      matt 	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
    828      1.1      matt 		       CGEN_SYNTAX_CHAR(*syn));
    829      1.1      matt 	      return msg;
    830      1.1      matt 	    }
    831      1.1      matt 	  continue;
    832      1.1      matt 	}
    833      1.1      matt 
    834      1.1      matt #ifdef CGEN_MNEMONIC_OPERANDS
    835      1.1      matt       (void) past_opcode_p;
    836      1.1      matt #endif
    837      1.1      matt       /* We have an operand of some sort.  */
    838      1.1      matt       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
    839      1.1      matt       if (errmsg)
    840      1.1      matt 	return errmsg;
    841      1.1      matt 
    842      1.1      matt       /* Done with this operand, continue with next one.  */
    843      1.1      matt       ++ syn;
    844      1.1      matt     }
    845      1.1      matt 
    846      1.1      matt   /* If we're at the end of the syntax string, we're done.  */
    847      1.1      matt   if (* syn == 0)
    848      1.1      matt     {
    849      1.1      matt       /* FIXME: For the moment we assume a valid `str' can only contain
    850      1.1      matt 	 blanks now.  IE: We needn't try again with a longer version of
    851      1.1      matt 	 the insn and it is assumed that longer versions of insns appear
    852      1.1      matt 	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
    853      1.1      matt       while (ISSPACE (* str))
    854      1.1      matt 	++ str;
    855      1.1      matt 
    856      1.1      matt       if (* str != '\0')
    857      1.1      matt 	return _("junk at end of line"); /* FIXME: would like to include `str' */
    858      1.1      matt 
    859      1.1      matt       return NULL;
    860      1.1      matt     }
    861      1.1      matt 
    862      1.1      matt   /* We couldn't parse it.  */
    863      1.1      matt   return _("unrecognized instruction");
    864      1.1      matt }
    865      1.1      matt 
    866      1.1      matt /* Main entry point.
    868      1.1      matt    This routine is called for each instruction to be assembled.
    869      1.1      matt    STR points to the insn to be assembled.
    870      1.1      matt    We assume all necessary tables have been initialized.
    871      1.1      matt    The assembled instruction, less any fixups, is stored in BUF.
    872      1.1      matt    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
    873      1.1      matt    still needs to be converted to target byte order, otherwise BUF is an array
    874      1.1      matt    of bytes in target byte order.
    875      1.1      matt    The result is a pointer to the insn's entry in the opcode table,
    876      1.1      matt    or NULL if an error occured (an error message will have already been
    877      1.1      matt    printed).
    878      1.1      matt 
    879      1.1      matt    Note that when processing (non-alias) macro-insns,
    880      1.1      matt    this function recurses.
    881      1.1      matt 
    882      1.1      matt    ??? It's possible to make this cpu-independent.
    883      1.1      matt    One would have to deal with a few minor things.
    884      1.1      matt    At this point in time doing so would be more of a curiosity than useful
    885      1.1      matt    [for example this file isn't _that_ big], but keeping the possibility in
    886      1.1      matt    mind helps keep the design clean.  */
    887      1.1      matt 
    888      1.1      matt const CGEN_INSN *
    889      1.1      matt or1k_cgen_assemble_insn (CGEN_CPU_DESC cd,
    890      1.1      matt 			   const char *str,
    891      1.1      matt 			   CGEN_FIELDS *fields,
    892      1.1      matt 			   CGEN_INSN_BYTES_PTR buf,
    893      1.1      matt 			   char **errmsg)
    894      1.1      matt {
    895      1.1      matt   const char *start;
    896      1.1      matt   CGEN_INSN_LIST *ilist;
    897      1.1      matt   const char *parse_errmsg = NULL;
    898      1.1      matt   const char *insert_errmsg = NULL;
    899      1.1      matt   int recognized_mnemonic = 0;
    900      1.1      matt 
    901      1.1      matt   /* Skip leading white space.  */
    902      1.1      matt   while (ISSPACE (* str))
    903      1.1      matt     ++ str;
    904      1.1      matt 
    905      1.1      matt   /* The instructions are stored in hashed lists.
    906      1.1      matt      Get the first in the list.  */
    907      1.1      matt   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
    908      1.1      matt 
    909      1.1      matt   /* Keep looking until we find a match.  */
    910      1.1      matt   start = str;
    911      1.1      matt   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
    912      1.2  christos     {
    913      1.1      matt       const CGEN_INSN *insn = ilist->insn;
    914      1.1      matt       recognized_mnemonic = 1;
    915      1.1      matt 
    916      1.1      matt #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    917      1.1      matt       /* Not usually needed as unsupported opcodes
    918      1.1      matt 	 shouldn't be in the hash lists.  */
    919      1.1      matt       /* Is this insn supported by the selected cpu?  */
    920      1.1      matt       if (! or1k_cgen_insn_supported (cd, insn))
    921      1.1      matt 	continue;
    922      1.1      matt #endif
    923      1.1      matt       /* If the RELAXED attribute is set, this is an insn that shouldn't be
    924      1.1      matt 	 chosen immediately.  Instead, it is used during assembler/linker
    925      1.1      matt 	 relaxation if possible.  */
    926      1.1      matt       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
    927      1.1      matt 	continue;
    928      1.1      matt 
    929      1.1      matt       str = start;
    930      1.1      matt 
    931      1.1      matt       /* Skip this insn if str doesn't look right lexically.  */
    932      1.1      matt       if (CGEN_INSN_RX (insn) != NULL &&
    933      1.1      matt 	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
    934      1.1      matt 	continue;
    935      1.1      matt 
    936      1.1      matt       /* Allow parse/insert handlers to obtain length of insn.  */
    937      1.1      matt       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
    938      1.1      matt 
    939      1.1      matt       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
    940      1.1      matt       if (parse_errmsg != NULL)
    941      1.1      matt 	continue;
    942      1.1      matt 
    943      1.1      matt       /* ??? 0 is passed for `pc'.  */
    944      1.1      matt       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
    945      1.1      matt 						 (bfd_vma) 0);
    946      1.1      matt       if (insert_errmsg != NULL)
    947      1.1      matt         continue;
    948      1.1      matt 
    949      1.1      matt       /* It is up to the caller to actually output the insn and any
    950      1.1      matt          queued relocs.  */
    951      1.1      matt       return insn;
    952      1.1      matt     }
    953      1.1      matt 
    954      1.1      matt   {
    955      1.1      matt     static char errbuf[150];
    956      1.1      matt     const char *tmp_errmsg;
    957      1.1      matt #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
    958      1.1      matt #define be_verbose 1
    959      1.1      matt #else
    960      1.1      matt #define be_verbose 0
    961      1.1      matt #endif
    962      1.1      matt 
    963      1.1      matt     if (be_verbose)
    964      1.1      matt       {
    965      1.1      matt 	/* If requesting verbose error messages, use insert_errmsg.
    966      1.1      matt 	   Failing that, use parse_errmsg.  */
    967      1.1      matt 	tmp_errmsg = (insert_errmsg ? insert_errmsg :
    968      1.1      matt 		      parse_errmsg ? parse_errmsg :
    969      1.1      matt 		      recognized_mnemonic ?
    970      1.1      matt 		      _("unrecognized form of instruction") :
    971      1.1      matt 		      _("unrecognized instruction"));
    972      1.2  christos 
    973      1.1      matt 	if (strlen (start) > 50)
    974      1.1      matt 	  /* xgettext:c-format */
    975      1.1      matt 	  sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
    976      1.1      matt 	else
    977      1.1      matt 	  /* xgettext:c-format */
    978      1.1      matt 	  sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
    979      1.1      matt       }
    980      1.1      matt     else
    981      1.2  christos       {
    982      1.1      matt 	if (strlen (start) > 50)
    983      1.1      matt 	  /* xgettext:c-format */
    984      1.1      matt 	  sprintf (errbuf, _("bad instruction `%.50s...'"), start);
    985      1.2  christos 	else
    986      1.1      matt 	  /* xgettext:c-format */
    987      1.1      matt 	  sprintf (errbuf, _("bad instruction `%.50s'"), start);
    988      1.1      matt       }
    989      1.1      matt 
    990                        *errmsg = errbuf;
    991                        return NULL;
    992                      }
    993                    }
    994