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" */
38 #undef CGEN_DIS_HASH_SIZE
39 #define CGEN_DIS_HASH_SIZE 256
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 *);
52 /* Special check to ensure that instruction exists for given machine. */
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. */
63 return ((machs & cd->machs) != 0);
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
77 parse_disp26 (CGEN_CPU_DESC cd,
80 int opinfo ATTRIBUTE_UNUSED,
81 enum cgen_parse_operand_result * resultp,
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)
91 reloc = BFD_RELOC_OR1K_PLTA26;
93 else if (strncasecmp (str, "plt(", 4) == 0)
96 reloc = BFD_RELOC_OR1K_PLT26;
99 errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
101 if (reloc != BFD_RELOC_OR1K_REL_26)
104 errmsg = MISSING_CLOSING_PARENTHESIS;
113 parse_disp21 (CGEN_CPU_DESC cd,
116 int opinfo ATTRIBUTE_UNUSED,
117 enum cgen_parse_operand_result * resultp,
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)
127 reloc = BFD_RELOC_OR1K_GOT_PG21;
129 else if (strncasecmp (str, "tlsgd(", 6) == 0)
132 reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
134 else if (strncasecmp (str, "tlsldm(", 7) == 0)
137 reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
139 else if (strncasecmp (str, "gottp(", 6) == 0)
142 reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
145 errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
147 if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
150 errmsg = MISSING_CLOSING_PARENTHESIS;
181 #define RCLASS_SHIFT 3
184 static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
186 BFD_RELOC_OR1K_SLO16,
188 BFD_RELOC_OR1K_SLO13,
191 { BFD_RELOC_OR1K_GOT16,
193 BFD_RELOC_OR1K_GOT_LO13,
196 BFD_RELOC_OR1K_GOT_AHI16 },
197 { BFD_RELOC_OR1K_GOTPC_LO16,
201 BFD_RELOC_OR1K_GOTPC_HI16,
203 { BFD_RELOC_LO16_GOTOFF,
204 BFD_RELOC_OR1K_GOTOFF_SLO16,
207 BFD_RELOC_HI16_GOTOFF,
208 BFD_RELOC_HI16_S_GOTOFF },
209 { BFD_RELOC_OR1K_TLS_GD_LO16,
211 BFD_RELOC_OR1K_TLS_GD_LO13,
213 BFD_RELOC_OR1K_TLS_GD_HI16,
215 { BFD_RELOC_OR1K_TLS_LDM_LO16,
217 BFD_RELOC_OR1K_TLS_LDM_LO13,
219 BFD_RELOC_OR1K_TLS_LDM_HI16,
221 { BFD_RELOC_OR1K_TLS_LDO_LO16,
225 BFD_RELOC_OR1K_TLS_LDO_HI16,
227 { BFD_RELOC_OR1K_TLS_IE_LO16,
229 BFD_RELOC_OR1K_TLS_IE_LO13,
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,
237 BFD_RELOC_OR1K_TLS_LE_HI16,
238 BFD_RELOC_OR1K_TLS_LE_AHI16 },
242 parse_reloc (const char **strp)
244 const char *str = *strp;
245 enum or1k_rclass cls = RCLASS_DIRECT;
248 if (strncasecmp (str, "got(", 4) == 0)
251 return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
253 if (strncasecmp (str, "gotpo(", 6) == 0)
256 return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
258 if (strncasecmp (str, "gottppo(", 8) == 0)
261 return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
264 if (strncasecmp (str, "gotpc", 5) == 0)
269 else if (strncasecmp (str, "gotoff", 6) == 0)
274 else if (strncasecmp (str, "tlsgd", 5) == 0)
279 else if (strncasecmp (str, "tlsldm", 6) == 0)
284 else if (strncasecmp (str, "dtpoff", 6) == 0)
289 else if (strncasecmp (str, "gottpoff", 8) == 0)
292 cls = RCLASS_GOTTPOFF;
294 else if (strncasecmp (str, "tpoff", 5) == 0)
299 else if (strncasecmp (str, "got", 3) == 0)
305 if (strncasecmp (str, "hi(", 3) == 0)
310 else if (strncasecmp (str, "lo(", 3) == 0)
315 else if (strncasecmp (str, "ha(", 3) == 0)
320 else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
329 return (cls << RCLASS_SHIFT) | typ;
333 parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
334 long *valuep, int splitp)
337 enum cgen_parse_operand_result result_type;
338 bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
339 enum or1k_rtype reloc_type;
346 reloc_code = parse_reloc (strp);
347 reloc_type = reloc_code & RTYPE_MASK;
350 enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
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. */
358 return INVALID_STORE_RELOC;
360 reloc = or1k_imm16_relocs[reloc_class][reloc_type];
363 if (reloc != BFD_RELOC_UNUSED)
367 errmsg = cgen_parse_address (cd, strp, opindex, reloc,
368 &result_type, &value);
370 errmsg = MISSING_CLOSING_PARENTHESIS;
375 if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
387 ret = (ret ^ 0x8000) - 0x8000;
394 errmsg = INVALID_RELOC_TYPE;
400 errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
411 parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
413 return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
417 parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
420 return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
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);
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);
443 /* Parse register pairs with syntax rA,rB to a flag + rA value. */
446 parse_regpair (CGEN_CPU_DESC cd, const char **strp,
447 int opindex ATTRIBUTE_UNUSED, unsigned long *valuep)
453 /* The first part should just be a register. */
454 errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
457 /* If that worked skip the comma separator. */
463 errmsg = "Unexpected character, expected ','";
466 /* If that worked the next part is just another register. */
468 errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
471 /* Validate the register pair is valid and create the output value. */
474 int regoffset = reg2_index - reg1_index;
476 if (regoffset == 1 || regoffset == 2)
478 unsigned short offsetmask;
479 unsigned short value;
481 offsetmask = ((regoffset == 2 ? 1 : 0) << 5);
482 value = offsetmask | reg1_index;
487 errmsg = "Invalid register pair, offset not 1 or 2.";
498 print_regpair (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
501 unsigned int attrs ATTRIBUTE_UNUSED,
502 bfd_vma pc ATTRIBUTE_UNUSED,
503 int length ATTRIBUTE_UNUSED)
505 disassemble_info *info = dis_info;
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);