Automatic date update in version.in
[binutils-gdb.git] / cpu / or1k.opc
blob5d20a1f33a709931962647b12b61751ed94c324d
1 /* OpenRISC 1000 opcode support.  -*- C -*-
2    Copyright 2000-2014 Free Software Foundation, Inc.
4    Originally ontributed for OR32 by Red Hat Inc;
6    This file is part of the GNU Binutils.
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.
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.
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/>. */
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.
28    Each section is delimited with start and end markers.
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"  */
36 /* -- opc.h */
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)
43 /* Check applicability of instructions against machines.  */
44 #define CGEN_VALIDATE_INSN_SUPPORTED
46 extern int or1k_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
48 /* -- */
50 /* -- opc.c */
52 /* Special check to ensure that instruction exists for given machine.  */
54 int
55 or1k_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
57   int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
59   /* No mach attribute?  Assume it's supported for all machs.  */
60   if (machs == 0)
61     return 1;
63   return ((machs & cd->machs) != 0);
66 /* -- */
68 /* -- asm.c */
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");
74 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
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)
84   const char *str = *strp;
85   const char *errmsg = NULL;
86   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
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     }
99   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
101   if (reloc != BFD_RELOC_OR1K_REL_26)
102     {
103       if (**strp != ')')
104         errmsg = MISSING_CLOSING_PARENTHESIS;
105       else
106         ++*strp;
107     }
109   return errmsg;
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)
120   const char *str = *strp;
121   const char *errmsg = NULL;
122   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
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     }
145   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
147   if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
148     {
149       if (**strp != ')')
150         errmsg = MISSING_CLOSING_PARENTHESIS;
151       else
152         ++*strp;
153     }
155   return errmsg;
158 enum or1k_rclass
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,
171 enum or1k_rtype
173   RTYPE_LO = 0,
174   RTYPE_SLO = 1,
175   RTYPE_PO = 2,
176   RTYPE_SPO = 3,
177   RTYPE_HI = 4,
178   RTYPE_AHI = 5,
181 #define RCLASS_SHIFT 3
182 #define RTYPE_MASK   7
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_OR1K_GOT_AHI16 },
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 },
241 static int
242 parse_reloc (const char **strp)
244     const char *str = *strp;
245     enum or1k_rclass cls = RCLASS_DIRECT;
246     enum or1k_rtype typ;
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       }
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     else if (strncasecmp (str, "got", 3) == 0)
300       {
301         str += 3;
302         cls = RCLASS_GOT;
303       }
305     if (strncasecmp (str, "hi(", 3) == 0)
306       {
307         str += 3;
308         typ = RTYPE_HI;
309       }
310     else if (strncasecmp (str, "lo(", 3) == 0)
311       {
312         str += 3;
313         typ = RTYPE_LO;
314       }
315     else if (strncasecmp (str, "ha(", 3) == 0)
316       {
317         str += 3;
318         typ = RTYPE_AHI;
319       }
320     else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
321       {
322         str += 3;
323         typ = RTYPE_PO;
324       }
325     else
326       return -1;
328     *strp = str;
329     return (cls << RCLASS_SHIFT) | typ;
332 static const char *
333 parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
334              long *valuep, int splitp)
336   const char *errmsg;
337   enum cgen_parse_operand_result result_type;
338   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
339   enum or1k_rtype reloc_type;
340   int reloc_code;
341   bfd_vma ret;
343   if (**strp == '#')
344     ++*strp;
346   reloc_code = parse_reloc (strp);
347   reloc_type = reloc_code & RTYPE_MASK;
348   if (reloc_code >= 0)
349     {
350       enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
351       if (splitp)
352         {
353           if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
354               && reloc_class != RCLASS_GOT)
355             /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
356             reloc_type |= 1;
357           else
358             return INVALID_STORE_RELOC;
359         }
360       reloc = or1k_imm16_relocs[reloc_class][reloc_type];
361     }
363   if (reloc != BFD_RELOC_UNUSED)
364     {
365       bfd_vma value;
367       errmsg = cgen_parse_address (cd, strp, opindex, reloc,
368                                    &result_type, &value);
369       if (**strp != ')')
370         errmsg = MISSING_CLOSING_PARENTHESIS;
371       ++*strp;
373       ret = value;
375       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
376         switch (reloc_type)
377           {
378           case RTYPE_AHI:
379             ret += 0x8000;
380             /* FALLTHRU */
381           case RTYPE_HI:
382             ret >>= 16;
383             /* FALLTHRU */
384           case RTYPE_LO:
385           case RTYPE_SLO:
386             ret &= 0xffff;
387             ret = (ret ^ 0x8000) - 0x8000;
388             break;
389           case RTYPE_PO:
390           case RTYPE_SPO:
391             ret &= 0x1fff;
392             break;
393           default:
394             errmsg = INVALID_RELOC_TYPE;
395           }
396     }
397   else
398     {
399       long value;
400       errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
401       ret = value;
402     }
404   if (errmsg == NULL)
405     *valuep = ret;
407   return errmsg;
410 static const char *
411 parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
413   return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
416 static const char *
417 parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
418                     long *valuep)
420   return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
423 static const char *
424 parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
425               unsigned long *valuep)
427   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
428   if (errmsg == NULL)
429     *valuep &= 0xffff;
430   return errmsg;
433 static const char *
434 parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
435                     unsigned long *valuep)
437   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
438   if (errmsg == NULL)
439     *valuep &= 0xffff;
440   return errmsg;
443 /* Parse register pairs with syntax rA,rB to a flag + rA value.  */
445 static const char *
446 parse_regpair (CGEN_CPU_DESC cd, const char **strp,
447                int opindex ATTRIBUTE_UNUSED, unsigned long *valuep)
449   long reg1_index;
450   long reg2_index;
451   const char *errmsg;
453   /* The first part should just be a register.  */
454   errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
455                                &reg1_index);
457   /* If that worked skip the comma separator.  */
458   if (errmsg == NULL)
459     {
460       if (**strp == ',')
461         ++*strp;
462       else
463         errmsg = "Unexpected character, expected ','";
464     }
466   /* If that worked the next part is just another register.  */
467   if (errmsg == NULL)
468     errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
469                                  &reg2_index);
471   /* Validate the register pair is valid and create the output value.  */
472   if (errmsg == NULL)
473     {
474       int regoffset = reg2_index - reg1_index;
476       if (regoffset == 1 || regoffset == 2)
477         {
478           unsigned short offsetmask;
479           unsigned short value;
481           offsetmask = ((regoffset == 2 ? 1 : 0) << 5);
482           value = offsetmask | reg1_index;
484           *valuep = value;
485         }
486       else
487         errmsg = "Invalid register pair, offset not 1 or 2.";
488     }
490   return errmsg;
493 /* -- */
495 /* -- dis.c */
497 static void
498 print_regpair (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
499                void * dis_info,
500                long value,
501                unsigned int attrs ATTRIBUTE_UNUSED,
502                bfd_vma pc ATTRIBUTE_UNUSED,
503                int length ATTRIBUTE_UNUSED)
505   disassemble_info *info = dis_info;
506   char reg1_index;
507   char reg2_index;
509   reg1_index = value & 0x1f;
510   reg2_index = reg1_index + ((value & (1 << 5)) ? 2 : 1);
512   (*info->fprintf_func) (info->stream, "r%d,r%d", reg1_index, reg2_index);
515 /* -- */
517 /* -- ibd.h */
519 /* -- */