[AArch64][gas] Update MTE system register encodings
[external/binutils.git] / cpu / or1k.opc
1 /* OpenRISC 1000 opcode support.  -*- C -*-
2    Copyright 2000-2014 Free Software Foundation, Inc.
3
4    Originally ontributed for OR32 by Red Hat Inc;
5
6    This file is part of the GNU Binutils.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, see <http://www.gnu.org/licenses/>. */
20
21 /* This file is an addendum to or1k.cpu.  Heavy use of C code isn't
22    appropriate in .cpu files, so it resides here.  This especially applies
23    to assembly/disassembly where parsing/printing can be quite involved.
24    Such things aren't really part of the specification of the cpu, per se,
25    so .cpu files provide the general framework and .opc files handle the
26    nitty-gritty details as necessary.
27
28    Each section is delimited with start and end markers.
29
30    <arch>-opc.h additions use: "-- opc.h"
31    <arch>-opc.c additions use: "-- opc.c"
32    <arch>-asm.c additions use: "-- asm.c"
33    <arch>-dis.c additions use: "-- dis.c"
34    <arch>-ibd.h additions use: "-- ibd.h"  */
35
36 /* -- opc.h */
37
38 #undef  CGEN_DIS_HASH_SIZE
39 #define CGEN_DIS_HASH_SIZE 256
40 #undef  CGEN_DIS_HASH
41 #define CGEN_DIS_HASH(buffer, value) (((unsigned char *) (buffer))[0] >> 2)
42
43 /* Check applicability of instructions against machines.  */
44 #define CGEN_VALIDATE_INSN_SUPPORTED
45
46 extern int or1k_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
47
48 /* -- */
49
50 /* -- opc.c */
51
52 /* Special check to ensure that instruction exists for given machine.  */
53
54 int
55 or1k_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
56 {
57   int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
58
59   /* No mach attribute?  Assume it's supported for all machs.  */
60   if (machs == 0)
61     return 1;
62
63   return ((machs & cd->machs) != 0);
64 }
65
66 /* -- */
67
68 /* -- asm.c */
69
70 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
71 static const char * INVALID_STORE_RELOC = N_("relocation invalid for store");
72 static const char * INVALID_RELOC_TYPE = N_("internal relocation type invalid");
73
74 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
75
76 static const char *
77 parse_disp26 (CGEN_CPU_DESC cd,
78               const char ** strp,
79               int opindex,
80               int opinfo ATTRIBUTE_UNUSED,
81               enum cgen_parse_operand_result * resultp,
82               bfd_vma * valuep)
83 {
84   const char *str = *strp;
85   const char *errmsg = NULL;
86   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
87
88   if (strncasecmp (str, "plta(", 5) == 0)
89     {
90       *strp = str + 5;
91       reloc = BFD_RELOC_OR1K_PLTA26;
92     }
93   else if (strncasecmp (str, "plt(", 4) == 0)
94     {
95       *strp = str + 4;
96       reloc = BFD_RELOC_OR1K_PLT26;
97     }
98
99   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
100
101   if (reloc != BFD_RELOC_OR1K_REL_26)
102     {
103       if (**strp != ')')
104         errmsg = MISSING_CLOSING_PARENTHESIS;
105       else
106         ++*strp;
107     }
108
109   return errmsg;
110 }
111
112 static const char *
113 parse_disp21 (CGEN_CPU_DESC cd,
114               const char ** strp,
115               int opindex,
116               int opinfo ATTRIBUTE_UNUSED,
117               enum cgen_parse_operand_result * resultp,
118               bfd_vma * valuep)
119 {
120   const char *str = *strp;
121   const char *errmsg = NULL;
122   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
123
124   if (strncasecmp (str, "got(", 4) == 0)
125     {
126       *strp = str + 4;
127       reloc = BFD_RELOC_OR1K_GOT_PG21;
128     }
129   else if (strncasecmp (str, "tlsgd(", 6) == 0)
130     {
131       *strp = str + 6;
132       reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
133     }
134   else if (strncasecmp (str, "tlsldm(", 7) == 0)
135     {
136       *strp = str + 7;
137       reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
138     }
139   else if (strncasecmp (str, "gottp(", 6) == 0)
140     {
141       *strp = str + 6;
142       reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
143     }
144
145   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
146
147   if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
148     {
149       if (**strp != ')')
150         errmsg = MISSING_CLOSING_PARENTHESIS;
151       else
152         ++*strp;
153     }
154
155   return errmsg;
156 }
157
158 enum or1k_rclass
159 {
160   RCLASS_DIRECT   = 0,
161   RCLASS_GOT      = 1,
162   RCLASS_GOTPC    = 2,
163   RCLASS_GOTOFF   = 3,
164   RCLASS_TLSGD    = 4,
165   RCLASS_TLSLDM   = 5,
166   RCLASS_DTPOFF   = 6,
167   RCLASS_GOTTPOFF = 7,
168   RCLASS_TPOFF    = 8,
169 };
170
171 enum or1k_rtype
172 {
173   RTYPE_LO = 0,
174   RTYPE_SLO = 1,
175   RTYPE_PO = 2,
176   RTYPE_SPO = 3,
177   RTYPE_HI = 4,
178   RTYPE_AHI = 5,
179 };
180
181 #define RCLASS_SHIFT 3
182 #define RTYPE_MASK   7
183
184 static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
185   { BFD_RELOC_LO16,
186     BFD_RELOC_OR1K_SLO16,
187     BFD_RELOC_OR1K_LO13,
188     BFD_RELOC_OR1K_SLO13,
189     BFD_RELOC_HI16,
190     BFD_RELOC_HI16_S, },
191   { BFD_RELOC_OR1K_GOT16,
192     BFD_RELOC_UNUSED,
193     BFD_RELOC_OR1K_GOT_LO13,
194     BFD_RELOC_UNUSED,
195     BFD_RELOC_UNUSED,
196     BFD_RELOC_UNUSED },
197   { BFD_RELOC_OR1K_GOTPC_LO16,
198     BFD_RELOC_UNUSED,
199     BFD_RELOC_UNUSED,
200     BFD_RELOC_UNUSED,
201     BFD_RELOC_OR1K_GOTPC_HI16,
202     BFD_RELOC_UNUSED },
203   { BFD_RELOC_LO16_GOTOFF,
204     BFD_RELOC_OR1K_GOTOFF_SLO16,
205     BFD_RELOC_UNUSED,
206     BFD_RELOC_UNUSED,
207     BFD_RELOC_HI16_GOTOFF,
208     BFD_RELOC_HI16_S_GOTOFF },
209   { BFD_RELOC_OR1K_TLS_GD_LO16,
210     BFD_RELOC_UNUSED,
211     BFD_RELOC_OR1K_TLS_GD_LO13,
212     BFD_RELOC_UNUSED,
213     BFD_RELOC_OR1K_TLS_GD_HI16,
214     BFD_RELOC_UNUSED },
215   { BFD_RELOC_OR1K_TLS_LDM_LO16,
216     BFD_RELOC_UNUSED,
217     BFD_RELOC_OR1K_TLS_LDM_LO13,
218     BFD_RELOC_UNUSED,
219     BFD_RELOC_OR1K_TLS_LDM_HI16,
220     BFD_RELOC_UNUSED },
221   { BFD_RELOC_OR1K_TLS_LDO_LO16,
222     BFD_RELOC_UNUSED,
223     BFD_RELOC_UNUSED,
224     BFD_RELOC_UNUSED,
225     BFD_RELOC_OR1K_TLS_LDO_HI16,
226     BFD_RELOC_UNUSED },
227   { BFD_RELOC_OR1K_TLS_IE_LO16,
228     BFD_RELOC_UNUSED,
229     BFD_RELOC_OR1K_TLS_IE_LO13,
230     BFD_RELOC_UNUSED,
231     BFD_RELOC_OR1K_TLS_IE_HI16,
232     BFD_RELOC_OR1K_TLS_IE_AHI16 },
233   { BFD_RELOC_OR1K_TLS_LE_LO16,
234     BFD_RELOC_OR1K_TLS_LE_SLO16,
235     BFD_RELOC_UNUSED,
236     BFD_RELOC_UNUSED,
237     BFD_RELOC_OR1K_TLS_LE_HI16,
238     BFD_RELOC_OR1K_TLS_LE_AHI16 },
239 };
240
241 static int
242 parse_reloc (const char **strp)
243 {
244     const char *str = *strp;
245     enum or1k_rclass cls = RCLASS_DIRECT;
246     enum or1k_rtype typ;
247
248     if (strncasecmp (str, "got(", 4) == 0)
249       {
250         *strp = str + 4;
251         return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
252       }
253     if (strncasecmp (str, "gotpo(", 6) == 0)
254       {
255         *strp = str + 6;
256         return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
257       }
258     if (strncasecmp (str, "gottppo(", 8) == 0)
259       {
260         *strp = str + 8;
261         return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
262       }
263
264     if (strncasecmp (str, "gotpc", 5) == 0)
265       {
266         str += 5;
267         cls = RCLASS_GOTPC;
268       }
269     else if (strncasecmp (str, "gotoff", 6) == 0)
270       {
271         str += 6;
272         cls = RCLASS_GOTOFF;
273       }
274     else if (strncasecmp (str, "tlsgd", 5) == 0)
275       {
276         str += 5;
277         cls = RCLASS_TLSGD;
278       }
279     else if (strncasecmp (str, "tlsldm", 6) == 0)
280       {
281         str += 6;
282         cls = RCLASS_TLSLDM;
283       }
284     else if (strncasecmp (str, "dtpoff", 6) == 0)
285       {
286         str += 6;
287         cls = RCLASS_DTPOFF;
288       }
289     else if (strncasecmp (str, "gottpoff", 8) == 0)
290       {
291         str += 8;
292         cls = RCLASS_GOTTPOFF;
293       }
294     else if (strncasecmp (str, "tpoff", 5) == 0)
295       {
296         str += 5;
297         cls = RCLASS_TPOFF;
298       }
299
300     if (strncasecmp (str, "hi(", 3) == 0)
301       {
302         str += 3;
303         typ = RTYPE_HI;
304       }
305     else if (strncasecmp (str, "lo(", 3) == 0)
306       {
307         str += 3;
308         typ = RTYPE_LO;
309       }
310     else if (strncasecmp (str, "ha(", 3) == 0)
311       {
312         str += 3;
313         typ = RTYPE_AHI;
314       }
315     else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
316       {
317         str += 3;
318         typ = RTYPE_PO;
319       }
320     else
321       return -1;
322
323     *strp = str;
324     return (cls << RCLASS_SHIFT) | typ;
325 }
326
327 static const char *
328 parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
329              long *valuep, int splitp)
330 {
331   const char *errmsg;
332   enum cgen_parse_operand_result result_type;
333   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
334   enum or1k_rtype reloc_type;
335   int reloc_code;
336   bfd_vma ret;
337
338   if (**strp == '#')
339     ++*strp;
340
341   reloc_code = parse_reloc (strp);
342   reloc_type = reloc_code & RTYPE_MASK;
343   if (reloc_code >= 0)
344     {
345       enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
346       if (splitp)
347         {
348           if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
349               && reloc_class != RCLASS_GOT)
350             /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
351             reloc_type |= 1;
352           else
353             return INVALID_STORE_RELOC;
354         }
355       reloc = or1k_imm16_relocs[reloc_class][reloc_type];
356     }
357
358   if (reloc != BFD_RELOC_UNUSED)
359     {
360       bfd_vma value;
361
362       errmsg = cgen_parse_address (cd, strp, opindex, reloc,
363                                    &result_type, &value);
364       if (**strp != ')')
365         errmsg = MISSING_CLOSING_PARENTHESIS;
366       ++*strp;
367
368       ret = value;
369
370       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
371         switch (reloc_type)
372           {
373           case RTYPE_AHI:
374             ret += 0x8000;
375             /* FALLTHRU */
376           case RTYPE_HI:
377             ret >>= 16;
378             /* FALLTHRU */
379           case RTYPE_LO:
380           case RTYPE_SLO:
381             ret &= 0xffff;
382             ret = (ret ^ 0x8000) - 0x8000;
383             break;
384           case RTYPE_PO:
385           case RTYPE_SPO:
386             ret &= 0x1fff;
387             break;
388           default:
389             errmsg = INVALID_RELOC_TYPE;
390           }
391     }
392   else
393     {
394       long value;
395       errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
396       ret = value;
397     }
398
399   if (errmsg == NULL)
400     *valuep = ret;
401
402   return errmsg;
403 }
404
405 static const char *
406 parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
407 {
408   return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
409 }
410
411 static const char *
412 parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
413                     long *valuep)
414 {
415   return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
416 }
417
418 static const char *
419 parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
420               unsigned long *valuep)
421 {
422   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
423   if (errmsg == NULL)
424     *valuep &= 0xffff;
425   return errmsg;
426 }
427
428 static const char *
429 parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
430                     unsigned long *valuep)
431 {
432   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
433   if (errmsg == NULL)
434     *valuep &= 0xffff;
435   return errmsg;
436 }
437
438 /* Parse register pairs with syntax rA,rB to a flag + rA value.  */
439
440 static const char *
441 parse_regpair (CGEN_CPU_DESC cd, const char **strp,
442                int opindex ATTRIBUTE_UNUSED, unsigned long *valuep)
443 {
444   long reg1_index;
445   long reg2_index;
446   const char *errmsg;
447
448   /* The first part should just be a register.  */
449   errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
450                                &reg1_index);
451
452   /* If that worked skip the comma separator.  */
453   if (errmsg == NULL)
454     {
455       if (**strp == ',')
456         ++*strp;
457       else
458         errmsg = "Unexpected character, expected ','";
459     }
460
461   /* If that worked the next part is just another register.  */
462   if (errmsg == NULL)
463     errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
464                                  &reg2_index);
465
466   /* Validate the register pair is valid and create the output value.  */
467   if (errmsg == NULL)
468     {
469       int regoffset = reg2_index - reg1_index;
470
471       if (regoffset == 1 || regoffset == 2)
472         {
473           unsigned short offsetmask;
474           unsigned short value;
475
476           offsetmask = ((regoffset == 2 ? 1 : 0) << 5);
477           value = offsetmask | reg1_index;
478
479           *valuep = value;
480         }
481       else
482         errmsg = "Invalid register pair, offset not 1 or 2.";
483     }
484
485   return errmsg;
486 }
487
488 /* -- */
489
490 /* -- dis.c */
491
492 static void
493 print_regpair (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
494                void * dis_info,
495                long value,
496                unsigned int attrs ATTRIBUTE_UNUSED,
497                bfd_vma pc ATTRIBUTE_UNUSED,
498                int length ATTRIBUTE_UNUSED)
499 {
500   disassemble_info *info = dis_info;
501   char reg1_index;
502   char reg2_index;
503
504   reg1_index = value & 0x1f;
505   reg2_index = reg1_index + ((value & (1 << 5)) ? 2 : 1);
506
507   (*info->fprintf_func) (info->stream, "r%d,r%d", reg1_index, reg2_index);
508 }
509
510 /* -- */
511
512 /* -- ibd.h */
513
514 /* -- */