]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - cpu/or1k.opc
cpu/or1k: Add support for orfp64a32 spec
[thirdparty/binutils-gdb.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 /* -- */