Commit | Line | Data |
---|---|---|
73589c9d CS |
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 | /* -- */ | |
44 | ||
45 | /* -- opc.c */ | |
46 | /* -- */ | |
47 | ||
48 | /* -- asm.c */ | |
49 | ||
50 | static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'"); | |
1c4f3780 RH |
51 | static const char * INVALID_STORE_RELOC = N_("relocation invalid for store"); |
52 | static const char * INVALID_RELOC_TYPE = N_("internal relocation type invalid"); | |
73589c9d CS |
53 | |
54 | #define CGEN_VERBOSE_ASSEMBLER_ERRORS | |
55 | ||
56 | static const char * | |
57 | parse_disp26 (CGEN_CPU_DESC cd, | |
c151b1c6 AM |
58 | const char ** strp, |
59 | int opindex, | |
c8e98e36 | 60 | int opinfo ATTRIBUTE_UNUSED, |
c151b1c6 AM |
61 | enum cgen_parse_operand_result * resultp, |
62 | bfd_vma * valuep) | |
73589c9d | 63 | { |
c8e98e36 | 64 | const char *str = *strp; |
73589c9d | 65 | const char *errmsg = NULL; |
c8e98e36 | 66 | bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26; |
73589c9d | 67 | |
c8e98e36 | 68 | if (strncasecmp (str, "plta(", 5) == 0) |
73589c9d | 69 | { |
c8e98e36 SH |
70 | *strp = str + 5; |
71 | reloc = BFD_RELOC_OR1K_PLTA26; | |
72 | } | |
73 | else if (strncasecmp (str, "plt(", 4) == 0) | |
74 | { | |
75 | *strp = str + 4; | |
76 | reloc = BFD_RELOC_OR1K_PLT26; | |
77 | } | |
73589c9d | 78 | |
c8e98e36 SH |
79 | errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep); |
80 | ||
81 | if (reloc != BFD_RELOC_OR1K_REL_26) | |
82 | { | |
73589c9d | 83 | if (**strp != ')') |
c8e98e36 SH |
84 | errmsg = MISSING_CLOSING_PARENTHESIS; |
85 | else | |
86 | ++*strp; | |
73589c9d | 87 | } |
c8e98e36 SH |
88 | |
89 | return errmsg; | |
90 | } | |
91 | ||
92 | static const char * | |
93 | parse_disp21 (CGEN_CPU_DESC cd, | |
94 | const char ** strp, | |
95 | int opindex, | |
96 | int opinfo ATTRIBUTE_UNUSED, | |
97 | enum cgen_parse_operand_result * resultp, | |
98 | bfd_vma * valuep) | |
99 | { | |
100 | const char *str = *strp; | |
101 | const char *errmsg = NULL; | |
102 | bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21; | |
103 | ||
104 | if (strncasecmp (str, "got(", 4) == 0) | |
105 | { | |
106 | *strp = str + 4; | |
107 | reloc = BFD_RELOC_OR1K_GOT_PG21; | |
108 | } | |
109 | else if (strncasecmp (str, "tlsgd(", 6) == 0) | |
110 | { | |
111 | *strp = str + 6; | |
112 | reloc = BFD_RELOC_OR1K_TLS_GD_PG21; | |
113 | } | |
114 | else if (strncasecmp (str, "tlsldm(", 7) == 0) | |
115 | { | |
116 | *strp = str + 7; | |
117 | reloc = BFD_RELOC_OR1K_TLS_LDM_PG21; | |
118 | } | |
119 | else if (strncasecmp (str, "gottp(", 6) == 0) | |
120 | { | |
121 | *strp = str + 6; | |
122 | reloc = BFD_RELOC_OR1K_TLS_IE_PG21; | |
123 | } | |
124 | ||
125 | errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep); | |
126 | ||
127 | if (reloc != BFD_RELOC_OR1K_PCREL_PG21) | |
128 | { | |
129 | if (**strp != ')') | |
130 | errmsg = MISSING_CLOSING_PARENTHESIS; | |
131 | else | |
132 | ++*strp; | |
133 | } | |
134 | ||
135 | return errmsg; | |
73589c9d CS |
136 | } |
137 | ||
c8e98e36 SH |
138 | enum or1k_rclass |
139 | { | |
140 | RCLASS_DIRECT = 0, | |
141 | RCLASS_GOT = 1, | |
142 | RCLASS_GOTPC = 2, | |
143 | RCLASS_GOTOFF = 3, | |
144 | RCLASS_TLSGD = 4, | |
145 | RCLASS_TLSLDM = 5, | |
146 | RCLASS_DTPOFF = 6, | |
147 | RCLASS_GOTTPOFF = 7, | |
148 | RCLASS_TPOFF = 8, | |
149 | }; | |
150 | ||
151 | enum or1k_rtype | |
1c4f3780 RH |
152 | { |
153 | RTYPE_LO = 0, | |
c8e98e36 SH |
154 | RTYPE_SLO = 1, |
155 | RTYPE_PO = 2, | |
156 | RTYPE_SPO = 3, | |
157 | RTYPE_HI = 4, | |
158 | RTYPE_AHI = 5, | |
1c4f3780 RH |
159 | }; |
160 | ||
c8e98e36 SH |
161 | #define RCLASS_SHIFT 3 |
162 | #define RTYPE_MASK 7 | |
163 | ||
164 | static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = { | |
1c4f3780 | 165 | { BFD_RELOC_LO16, |
c8e98e36 SH |
166 | BFD_RELOC_OR1K_SLO16, |
167 | BFD_RELOC_OR1K_LO13, | |
168 | BFD_RELOC_OR1K_SLO13, | |
1c4f3780 | 169 | BFD_RELOC_HI16, |
c8e98e36 | 170 | BFD_RELOC_HI16_S, }, |
1c4f3780 | 171 | { BFD_RELOC_OR1K_GOT16, |
c8e98e36 SH |
172 | BFD_RELOC_UNUSED, |
173 | BFD_RELOC_OR1K_GOT_LO13, | |
1c4f3780 RH |
174 | BFD_RELOC_UNUSED, |
175 | BFD_RELOC_UNUSED, | |
176 | BFD_RELOC_UNUSED }, | |
177 | { BFD_RELOC_OR1K_GOTPC_LO16, | |
1c4f3780 | 178 | BFD_RELOC_UNUSED, |
c8e98e36 SH |
179 | BFD_RELOC_UNUSED, |
180 | BFD_RELOC_UNUSED, | |
181 | BFD_RELOC_OR1K_GOTPC_HI16, | |
1c4f3780 RH |
182 | BFD_RELOC_UNUSED }, |
183 | { BFD_RELOC_LO16_GOTOFF, | |
c8e98e36 SH |
184 | BFD_RELOC_OR1K_GOTOFF_SLO16, |
185 | BFD_RELOC_UNUSED, | |
186 | BFD_RELOC_UNUSED, | |
1c4f3780 | 187 | BFD_RELOC_HI16_GOTOFF, |
c8e98e36 | 188 | BFD_RELOC_HI16_S_GOTOFF }, |
1c4f3780 | 189 | { BFD_RELOC_OR1K_TLS_GD_LO16, |
1c4f3780 | 190 | BFD_RELOC_UNUSED, |
c8e98e36 SH |
191 | BFD_RELOC_OR1K_TLS_GD_LO13, |
192 | BFD_RELOC_UNUSED, | |
193 | BFD_RELOC_OR1K_TLS_GD_HI16, | |
1c4f3780 RH |
194 | BFD_RELOC_UNUSED }, |
195 | { BFD_RELOC_OR1K_TLS_LDM_LO16, | |
1c4f3780 | 196 | BFD_RELOC_UNUSED, |
c8e98e36 SH |
197 | BFD_RELOC_OR1K_TLS_LDM_LO13, |
198 | BFD_RELOC_UNUSED, | |
199 | BFD_RELOC_OR1K_TLS_LDM_HI16, | |
1c4f3780 RH |
200 | BFD_RELOC_UNUSED }, |
201 | { BFD_RELOC_OR1K_TLS_LDO_LO16, | |
1c4f3780 | 202 | BFD_RELOC_UNUSED, |
c8e98e36 SH |
203 | BFD_RELOC_UNUSED, |
204 | BFD_RELOC_UNUSED, | |
205 | BFD_RELOC_OR1K_TLS_LDO_HI16, | |
1c4f3780 RH |
206 | BFD_RELOC_UNUSED }, |
207 | { BFD_RELOC_OR1K_TLS_IE_LO16, | |
c8e98e36 SH |
208 | BFD_RELOC_UNUSED, |
209 | BFD_RELOC_OR1K_TLS_IE_LO13, | |
210 | BFD_RELOC_UNUSED, | |
1c4f3780 | 211 | BFD_RELOC_OR1K_TLS_IE_HI16, |
c8e98e36 | 212 | BFD_RELOC_OR1K_TLS_IE_AHI16 }, |
1c4f3780 | 213 | { BFD_RELOC_OR1K_TLS_LE_LO16, |
c8e98e36 SH |
214 | BFD_RELOC_OR1K_TLS_LE_SLO16, |
215 | BFD_RELOC_UNUSED, | |
216 | BFD_RELOC_UNUSED, | |
1c4f3780 | 217 | BFD_RELOC_OR1K_TLS_LE_HI16, |
c8e98e36 | 218 | BFD_RELOC_OR1K_TLS_LE_AHI16 }, |
1c4f3780 RH |
219 | }; |
220 | ||
221 | static int | |
222 | parse_reloc (const char **strp) | |
223 | { | |
224 | const char *str = *strp; | |
c8e98e36 SH |
225 | enum or1k_rclass cls = RCLASS_DIRECT; |
226 | enum or1k_rtype typ; | |
1c4f3780 RH |
227 | |
228 | if (strncasecmp (str, "got(", 4) == 0) | |
229 | { | |
230 | *strp = str + 4; | |
c8e98e36 SH |
231 | return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO; |
232 | } | |
233 | if (strncasecmp (str, "gotpo(", 6) == 0) | |
234 | { | |
235 | *strp = str + 6; | |
236 | return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO; | |
237 | } | |
238 | if (strncasecmp (str, "gottppo(", 8) == 0) | |
239 | { | |
240 | *strp = str + 8; | |
241 | return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO; | |
1c4f3780 RH |
242 | } |
243 | ||
244 | if (strncasecmp (str, "gotpc", 5) == 0) | |
245 | { | |
246 | str += 5; | |
c8e98e36 | 247 | cls = RCLASS_GOTPC; |
1c4f3780 RH |
248 | } |
249 | else if (strncasecmp (str, "gotoff", 6) == 0) | |
250 | { | |
251 | str += 6; | |
c8e98e36 | 252 | cls = RCLASS_GOTOFF; |
1c4f3780 RH |
253 | } |
254 | else if (strncasecmp (str, "tlsgd", 5) == 0) | |
255 | { | |
256 | str += 5; | |
c8e98e36 | 257 | cls = RCLASS_TLSGD; |
1c4f3780 RH |
258 | } |
259 | else if (strncasecmp (str, "tlsldm", 6) == 0) | |
260 | { | |
261 | str += 6; | |
c8e98e36 | 262 | cls = RCLASS_TLSLDM; |
1c4f3780 RH |
263 | } |
264 | else if (strncasecmp (str, "dtpoff", 6) == 0) | |
265 | { | |
266 | str += 6; | |
c8e98e36 | 267 | cls = RCLASS_DTPOFF; |
1c4f3780 RH |
268 | } |
269 | else if (strncasecmp (str, "gottpoff", 8) == 0) | |
270 | { | |
271 | str += 8; | |
c8e98e36 | 272 | cls = RCLASS_GOTTPOFF; |
1c4f3780 RH |
273 | } |
274 | else if (strncasecmp (str, "tpoff", 5) == 0) | |
275 | { | |
276 | str += 5; | |
c8e98e36 | 277 | cls = RCLASS_TPOFF; |
1c4f3780 RH |
278 | } |
279 | ||
280 | if (strncasecmp (str, "hi(", 3) == 0) | |
281 | { | |
282 | str += 3; | |
c8e98e36 | 283 | typ = RTYPE_HI; |
1c4f3780 RH |
284 | } |
285 | else if (strncasecmp (str, "lo(", 3) == 0) | |
286 | { | |
287 | str += 3; | |
c8e98e36 | 288 | typ = RTYPE_LO; |
1c4f3780 RH |
289 | } |
290 | else if (strncasecmp (str, "ha(", 3) == 0) | |
291 | { | |
292 | str += 3; | |
c8e98e36 SH |
293 | typ = RTYPE_AHI; |
294 | } | |
295 | else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF) | |
296 | { | |
297 | str += 3; | |
298 | typ = RTYPE_PO; | |
1c4f3780 RH |
299 | } |
300 | else | |
301 | return -1; | |
302 | ||
303 | *strp = str; | |
c8e98e36 | 304 | return (cls << RCLASS_SHIFT) | typ; |
1c4f3780 RH |
305 | } |
306 | ||
73589c9d | 307 | static const char * |
1c4f3780 RH |
308 | parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, |
309 | long *valuep, int splitp) | |
73589c9d CS |
310 | { |
311 | const char *errmsg; | |
312 | enum cgen_parse_operand_result result_type; | |
1c4f3780 | 313 | bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; |
c8e98e36 SH |
314 | enum or1k_rtype reloc_type; |
315 | int reloc_code; | |
1c4f3780 | 316 | bfd_vma ret; |
73589c9d CS |
317 | |
318 | if (**strp == '#') | |
319 | ++*strp; | |
320 | ||
c8e98e36 SH |
321 | reloc_code = parse_reloc (strp); |
322 | reloc_type = reloc_code & RTYPE_MASK; | |
323 | if (reloc_code >= 0) | |
73589c9d | 324 | { |
c8e98e36 | 325 | enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT; |
1c4f3780 | 326 | if (splitp) |
73589c9d | 327 | { |
c8e98e36 SH |
328 | if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO) |
329 | && reloc_class != RCLASS_GOT) | |
330 | /* If split we or up the type to RTYPE_SLO or RTYPE_SPO. */ | |
331 | reloc_type |= 1; | |
1c4f3780 RH |
332 | else |
333 | return INVALID_STORE_RELOC; | |
73589c9d | 334 | } |
c8e98e36 | 335 | reloc = or1k_imm16_relocs[reloc_class][reloc_type]; |
73589c9d | 336 | } |
73589c9d | 337 | |
1c4f3780 | 338 | if (reloc != BFD_RELOC_UNUSED) |
73589c9d CS |
339 | { |
340 | bfd_vma value; | |
341 | ||
1c4f3780 | 342 | errmsg = cgen_parse_address (cd, strp, opindex, reloc, |
c151b1c6 | 343 | &result_type, &value); |
73589c9d | 344 | if (**strp != ')') |
1c4f3780 | 345 | errmsg = MISSING_CLOSING_PARENTHESIS; |
73589c9d | 346 | ++*strp; |
73589c9d | 347 | |
1c4f3780 | 348 | ret = value; |
73589c9d | 349 | |
1c4f3780 | 350 | if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) |
c8e98e36 | 351 | switch (reloc_type) |
1c4f3780 RH |
352 | { |
353 | case RTYPE_AHI: | |
354 | ret += 0x8000; | |
355 | /* FALLTHRU */ | |
356 | case RTYPE_HI: | |
357 | ret >>= 16; | |
358 | /* FALLTHRU */ | |
359 | case RTYPE_LO: | |
360 | case RTYPE_SLO: | |
361 | ret &= 0xffff; | |
362 | ret = (ret ^ 0x8000) - 0x8000; | |
363 | break; | |
c8e98e36 SH |
364 | case RTYPE_PO: |
365 | case RTYPE_SPO: | |
366 | ret &= 0x1fff; | |
367 | break; | |
1c4f3780 RH |
368 | default: |
369 | errmsg = INVALID_RELOC_TYPE; | |
370 | } | |
73589c9d CS |
371 | } |
372 | else | |
373 | { | |
374 | long value; | |
375 | errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value); | |
376 | ret = value; | |
377 | } | |
378 | ||
379 | if (errmsg == NULL) | |
380 | *valuep = ret; | |
381 | ||
382 | return errmsg; | |
383 | } | |
384 | ||
385 | static const char * | |
1c4f3780 | 386 | parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep) |
73589c9d | 387 | { |
1c4f3780 RH |
388 | return parse_imm16(cd, strp, opindex, (long *) valuep, 0); |
389 | } | |
73589c9d | 390 | |
1c4f3780 RH |
391 | static const char * |
392 | parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex, | |
393 | long *valuep) | |
394 | { | |
395 | return parse_imm16(cd, strp, opindex, (long *) valuep, 1); | |
396 | } | |
397 | ||
398 | static const char * | |
399 | parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, | |
400 | unsigned long *valuep) | |
401 | { | |
402 | const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0); | |
403 | if (errmsg == NULL) | |
404 | *valuep &= 0xffff; | |
405 | return errmsg; | |
406 | } | |
407 | ||
408 | static const char * | |
409 | parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex, | |
410 | unsigned long *valuep) | |
411 | { | |
412 | const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1); | |
73589c9d CS |
413 | if (errmsg == NULL) |
414 | *valuep &= 0xffff; | |
415 | return errmsg; | |
416 | } | |
417 | ||
418 | /* -- */ | |
419 | ||
420 | /* -- ibd.h */ | |
421 | ||
422 | /* -- */ |