xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/or1k-asm.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1ede78133Schristos /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
275fd0b74Schristos /* Assembler interface for targets using CGEN. -*- C -*-
375fd0b74Schristos    CGEN: Cpu tools GENerator
475fd0b74Schristos 
575fd0b74Schristos    THIS FILE IS MACHINE GENERATED WITH CGEN.
675fd0b74Schristos    - the resultant file is machine generated, cgen-asm.in isn't
775fd0b74Schristos 
8*e992f068Schristos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
975fd0b74Schristos 
1075fd0b74Schristos    This file is part of libopcodes.
1175fd0b74Schristos 
1275fd0b74Schristos    This library is free software; you can redistribute it and/or modify
1375fd0b74Schristos    it under the terms of the GNU General Public License as published by
1475fd0b74Schristos    the Free Software Foundation; either version 3, or (at your option)
1575fd0b74Schristos    any later version.
1675fd0b74Schristos 
1775fd0b74Schristos    It is distributed in the hope that it will be useful, but WITHOUT
1875fd0b74Schristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1975fd0b74Schristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
2075fd0b74Schristos    License for more details.
2175fd0b74Schristos 
2275fd0b74Schristos    You should have received a copy of the GNU General Public License
2375fd0b74Schristos    along with this program; if not, write to the Free Software Foundation, Inc.,
2475fd0b74Schristos    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2575fd0b74Schristos 
2675fd0b74Schristos 
2775fd0b74Schristos /* ??? Eventually more and more of this stuff can go to cpu-independent files.
2875fd0b74Schristos    Keep that in mind.  */
2975fd0b74Schristos 
3075fd0b74Schristos #include "sysdep.h"
3175fd0b74Schristos #include <stdio.h>
3275fd0b74Schristos #include "ansidecl.h"
3375fd0b74Schristos #include "bfd.h"
3475fd0b74Schristos #include "symcat.h"
3575fd0b74Schristos #include "or1k-desc.h"
3675fd0b74Schristos #include "or1k-opc.h"
3775fd0b74Schristos #include "opintl.h"
3875fd0b74Schristos #include "xregex.h"
3975fd0b74Schristos #include "libiberty.h"
4075fd0b74Schristos #include "safe-ctype.h"
4175fd0b74Schristos 
4275fd0b74Schristos #undef  min
4375fd0b74Schristos #define min(a,b) ((a) < (b) ? (a) : (b))
4475fd0b74Schristos #undef  max
4575fd0b74Schristos #define max(a,b) ((a) > (b) ? (a) : (b))
4675fd0b74Schristos 
4775fd0b74Schristos static const char * parse_insn_normal
4875fd0b74Schristos   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
4975fd0b74Schristos 
5075fd0b74Schristos /* -- assembler routines inserted here.  */
5175fd0b74Schristos 
5275fd0b74Schristos /* -- asm.c */
5375fd0b74Schristos 
5475fd0b74Schristos static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
55012573ebSchristos static const char * INVALID_STORE_RELOC = N_("relocation invalid for store");
56012573ebSchristos static const char * INVALID_RELOC_TYPE = N_("internal relocation type invalid");
5775fd0b74Schristos 
5875fd0b74Schristos #define CGEN_VERBOSE_ASSEMBLER_ERRORS
5975fd0b74Schristos 
6075fd0b74Schristos static const char *
parse_disp26(CGEN_CPU_DESC cd,const char ** strp,int opindex,int opinfo ATTRIBUTE_UNUSED,enum cgen_parse_operand_result * resultp,bfd_vma * valuep)6175fd0b74Schristos parse_disp26 (CGEN_CPU_DESC cd,
6275fd0b74Schristos 	      const char ** strp,
6375fd0b74Schristos 	      int opindex,
64012573ebSchristos 	      int opinfo ATTRIBUTE_UNUSED,
6575fd0b74Schristos 	      enum cgen_parse_operand_result * resultp,
6675fd0b74Schristos 	      bfd_vma * valuep)
6775fd0b74Schristos {
68012573ebSchristos   const char *str = *strp;
6975fd0b74Schristos   const char *errmsg = NULL;
70012573ebSchristos   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
7175fd0b74Schristos 
72012573ebSchristos   if (strncasecmp (str, "plta(", 5) == 0)
7375fd0b74Schristos     {
74012573ebSchristos       *strp = str + 5;
75012573ebSchristos       reloc = BFD_RELOC_OR1K_PLTA26;
7675fd0b74Schristos     }
77012573ebSchristos   else if (strncasecmp (str, "plt(", 4) == 0)
78012573ebSchristos     {
79012573ebSchristos       *strp = str + 4;
80012573ebSchristos       reloc = BFD_RELOC_OR1K_PLT26;
81012573ebSchristos     }
82012573ebSchristos 
83012573ebSchristos   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
84012573ebSchristos 
85012573ebSchristos   if (reloc != BFD_RELOC_OR1K_REL_26)
86012573ebSchristos     {
87012573ebSchristos       if (**strp != ')')
88012573ebSchristos 	errmsg = MISSING_CLOSING_PARENTHESIS;
89012573ebSchristos       else
90012573ebSchristos 	++*strp;
91012573ebSchristos     }
92012573ebSchristos 
93012573ebSchristos   return errmsg;
9475fd0b74Schristos }
9575fd0b74Schristos 
9675fd0b74Schristos static const char *
parse_disp21(CGEN_CPU_DESC cd,const char ** strp,int opindex,int opinfo ATTRIBUTE_UNUSED,enum cgen_parse_operand_result * resultp,bfd_vma * valuep)97012573ebSchristos parse_disp21 (CGEN_CPU_DESC cd,
98012573ebSchristos 	      const char ** strp,
99012573ebSchristos 	      int opindex,
100012573ebSchristos 	      int opinfo ATTRIBUTE_UNUSED,
101012573ebSchristos 	      enum cgen_parse_operand_result * resultp,
102012573ebSchristos 	      bfd_vma * valuep)
103012573ebSchristos {
104012573ebSchristos   const char *str = *strp;
105012573ebSchristos   const char *errmsg = NULL;
106012573ebSchristos   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
107012573ebSchristos 
108012573ebSchristos   if (strncasecmp (str, "got(", 4) == 0)
109012573ebSchristos     {
110012573ebSchristos       *strp = str + 4;
111012573ebSchristos       reloc = BFD_RELOC_OR1K_GOT_PG21;
112012573ebSchristos     }
113012573ebSchristos   else if (strncasecmp (str, "tlsgd(", 6) == 0)
114012573ebSchristos     {
115012573ebSchristos       *strp = str + 6;
116012573ebSchristos       reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
117012573ebSchristos     }
118012573ebSchristos   else if (strncasecmp (str, "tlsldm(", 7) == 0)
119012573ebSchristos     {
120012573ebSchristos       *strp = str + 7;
121012573ebSchristos       reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
122012573ebSchristos     }
123012573ebSchristos   else if (strncasecmp (str, "gottp(", 6) == 0)
124012573ebSchristos     {
125012573ebSchristos       *strp = str + 6;
126012573ebSchristos       reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
127012573ebSchristos     }
128012573ebSchristos 
129012573ebSchristos   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
130012573ebSchristos 
131012573ebSchristos   if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
132012573ebSchristos     {
133012573ebSchristos       if (**strp != ')')
134012573ebSchristos 	errmsg = MISSING_CLOSING_PARENTHESIS;
135012573ebSchristos       else
136012573ebSchristos 	++*strp;
137012573ebSchristos     }
138012573ebSchristos 
139012573ebSchristos   return errmsg;
140012573ebSchristos }
141012573ebSchristos 
142012573ebSchristos enum or1k_rclass
143012573ebSchristos {
144012573ebSchristos   RCLASS_DIRECT   = 0,
145012573ebSchristos   RCLASS_GOT      = 1,
146012573ebSchristos   RCLASS_GOTPC    = 2,
147012573ebSchristos   RCLASS_GOTOFF   = 3,
148012573ebSchristos   RCLASS_TLSGD    = 4,
149012573ebSchristos   RCLASS_TLSLDM   = 5,
150012573ebSchristos   RCLASS_DTPOFF   = 6,
151012573ebSchristos   RCLASS_GOTTPOFF = 7,
152012573ebSchristos   RCLASS_TPOFF    = 8,
153012573ebSchristos };
154012573ebSchristos 
155012573ebSchristos enum or1k_rtype
156012573ebSchristos {
157012573ebSchristos   RTYPE_LO = 0,
158012573ebSchristos   RTYPE_SLO = 1,
159012573ebSchristos   RTYPE_PO = 2,
160012573ebSchristos   RTYPE_SPO = 3,
161012573ebSchristos   RTYPE_HI = 4,
162012573ebSchristos   RTYPE_AHI = 5,
163012573ebSchristos };
164012573ebSchristos 
165012573ebSchristos #define RCLASS_SHIFT 3
166012573ebSchristos #define RTYPE_MASK   7
167012573ebSchristos 
168012573ebSchristos static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
169012573ebSchristos   { BFD_RELOC_LO16,
170012573ebSchristos     BFD_RELOC_OR1K_SLO16,
171012573ebSchristos     BFD_RELOC_OR1K_LO13,
172012573ebSchristos     BFD_RELOC_OR1K_SLO13,
173012573ebSchristos     BFD_RELOC_HI16,
174012573ebSchristos     BFD_RELOC_HI16_S, },
175012573ebSchristos   { BFD_RELOC_OR1K_GOT16,
176012573ebSchristos     BFD_RELOC_UNUSED,
177012573ebSchristos     BFD_RELOC_OR1K_GOT_LO13,
178012573ebSchristos     BFD_RELOC_UNUSED,
179012573ebSchristos     BFD_RELOC_UNUSED,
180*e992f068Schristos     BFD_RELOC_OR1K_GOT_AHI16 },
181012573ebSchristos   { BFD_RELOC_OR1K_GOTPC_LO16,
182012573ebSchristos     BFD_RELOC_UNUSED,
183012573ebSchristos     BFD_RELOC_UNUSED,
184012573ebSchristos     BFD_RELOC_UNUSED,
185012573ebSchristos     BFD_RELOC_OR1K_GOTPC_HI16,
186012573ebSchristos     BFD_RELOC_UNUSED },
187012573ebSchristos   { BFD_RELOC_LO16_GOTOFF,
188012573ebSchristos     BFD_RELOC_OR1K_GOTOFF_SLO16,
189012573ebSchristos     BFD_RELOC_UNUSED,
190012573ebSchristos     BFD_RELOC_UNUSED,
191012573ebSchristos     BFD_RELOC_HI16_GOTOFF,
192012573ebSchristos     BFD_RELOC_HI16_S_GOTOFF },
193012573ebSchristos   { BFD_RELOC_OR1K_TLS_GD_LO16,
194012573ebSchristos     BFD_RELOC_UNUSED,
195012573ebSchristos     BFD_RELOC_OR1K_TLS_GD_LO13,
196012573ebSchristos     BFD_RELOC_UNUSED,
197012573ebSchristos     BFD_RELOC_OR1K_TLS_GD_HI16,
198012573ebSchristos     BFD_RELOC_UNUSED },
199012573ebSchristos   { BFD_RELOC_OR1K_TLS_LDM_LO16,
200012573ebSchristos     BFD_RELOC_UNUSED,
201012573ebSchristos     BFD_RELOC_OR1K_TLS_LDM_LO13,
202012573ebSchristos     BFD_RELOC_UNUSED,
203012573ebSchristos     BFD_RELOC_OR1K_TLS_LDM_HI16,
204012573ebSchristos     BFD_RELOC_UNUSED },
205012573ebSchristos   { BFD_RELOC_OR1K_TLS_LDO_LO16,
206012573ebSchristos     BFD_RELOC_UNUSED,
207012573ebSchristos     BFD_RELOC_UNUSED,
208012573ebSchristos     BFD_RELOC_UNUSED,
209012573ebSchristos     BFD_RELOC_OR1K_TLS_LDO_HI16,
210012573ebSchristos     BFD_RELOC_UNUSED },
211012573ebSchristos   { BFD_RELOC_OR1K_TLS_IE_LO16,
212012573ebSchristos     BFD_RELOC_UNUSED,
213012573ebSchristos     BFD_RELOC_OR1K_TLS_IE_LO13,
214012573ebSchristos     BFD_RELOC_UNUSED,
215012573ebSchristos     BFD_RELOC_OR1K_TLS_IE_HI16,
216012573ebSchristos     BFD_RELOC_OR1K_TLS_IE_AHI16 },
217012573ebSchristos   { BFD_RELOC_OR1K_TLS_LE_LO16,
218012573ebSchristos     BFD_RELOC_OR1K_TLS_LE_SLO16,
219012573ebSchristos     BFD_RELOC_UNUSED,
220012573ebSchristos     BFD_RELOC_UNUSED,
221012573ebSchristos     BFD_RELOC_OR1K_TLS_LE_HI16,
222012573ebSchristos     BFD_RELOC_OR1K_TLS_LE_AHI16 },
223012573ebSchristos };
224012573ebSchristos 
225012573ebSchristos static int
parse_reloc(const char ** strp)226012573ebSchristos parse_reloc (const char **strp)
227012573ebSchristos {
228012573ebSchristos     const char *str = *strp;
229012573ebSchristos     enum or1k_rclass cls = RCLASS_DIRECT;
230012573ebSchristos     enum or1k_rtype typ;
231012573ebSchristos 
232012573ebSchristos     if (strncasecmp (str, "got(", 4) == 0)
233012573ebSchristos       {
234012573ebSchristos 	*strp = str + 4;
235012573ebSchristos 	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
236012573ebSchristos       }
237012573ebSchristos     if (strncasecmp (str, "gotpo(", 6) == 0)
238012573ebSchristos       {
239012573ebSchristos 	*strp = str + 6;
240012573ebSchristos 	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
241012573ebSchristos       }
242012573ebSchristos     if (strncasecmp (str, "gottppo(", 8) == 0)
243012573ebSchristos       {
244012573ebSchristos 	*strp = str + 8;
245012573ebSchristos 	return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
246012573ebSchristos       }
247012573ebSchristos 
248012573ebSchristos     if (strncasecmp (str, "gotpc", 5) == 0)
249012573ebSchristos       {
250012573ebSchristos 	str += 5;
251012573ebSchristos 	cls = RCLASS_GOTPC;
252012573ebSchristos       }
253012573ebSchristos     else if (strncasecmp (str, "gotoff", 6) == 0)
254012573ebSchristos       {
255012573ebSchristos 	str += 6;
256012573ebSchristos 	cls = RCLASS_GOTOFF;
257012573ebSchristos       }
258012573ebSchristos     else if (strncasecmp (str, "tlsgd", 5) == 0)
259012573ebSchristos       {
260012573ebSchristos 	str += 5;
261012573ebSchristos 	cls = RCLASS_TLSGD;
262012573ebSchristos       }
263012573ebSchristos     else if (strncasecmp (str, "tlsldm", 6) == 0)
264012573ebSchristos       {
265012573ebSchristos 	str += 6;
266012573ebSchristos 	cls = RCLASS_TLSLDM;
267012573ebSchristos       }
268012573ebSchristos     else if (strncasecmp (str, "dtpoff", 6) == 0)
269012573ebSchristos       {
270012573ebSchristos 	str += 6;
271012573ebSchristos 	cls = RCLASS_DTPOFF;
272012573ebSchristos       }
273012573ebSchristos     else if (strncasecmp (str, "gottpoff", 8) == 0)
274012573ebSchristos       {
275012573ebSchristos 	str += 8;
276012573ebSchristos 	cls = RCLASS_GOTTPOFF;
277012573ebSchristos       }
278012573ebSchristos     else if (strncasecmp (str, "tpoff", 5) == 0)
279012573ebSchristos       {
280012573ebSchristos 	str += 5;
281012573ebSchristos 	cls = RCLASS_TPOFF;
282012573ebSchristos       }
283*e992f068Schristos     else if (strncasecmp (str, "got", 3) == 0)
284*e992f068Schristos       {
285*e992f068Schristos 	str += 3;
286*e992f068Schristos 	cls = RCLASS_GOT;
287*e992f068Schristos       }
288012573ebSchristos 
289012573ebSchristos     if (strncasecmp (str, "hi(", 3) == 0)
290012573ebSchristos       {
291012573ebSchristos 	str += 3;
292012573ebSchristos 	typ = RTYPE_HI;
293012573ebSchristos       }
294012573ebSchristos     else if (strncasecmp (str, "lo(", 3) == 0)
295012573ebSchristos       {
296012573ebSchristos 	str += 3;
297012573ebSchristos 	typ = RTYPE_LO;
298012573ebSchristos       }
299012573ebSchristos     else if (strncasecmp (str, "ha(", 3) == 0)
300012573ebSchristos       {
301012573ebSchristos 	str += 3;
302012573ebSchristos 	typ = RTYPE_AHI;
303012573ebSchristos       }
304012573ebSchristos     else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
305012573ebSchristos       {
306012573ebSchristos 	str += 3;
307012573ebSchristos 	typ = RTYPE_PO;
308012573ebSchristos       }
309012573ebSchristos     else
310012573ebSchristos       return -1;
311012573ebSchristos 
312012573ebSchristos     *strp = str;
313012573ebSchristos     return (cls << RCLASS_SHIFT) | typ;
314012573ebSchristos }
315012573ebSchristos 
316012573ebSchristos static const char *
parse_imm16(CGEN_CPU_DESC cd,const char ** strp,int opindex,long * valuep,int splitp)317012573ebSchristos parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
318012573ebSchristos 	     long *valuep, int splitp)
31975fd0b74Schristos {
32075fd0b74Schristos   const char *errmsg;
32175fd0b74Schristos   enum cgen_parse_operand_result result_type;
322012573ebSchristos   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
323012573ebSchristos   enum or1k_rtype reloc_type;
324012573ebSchristos   int reloc_code;
325012573ebSchristos   bfd_vma ret;
32675fd0b74Schristos 
32775fd0b74Schristos   if (**strp == '#')
32875fd0b74Schristos     ++*strp;
32975fd0b74Schristos 
330012573ebSchristos   reloc_code = parse_reloc (strp);
331012573ebSchristos   reloc_type = reloc_code & RTYPE_MASK;
332012573ebSchristos   if (reloc_code >= 0)
333012573ebSchristos     {
334012573ebSchristos       enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
335012573ebSchristos       if (splitp)
336012573ebSchristos 	{
337012573ebSchristos 	  if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
338012573ebSchristos 	      && reloc_class != RCLASS_GOT)
339012573ebSchristos 	    /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
340012573ebSchristos 	    reloc_type |= 1;
341012573ebSchristos 	  else
342012573ebSchristos 	    return INVALID_STORE_RELOC;
343012573ebSchristos 	}
344012573ebSchristos       reloc = or1k_imm16_relocs[reloc_class][reloc_type];
345012573ebSchristos     }
346012573ebSchristos 
347012573ebSchristos   if (reloc != BFD_RELOC_UNUSED)
34875fd0b74Schristos     {
34975fd0b74Schristos       bfd_vma value;
35075fd0b74Schristos 
351012573ebSchristos       errmsg = cgen_parse_address (cd, strp, opindex, reloc,
35275fd0b74Schristos 				   &result_type, &value);
35375fd0b74Schristos       if (**strp != ')')
35475fd0b74Schristos 	errmsg = MISSING_CLOSING_PARENTHESIS;
35575fd0b74Schristos       ++*strp;
35675fd0b74Schristos 
35775fd0b74Schristos       ret = value;
35875fd0b74Schristos 
359012573ebSchristos       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
360012573ebSchristos 	switch (reloc_type)
36175fd0b74Schristos 	  {
362012573ebSchristos 	  case RTYPE_AHI:
363012573ebSchristos 	    ret += 0x8000;
364012573ebSchristos 	    /* FALLTHRU */
365012573ebSchristos 	  case RTYPE_HI:
36675fd0b74Schristos 	    ret >>= 16;
367012573ebSchristos 	    /* FALLTHRU */
368012573ebSchristos 	  case RTYPE_LO:
369012573ebSchristos 	  case RTYPE_SLO:
37075fd0b74Schristos 	    ret &= 0xffff;
37175fd0b74Schristos 	    ret = (ret ^ 0x8000) - 0x8000;
372012573ebSchristos 	    break;
373012573ebSchristos 	  case RTYPE_PO:
374012573ebSchristos 	  case RTYPE_SPO:
375012573ebSchristos 	    ret &= 0x1fff;
376012573ebSchristos 	    break;
377012573ebSchristos 	  default:
378012573ebSchristos 	    errmsg = INVALID_RELOC_TYPE;
37975fd0b74Schristos 	  }
38075fd0b74Schristos     }
38175fd0b74Schristos   else
38275fd0b74Schristos     {
38375fd0b74Schristos       long value;
38475fd0b74Schristos       errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
38575fd0b74Schristos       ret = value;
38675fd0b74Schristos     }
38775fd0b74Schristos 
38875fd0b74Schristos   if (errmsg == NULL)
38975fd0b74Schristos     *valuep = ret;
39075fd0b74Schristos 
39175fd0b74Schristos   return errmsg;
39275fd0b74Schristos }
39375fd0b74Schristos 
39475fd0b74Schristos static const char *
parse_simm16(CGEN_CPU_DESC cd,const char ** strp,int opindex,long * valuep)395012573ebSchristos parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
39675fd0b74Schristos {
397012573ebSchristos   return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
398012573ebSchristos }
39975fd0b74Schristos 
400012573ebSchristos static const char *
parse_simm16_split(CGEN_CPU_DESC cd,const char ** strp,int opindex,long * valuep)401012573ebSchristos parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
402012573ebSchristos 		    long *valuep)
403012573ebSchristos {
404012573ebSchristos   return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
405012573ebSchristos }
406012573ebSchristos 
407012573ebSchristos static const char *
parse_uimm16(CGEN_CPU_DESC cd,const char ** strp,int opindex,unsigned long * valuep)408012573ebSchristos parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
409012573ebSchristos 	      unsigned long *valuep)
410012573ebSchristos {
411012573ebSchristos   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
41275fd0b74Schristos   if (errmsg == NULL)
41375fd0b74Schristos     *valuep &= 0xffff;
41475fd0b74Schristos   return errmsg;
41575fd0b74Schristos }
41675fd0b74Schristos 
417012573ebSchristos static const char *
parse_uimm16_split(CGEN_CPU_DESC cd,const char ** strp,int opindex,unsigned long * valuep)418012573ebSchristos parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
419012573ebSchristos 		    unsigned long *valuep)
420012573ebSchristos {
421012573ebSchristos   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
422012573ebSchristos   if (errmsg == NULL)
423012573ebSchristos     *valuep &= 0xffff;
424012573ebSchristos   return errmsg;
425012573ebSchristos }
426012573ebSchristos 
427012573ebSchristos /* Parse register pairs with syntax rA,rB to a flag + rA value.  */
428012573ebSchristos 
429012573ebSchristos static const char *
parse_regpair(CGEN_CPU_DESC cd,const char ** strp,int opindex ATTRIBUTE_UNUSED,unsigned long * valuep)430012573ebSchristos parse_regpair (CGEN_CPU_DESC cd, const char **strp,
431012573ebSchristos 	       int opindex ATTRIBUTE_UNUSED, unsigned long *valuep)
432012573ebSchristos {
433012573ebSchristos   long reg1_index;
434012573ebSchristos   long reg2_index;
435012573ebSchristos   const char *errmsg;
436012573ebSchristos 
437012573ebSchristos   /* The first part should just be a register.  */
438012573ebSchristos   errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
439012573ebSchristos 			       &reg1_index);
440012573ebSchristos 
441012573ebSchristos   /* If that worked skip the comma separator.  */
442012573ebSchristos   if (errmsg == NULL)
443012573ebSchristos     {
444012573ebSchristos       if (**strp == ',')
445012573ebSchristos 	++*strp;
446012573ebSchristos       else
447012573ebSchristos 	errmsg = "Unexpected character, expected ','";
448012573ebSchristos     }
449012573ebSchristos 
450012573ebSchristos   /* If that worked the next part is just another register.  */
451012573ebSchristos   if (errmsg == NULL)
452012573ebSchristos     errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
453012573ebSchristos 				 &reg2_index);
454012573ebSchristos 
455012573ebSchristos   /* Validate the register pair is valid and create the output value.  */
456012573ebSchristos   if (errmsg == NULL)
457012573ebSchristos     {
458012573ebSchristos       int regoffset = reg2_index - reg1_index;
459012573ebSchristos 
460012573ebSchristos       if (regoffset == 1 || regoffset == 2)
461012573ebSchristos 	{
462012573ebSchristos 	  unsigned short offsetmask;
463012573ebSchristos 	  unsigned short value;
464012573ebSchristos 
465012573ebSchristos 	  offsetmask = ((regoffset == 2 ? 1 : 0) << 5);
466012573ebSchristos 	  value = offsetmask | reg1_index;
467012573ebSchristos 
468012573ebSchristos 	  *valuep = value;
469012573ebSchristos 	}
470012573ebSchristos       else
471012573ebSchristos 	errmsg = "Invalid register pair, offset not 1 or 2.";
472012573ebSchristos     }
473012573ebSchristos 
474012573ebSchristos   return errmsg;
475012573ebSchristos }
476012573ebSchristos 
47775fd0b74Schristos /* -- */
47875fd0b74Schristos 
47975fd0b74Schristos const char * or1k_cgen_parse_operand
48075fd0b74Schristos   (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
48175fd0b74Schristos 
48275fd0b74Schristos /* Main entry point for operand parsing.
48375fd0b74Schristos 
48475fd0b74Schristos    This function is basically just a big switch statement.  Earlier versions
48575fd0b74Schristos    used tables to look up the function to use, but
48675fd0b74Schristos    - if the table contains both assembler and disassembler functions then
48775fd0b74Schristos      the disassembler contains much of the assembler and vice-versa,
48875fd0b74Schristos    - there's a lot of inlining possibilities as things grow,
48975fd0b74Schristos    - using a switch statement avoids the function call overhead.
49075fd0b74Schristos 
49175fd0b74Schristos    This function could be moved into `parse_insn_normal', but keeping it
49275fd0b74Schristos    separate makes clear the interface between `parse_insn_normal' and each of
49375fd0b74Schristos    the handlers.  */
49475fd0b74Schristos 
49575fd0b74Schristos const char *
or1k_cgen_parse_operand(CGEN_CPU_DESC cd,int opindex,const char ** strp,CGEN_FIELDS * fields)49675fd0b74Schristos or1k_cgen_parse_operand (CGEN_CPU_DESC cd,
49775fd0b74Schristos 			   int opindex,
49875fd0b74Schristos 			   const char ** strp,
49975fd0b74Schristos 			   CGEN_FIELDS * fields)
50075fd0b74Schristos {
50175fd0b74Schristos   const char * errmsg = NULL;
50275fd0b74Schristos   /* Used by scalar operands that still need to be parsed.  */
50375fd0b74Schristos   long junk ATTRIBUTE_UNUSED;
50475fd0b74Schristos 
50575fd0b74Schristos   switch (opindex)
50675fd0b74Schristos     {
507012573ebSchristos     case OR1K_OPERAND_DISP21 :
508012573ebSchristos       {
509012573ebSchristos         bfd_vma value = 0;
510012573ebSchristos         errmsg = parse_disp21 (cd, strp, OR1K_OPERAND_DISP21, 0, NULL,  & value);
511012573ebSchristos         fields->f_disp21 = value;
512012573ebSchristos       }
513012573ebSchristos       break;
51475fd0b74Schristos     case OR1K_OPERAND_DISP26 :
51575fd0b74Schristos       {
51675fd0b74Schristos         bfd_vma value = 0;
51775fd0b74Schristos         errmsg = parse_disp26 (cd, strp, OR1K_OPERAND_DISP26, 0, NULL,  & value);
51875fd0b74Schristos         fields->f_disp26 = value;
51975fd0b74Schristos       }
52075fd0b74Schristos       break;
52175fd0b74Schristos     case OR1K_OPERAND_RA :
52275fd0b74Schristos       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r2);
52375fd0b74Schristos       break;
524012573ebSchristos     case OR1K_OPERAND_RAD32F :
525012573ebSchristos       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RAD32F, (unsigned long *) (& fields->f_rad32));
526012573ebSchristos       break;
527012573ebSchristos     case OR1K_OPERAND_RADI :
528012573ebSchristos       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RADI, (unsigned long *) (& fields->f_rad32));
52975fd0b74Schristos       break;
53075fd0b74Schristos     case OR1K_OPERAND_RASF :
53175fd0b74Schristos       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r2);
53275fd0b74Schristos       break;
53375fd0b74Schristos     case OR1K_OPERAND_RB :
53475fd0b74Schristos       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r3);
53575fd0b74Schristos       break;
536012573ebSchristos     case OR1K_OPERAND_RBD32F :
537012573ebSchristos       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RBD32F, (unsigned long *) (& fields->f_rbd32));
538012573ebSchristos       break;
539012573ebSchristos     case OR1K_OPERAND_RBDI :
540012573ebSchristos       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RBDI, (unsigned long *) (& fields->f_rbd32));
54175fd0b74Schristos       break;
54275fd0b74Schristos     case OR1K_OPERAND_RBSF :
54375fd0b74Schristos       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r3);
54475fd0b74Schristos       break;
54575fd0b74Schristos     case OR1K_OPERAND_RD :
54675fd0b74Schristos       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r1);
54775fd0b74Schristos       break;
548012573ebSchristos     case OR1K_OPERAND_RDD32F :
549012573ebSchristos       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RDD32F, (unsigned long *) (& fields->f_rdd32));
550012573ebSchristos       break;
551012573ebSchristos     case OR1K_OPERAND_RDDI :
552012573ebSchristos       errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RDDI, (unsigned long *) (& fields->f_rdd32));
553012573ebSchristos       break;
55475fd0b74Schristos     case OR1K_OPERAND_RDSF :
55575fd0b74Schristos       errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r1);
55675fd0b74Schristos       break;
55775fd0b74Schristos     case OR1K_OPERAND_SIMM16 :
55875fd0b74Schristos       errmsg = parse_simm16 (cd, strp, OR1K_OPERAND_SIMM16, (long *) (& fields->f_simm16));
55975fd0b74Schristos       break;
56075fd0b74Schristos     case OR1K_OPERAND_SIMM16_SPLIT :
561012573ebSchristos       errmsg = parse_simm16_split (cd, strp, OR1K_OPERAND_SIMM16_SPLIT, (long *) (& fields->f_simm16_split));
56275fd0b74Schristos       break;
56375fd0b74Schristos     case OR1K_OPERAND_UIMM16 :
56475fd0b74Schristos       errmsg = parse_uimm16 (cd, strp, OR1K_OPERAND_UIMM16, (unsigned long *) (& fields->f_uimm16));
56575fd0b74Schristos       break;
56675fd0b74Schristos     case OR1K_OPERAND_UIMM16_SPLIT :
567012573ebSchristos       errmsg = parse_uimm16_split (cd, strp, OR1K_OPERAND_UIMM16_SPLIT, (unsigned long *) (& fields->f_uimm16_split));
56875fd0b74Schristos       break;
56975fd0b74Schristos     case OR1K_OPERAND_UIMM6 :
57075fd0b74Schristos       errmsg = cgen_parse_unsigned_integer (cd, strp, OR1K_OPERAND_UIMM6, (unsigned long *) (& fields->f_uimm6));
57175fd0b74Schristos       break;
57275fd0b74Schristos 
57375fd0b74Schristos     default :
57475fd0b74Schristos       /* xgettext:c-format */
575ede78133Schristos       opcodes_error_handler
576ede78133Schristos 	(_("internal error: unrecognized field %d while parsing"),
577ede78133Schristos 	 opindex);
57875fd0b74Schristos       abort ();
57975fd0b74Schristos   }
58075fd0b74Schristos 
58175fd0b74Schristos   return errmsg;
58275fd0b74Schristos }
58375fd0b74Schristos 
58475fd0b74Schristos cgen_parse_fn * const or1k_cgen_parse_handlers[] =
58575fd0b74Schristos {
58675fd0b74Schristos   parse_insn_normal,
58775fd0b74Schristos };
58875fd0b74Schristos 
58975fd0b74Schristos void
or1k_cgen_init_asm(CGEN_CPU_DESC cd)59075fd0b74Schristos or1k_cgen_init_asm (CGEN_CPU_DESC cd)
59175fd0b74Schristos {
59275fd0b74Schristos   or1k_cgen_init_opcode_table (cd);
59375fd0b74Schristos   or1k_cgen_init_ibld_table (cd);
59475fd0b74Schristos   cd->parse_handlers = & or1k_cgen_parse_handlers[0];
59575fd0b74Schristos   cd->parse_operand = or1k_cgen_parse_operand;
59675fd0b74Schristos #ifdef CGEN_ASM_INIT_HOOK
59775fd0b74Schristos CGEN_ASM_INIT_HOOK
59875fd0b74Schristos #endif
59975fd0b74Schristos }
60075fd0b74Schristos 
60175fd0b74Schristos 
60275fd0b74Schristos 
60375fd0b74Schristos /* Regex construction routine.
60475fd0b74Schristos 
60575fd0b74Schristos    This translates an opcode syntax string into a regex string,
60675fd0b74Schristos    by replacing any non-character syntax element (such as an
60775fd0b74Schristos    opcode) with the pattern '.*'
60875fd0b74Schristos 
60975fd0b74Schristos    It then compiles the regex and stores it in the opcode, for
61075fd0b74Schristos    later use by or1k_cgen_assemble_insn
61175fd0b74Schristos 
61275fd0b74Schristos    Returns NULL for success, an error message for failure.  */
61375fd0b74Schristos 
61475fd0b74Schristos char *
or1k_cgen_build_insn_regex(CGEN_INSN * insn)61575fd0b74Schristos or1k_cgen_build_insn_regex (CGEN_INSN *insn)
61675fd0b74Schristos {
61775fd0b74Schristos   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
61875fd0b74Schristos   const char *mnem = CGEN_INSN_MNEMONIC (insn);
61975fd0b74Schristos   char rxbuf[CGEN_MAX_RX_ELEMENTS];
62075fd0b74Schristos   char *rx = rxbuf;
62175fd0b74Schristos   const CGEN_SYNTAX_CHAR_TYPE *syn;
62275fd0b74Schristos   int reg_err;
62375fd0b74Schristos 
62475fd0b74Schristos   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
62575fd0b74Schristos 
62675fd0b74Schristos   /* Mnemonics come first in the syntax string.  */
62775fd0b74Schristos   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
62875fd0b74Schristos     return _("missing mnemonic in syntax string");
62975fd0b74Schristos   ++syn;
63075fd0b74Schristos 
63175fd0b74Schristos   /* Generate a case sensitive regular expression that emulates case
63275fd0b74Schristos      insensitive matching in the "C" locale.  We cannot generate a case
63375fd0b74Schristos      insensitive regular expression because in Turkish locales, 'i' and 'I'
63475fd0b74Schristos      are not equal modulo case conversion.  */
63575fd0b74Schristos 
63675fd0b74Schristos   /* Copy the literal mnemonic out of the insn.  */
63775fd0b74Schristos   for (; *mnem; mnem++)
63875fd0b74Schristos     {
63975fd0b74Schristos       char c = *mnem;
64075fd0b74Schristos 
64175fd0b74Schristos       if (ISALPHA (c))
64275fd0b74Schristos 	{
64375fd0b74Schristos 	  *rx++ = '[';
64475fd0b74Schristos 	  *rx++ = TOLOWER (c);
64575fd0b74Schristos 	  *rx++ = TOUPPER (c);
64675fd0b74Schristos 	  *rx++ = ']';
64775fd0b74Schristos 	}
64875fd0b74Schristos       else
64975fd0b74Schristos 	*rx++ = c;
65075fd0b74Schristos     }
65175fd0b74Schristos 
65275fd0b74Schristos   /* Copy any remaining literals from the syntax string into the rx.  */
65375fd0b74Schristos   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
65475fd0b74Schristos     {
65575fd0b74Schristos       if (CGEN_SYNTAX_CHAR_P (* syn))
65675fd0b74Schristos 	{
65775fd0b74Schristos 	  char c = CGEN_SYNTAX_CHAR (* syn);
65875fd0b74Schristos 
65975fd0b74Schristos 	  switch (c)
66075fd0b74Schristos 	    {
66175fd0b74Schristos 	      /* Escape any regex metacharacters in the syntax.  */
66275fd0b74Schristos 	    case '.': case '[': case '\\':
66375fd0b74Schristos 	    case '*': case '^': case '$':
66475fd0b74Schristos 
66575fd0b74Schristos #ifdef CGEN_ESCAPE_EXTENDED_REGEX
66675fd0b74Schristos 	    case '?': case '{': case '}':
66775fd0b74Schristos 	    case '(': case ')': case '*':
66875fd0b74Schristos 	    case '|': case '+': case ']':
66975fd0b74Schristos #endif
67075fd0b74Schristos 	      *rx++ = '\\';
67175fd0b74Schristos 	      *rx++ = c;
67275fd0b74Schristos 	      break;
67375fd0b74Schristos 
67475fd0b74Schristos 	    default:
67575fd0b74Schristos 	      if (ISALPHA (c))
67675fd0b74Schristos 		{
67775fd0b74Schristos 		  *rx++ = '[';
67875fd0b74Schristos 		  *rx++ = TOLOWER (c);
67975fd0b74Schristos 		  *rx++ = TOUPPER (c);
68075fd0b74Schristos 		  *rx++ = ']';
68175fd0b74Schristos 		}
68275fd0b74Schristos 	      else
68375fd0b74Schristos 		*rx++ = c;
68475fd0b74Schristos 	      break;
68575fd0b74Schristos 	    }
68675fd0b74Schristos 	}
68775fd0b74Schristos       else
68875fd0b74Schristos 	{
68975fd0b74Schristos 	  /* Replace non-syntax fields with globs.  */
69075fd0b74Schristos 	  *rx++ = '.';
69175fd0b74Schristos 	  *rx++ = '*';
69275fd0b74Schristos 	}
69375fd0b74Schristos     }
69475fd0b74Schristos 
69575fd0b74Schristos   /* Trailing whitespace ok.  */
69675fd0b74Schristos   * rx++ = '[';
69775fd0b74Schristos   * rx++ = ' ';
69875fd0b74Schristos   * rx++ = '\t';
69975fd0b74Schristos   * rx++ = ']';
70075fd0b74Schristos   * rx++ = '*';
70175fd0b74Schristos 
70275fd0b74Schristos   /* But anchor it after that.  */
70375fd0b74Schristos   * rx++ = '$';
70475fd0b74Schristos   * rx = '\0';
70575fd0b74Schristos 
70675fd0b74Schristos   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
70775fd0b74Schristos   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
70875fd0b74Schristos 
70975fd0b74Schristos   if (reg_err == 0)
71075fd0b74Schristos     return NULL;
71175fd0b74Schristos   else
71275fd0b74Schristos     {
71375fd0b74Schristos       static char msg[80];
71475fd0b74Schristos 
71575fd0b74Schristos       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
71675fd0b74Schristos       regfree ((regex_t *) CGEN_INSN_RX (insn));
71775fd0b74Schristos       free (CGEN_INSN_RX (insn));
71875fd0b74Schristos       (CGEN_INSN_RX (insn)) = NULL;
71975fd0b74Schristos       return msg;
72075fd0b74Schristos     }
72175fd0b74Schristos }
72275fd0b74Schristos 
72375fd0b74Schristos 
72475fd0b74Schristos /* Default insn parser.
72575fd0b74Schristos 
72675fd0b74Schristos    The syntax string is scanned and operands are parsed and stored in FIELDS.
72775fd0b74Schristos    Relocs are queued as we go via other callbacks.
72875fd0b74Schristos 
72975fd0b74Schristos    ??? Note that this is currently an all-or-nothing parser.  If we fail to
73075fd0b74Schristos    parse the instruction, we return 0 and the caller will start over from
73175fd0b74Schristos    the beginning.  Backtracking will be necessary in parsing subexpressions,
73275fd0b74Schristos    but that can be handled there.  Not handling backtracking here may get
73375fd0b74Schristos    expensive in the case of the m68k.  Deal with later.
73475fd0b74Schristos 
73575fd0b74Schristos    Returns NULL for success, an error message for failure.  */
73675fd0b74Schristos 
73775fd0b74Schristos static const char *
parse_insn_normal(CGEN_CPU_DESC cd,const CGEN_INSN * insn,const char ** strp,CGEN_FIELDS * fields)73875fd0b74Schristos parse_insn_normal (CGEN_CPU_DESC cd,
73975fd0b74Schristos 		   const CGEN_INSN *insn,
74075fd0b74Schristos 		   const char **strp,
74175fd0b74Schristos 		   CGEN_FIELDS *fields)
74275fd0b74Schristos {
74375fd0b74Schristos   /* ??? Runtime added insns not handled yet.  */
74475fd0b74Schristos   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
74575fd0b74Schristos   const char *str = *strp;
74675fd0b74Schristos   const char *errmsg;
74775fd0b74Schristos   const char *p;
74875fd0b74Schristos   const CGEN_SYNTAX_CHAR_TYPE * syn;
74975fd0b74Schristos #ifdef CGEN_MNEMONIC_OPERANDS
75075fd0b74Schristos   /* FIXME: wip */
75175fd0b74Schristos   int past_opcode_p;
75275fd0b74Schristos #endif
75375fd0b74Schristos 
75475fd0b74Schristos   /* For now we assume the mnemonic is first (there are no leading operands).
75575fd0b74Schristos      We can parse it without needing to set up operand parsing.
75675fd0b74Schristos      GAS's input scrubber will ensure mnemonics are lowercase, but we may
75775fd0b74Schristos      not be called from GAS.  */
75875fd0b74Schristos   p = CGEN_INSN_MNEMONIC (insn);
75975fd0b74Schristos   while (*p && TOLOWER (*p) == TOLOWER (*str))
76075fd0b74Schristos     ++p, ++str;
76175fd0b74Schristos 
76275fd0b74Schristos   if (* p)
76375fd0b74Schristos     return _("unrecognized instruction");
76475fd0b74Schristos 
76575fd0b74Schristos #ifndef CGEN_MNEMONIC_OPERANDS
76675fd0b74Schristos   if (* str && ! ISSPACE (* str))
76775fd0b74Schristos     return _("unrecognized instruction");
76875fd0b74Schristos #endif
76975fd0b74Schristos 
77075fd0b74Schristos   CGEN_INIT_PARSE (cd);
77175fd0b74Schristos   cgen_init_parse_operand (cd);
77275fd0b74Schristos #ifdef CGEN_MNEMONIC_OPERANDS
77375fd0b74Schristos   past_opcode_p = 0;
77475fd0b74Schristos #endif
77575fd0b74Schristos 
77675fd0b74Schristos   /* We don't check for (*str != '\0') here because we want to parse
77775fd0b74Schristos      any trailing fake arguments in the syntax string.  */
77875fd0b74Schristos   syn = CGEN_SYNTAX_STRING (syntax);
77975fd0b74Schristos 
78075fd0b74Schristos   /* Mnemonics come first for now, ensure valid string.  */
78175fd0b74Schristos   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
78275fd0b74Schristos     abort ();
78375fd0b74Schristos 
78475fd0b74Schristos   ++syn;
78575fd0b74Schristos 
78675fd0b74Schristos   while (* syn != 0)
78775fd0b74Schristos     {
78875fd0b74Schristos       /* Non operand chars must match exactly.  */
78975fd0b74Schristos       if (CGEN_SYNTAX_CHAR_P (* syn))
79075fd0b74Schristos 	{
79175fd0b74Schristos 	  /* FIXME: While we allow for non-GAS callers above, we assume the
79275fd0b74Schristos 	     first char after the mnemonic part is a space.  */
79375fd0b74Schristos 	  /* FIXME: We also take inappropriate advantage of the fact that
79475fd0b74Schristos 	     GAS's input scrubber will remove extraneous blanks.  */
79575fd0b74Schristos 	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
79675fd0b74Schristos 	    {
79775fd0b74Schristos #ifdef CGEN_MNEMONIC_OPERANDS
79875fd0b74Schristos 	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
79975fd0b74Schristos 		past_opcode_p = 1;
80075fd0b74Schristos #endif
80175fd0b74Schristos 	      ++ syn;
80275fd0b74Schristos 	      ++ str;
80375fd0b74Schristos 	    }
80475fd0b74Schristos 	  else if (*str)
80575fd0b74Schristos 	    {
80675fd0b74Schristos 	      /* Syntax char didn't match.  Can't be this insn.  */
80775fd0b74Schristos 	      static char msg [80];
80875fd0b74Schristos 
80975fd0b74Schristos 	      /* xgettext:c-format */
81075fd0b74Schristos 	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
81175fd0b74Schristos 		       CGEN_SYNTAX_CHAR(*syn), *str);
81275fd0b74Schristos 	      return msg;
81375fd0b74Schristos 	    }
81475fd0b74Schristos 	  else
81575fd0b74Schristos 	    {
81675fd0b74Schristos 	      /* Ran out of input.  */
81775fd0b74Schristos 	      static char msg [80];
81875fd0b74Schristos 
81975fd0b74Schristos 	      /* xgettext:c-format */
82075fd0b74Schristos 	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
82175fd0b74Schristos 		       CGEN_SYNTAX_CHAR(*syn));
82275fd0b74Schristos 	      return msg;
82375fd0b74Schristos 	    }
82475fd0b74Schristos 	  continue;
82575fd0b74Schristos 	}
82675fd0b74Schristos 
82775fd0b74Schristos #ifdef CGEN_MNEMONIC_OPERANDS
82875fd0b74Schristos       (void) past_opcode_p;
82975fd0b74Schristos #endif
83075fd0b74Schristos       /* We have an operand of some sort.  */
83175fd0b74Schristos       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
83275fd0b74Schristos       if (errmsg)
83375fd0b74Schristos 	return errmsg;
83475fd0b74Schristos 
83575fd0b74Schristos       /* Done with this operand, continue with next one.  */
83675fd0b74Schristos       ++ syn;
83775fd0b74Schristos     }
83875fd0b74Schristos 
83975fd0b74Schristos   /* If we're at the end of the syntax string, we're done.  */
84075fd0b74Schristos   if (* syn == 0)
84175fd0b74Schristos     {
84275fd0b74Schristos       /* FIXME: For the moment we assume a valid `str' can only contain
84375fd0b74Schristos 	 blanks now.  IE: We needn't try again with a longer version of
84475fd0b74Schristos 	 the insn and it is assumed that longer versions of insns appear
84575fd0b74Schristos 	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
84675fd0b74Schristos       while (ISSPACE (* str))
84775fd0b74Schristos 	++ str;
84875fd0b74Schristos 
84975fd0b74Schristos       if (* str != '\0')
85075fd0b74Schristos 	return _("junk at end of line"); /* FIXME: would like to include `str' */
85175fd0b74Schristos 
85275fd0b74Schristos       return NULL;
85375fd0b74Schristos     }
85475fd0b74Schristos 
85575fd0b74Schristos   /* We couldn't parse it.  */
85675fd0b74Schristos   return _("unrecognized instruction");
85775fd0b74Schristos }
85875fd0b74Schristos 
85975fd0b74Schristos /* Main entry point.
86075fd0b74Schristos    This routine is called for each instruction to be assembled.
86175fd0b74Schristos    STR points to the insn to be assembled.
86275fd0b74Schristos    We assume all necessary tables have been initialized.
86375fd0b74Schristos    The assembled instruction, less any fixups, is stored in BUF.
86475fd0b74Schristos    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
86575fd0b74Schristos    still needs to be converted to target byte order, otherwise BUF is an array
86675fd0b74Schristos    of bytes in target byte order.
86775fd0b74Schristos    The result is a pointer to the insn's entry in the opcode table,
86875fd0b74Schristos    or NULL if an error occured (an error message will have already been
86975fd0b74Schristos    printed).
87075fd0b74Schristos 
87175fd0b74Schristos    Note that when processing (non-alias) macro-insns,
87275fd0b74Schristos    this function recurses.
87375fd0b74Schristos 
87475fd0b74Schristos    ??? It's possible to make this cpu-independent.
87575fd0b74Schristos    One would have to deal with a few minor things.
87675fd0b74Schristos    At this point in time doing so would be more of a curiosity than useful
87775fd0b74Schristos    [for example this file isn't _that_ big], but keeping the possibility in
87875fd0b74Schristos    mind helps keep the design clean.  */
87975fd0b74Schristos 
88075fd0b74Schristos const CGEN_INSN *
or1k_cgen_assemble_insn(CGEN_CPU_DESC cd,const char * str,CGEN_FIELDS * fields,CGEN_INSN_BYTES_PTR buf,char ** errmsg)88175fd0b74Schristos or1k_cgen_assemble_insn (CGEN_CPU_DESC cd,
88275fd0b74Schristos 			   const char *str,
88375fd0b74Schristos 			   CGEN_FIELDS *fields,
88475fd0b74Schristos 			   CGEN_INSN_BYTES_PTR buf,
88575fd0b74Schristos 			   char **errmsg)
88675fd0b74Schristos {
88775fd0b74Schristos   const char *start;
88875fd0b74Schristos   CGEN_INSN_LIST *ilist;
88975fd0b74Schristos   const char *parse_errmsg = NULL;
89075fd0b74Schristos   const char *insert_errmsg = NULL;
89175fd0b74Schristos   int recognized_mnemonic = 0;
89275fd0b74Schristos 
89375fd0b74Schristos   /* Skip leading white space.  */
89475fd0b74Schristos   while (ISSPACE (* str))
89575fd0b74Schristos     ++ str;
89675fd0b74Schristos 
89775fd0b74Schristos   /* The instructions are stored in hashed lists.
89875fd0b74Schristos      Get the first in the list.  */
89975fd0b74Schristos   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
90075fd0b74Schristos 
90175fd0b74Schristos   /* Keep looking until we find a match.  */
90275fd0b74Schristos   start = str;
90375fd0b74Schristos   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
90475fd0b74Schristos     {
90575fd0b74Schristos       const CGEN_INSN *insn = ilist->insn;
90675fd0b74Schristos       recognized_mnemonic = 1;
90775fd0b74Schristos 
90875fd0b74Schristos #ifdef CGEN_VALIDATE_INSN_SUPPORTED
90975fd0b74Schristos       /* Not usually needed as unsupported opcodes
91075fd0b74Schristos 	 shouldn't be in the hash lists.  */
91175fd0b74Schristos       /* Is this insn supported by the selected cpu?  */
91275fd0b74Schristos       if (! or1k_cgen_insn_supported (cd, insn))
91375fd0b74Schristos 	continue;
91475fd0b74Schristos #endif
91575fd0b74Schristos       /* If the RELAXED attribute is set, this is an insn that shouldn't be
91675fd0b74Schristos 	 chosen immediately.  Instead, it is used during assembler/linker
91775fd0b74Schristos 	 relaxation if possible.  */
91875fd0b74Schristos       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
91975fd0b74Schristos 	continue;
92075fd0b74Schristos 
92175fd0b74Schristos       str = start;
92275fd0b74Schristos 
92375fd0b74Schristos       /* Skip this insn if str doesn't look right lexically.  */
92475fd0b74Schristos       if (CGEN_INSN_RX (insn) != NULL &&
92575fd0b74Schristos 	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
92675fd0b74Schristos 	continue;
92775fd0b74Schristos 
92875fd0b74Schristos       /* Allow parse/insert handlers to obtain length of insn.  */
92975fd0b74Schristos       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
93075fd0b74Schristos 
93175fd0b74Schristos       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
93275fd0b74Schristos       if (parse_errmsg != NULL)
93375fd0b74Schristos 	continue;
93475fd0b74Schristos 
93575fd0b74Schristos       /* ??? 0 is passed for `pc'.  */
93675fd0b74Schristos       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
93775fd0b74Schristos 						 (bfd_vma) 0);
93875fd0b74Schristos       if (insert_errmsg != NULL)
93975fd0b74Schristos         continue;
94075fd0b74Schristos 
94175fd0b74Schristos       /* It is up to the caller to actually output the insn and any
94275fd0b74Schristos          queued relocs.  */
94375fd0b74Schristos       return insn;
94475fd0b74Schristos     }
94575fd0b74Schristos 
94675fd0b74Schristos   {
94775fd0b74Schristos     static char errbuf[150];
94875fd0b74Schristos     const char *tmp_errmsg;
94975fd0b74Schristos #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
95075fd0b74Schristos #define be_verbose 1
95175fd0b74Schristos #else
95275fd0b74Schristos #define be_verbose 0
95375fd0b74Schristos #endif
95475fd0b74Schristos 
95575fd0b74Schristos     if (be_verbose)
95675fd0b74Schristos       {
95775fd0b74Schristos 	/* If requesting verbose error messages, use insert_errmsg.
95875fd0b74Schristos 	   Failing that, use parse_errmsg.  */
95975fd0b74Schristos 	tmp_errmsg = (insert_errmsg ? insert_errmsg :
96075fd0b74Schristos 		      parse_errmsg ? parse_errmsg :
96175fd0b74Schristos 		      recognized_mnemonic ?
96275fd0b74Schristos 		      _("unrecognized form of instruction") :
96375fd0b74Schristos 		      _("unrecognized instruction"));
96475fd0b74Schristos 
96575fd0b74Schristos 	if (strlen (start) > 50)
96675fd0b74Schristos 	  /* xgettext:c-format */
96775fd0b74Schristos 	  sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
96875fd0b74Schristos 	else
96975fd0b74Schristos 	  /* xgettext:c-format */
97075fd0b74Schristos 	  sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
97175fd0b74Schristos       }
97275fd0b74Schristos     else
97375fd0b74Schristos       {
97475fd0b74Schristos 	if (strlen (start) > 50)
97575fd0b74Schristos 	  /* xgettext:c-format */
97675fd0b74Schristos 	  sprintf (errbuf, _("bad instruction `%.50s...'"), start);
97775fd0b74Schristos 	else
97875fd0b74Schristos 	  /* xgettext:c-format */
97975fd0b74Schristos 	  sprintf (errbuf, _("bad instruction `%.50s'"), start);
98075fd0b74Schristos       }
98175fd0b74Schristos 
98275fd0b74Schristos     *errmsg = errbuf;
98375fd0b74Schristos     return NULL;
98475fd0b74Schristos   }
98575fd0b74Schristos }
986