]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - cpu/epiphany.opc
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / cpu / epiphany.opc
1 /* Adapteva epiphany opcode support. -*- C -*-
2
3 Copyright 2009, 2011 Free Software Foundation, Inc.
4
5 Contributed by Embecosm on behalf of Adapteva, Inc.
6
7 This file is part of the GNU Binutils and of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22 MA 02110-1301, USA. */
23
24 /*
25 Each section is delimited with start and end markers.
26
27 <arch>-opc.h additions use: "-- opc.h"
28 <arch>-opc.c additions use: "-- opc.c"
29 <arch>-asm.c additions use: "-- asm.c"
30 <arch>-dis.c additions use: "-- dis.c"
31 <arch>-ibd.h additions use: "-- ibd.h". */
32 \f
33 /* -- opc.h */
34
35 /* enumerate relaxation types for gas. */
36 typedef enum epiphany_relax_types
37 {
38 EPIPHANY_RELAX_NONE=0,
39 EPIPHANY_RELAX_NEED_RELAXING,
40
41 EPIPHANY_RELAX_BRANCH_SHORT, /* Fits into +127..-128 */
42 EPIPHANY_RELAX_BRANCH_LONG, /* b/bl/b<cond> +-2*16 */
43
44 EPIPHANY_RELAX_ARITH_SIMM3, /* add/sub -7..3 */
45 EPIPHANY_RELAX_ARITH_SIMM11, /* add/sub -2**11-1 .. 2**10-1 */
46
47 EPIPHANY_RELAX_MOV_IMM8, /* mov r,imm8 */
48 EPIPHANY_RELAX_MOV_IMM16, /* mov r,imm16 */
49
50 EPIPHANY_RELAX_LDST_IMM3, /* (ldr|str)* r,[r,disp3] */
51 EPIPHANY_RELAX_LDST_IMM11 /* (ldr|str)* r,[r,disp11] */
52
53 } EPIPHANY_RELAX_TYPES;
54
55 /* Override disassembly hashing... */
56
57 /* Can only depend on instruction having 4 decode bits which gets us to the
58 major groups of 16/32 instructions. */
59 #undef CGEN_DIS_HASH_SIZE
60 #if 1
61
62 /* hash code on the 4 LSBs */
63 #define CGEN_DIS_HASH_SIZE 16
64
65 #define CGEN_DIS_HASH(buf, value) ((*buf) & 0xf)
66 #else
67 #define CGEN_DIS_HASH_SIZE 1
68 #define CGEN_DIS_HASH(buf, value) 0
69 #endif
70
71 extern const char * parse_shortregs (CGEN_CPU_DESC cd,
72 const char ** strp,
73 CGEN_KEYWORD * keywords,
74 long * valuep);
75
76 extern const char * parse_branch_addr (CGEN_CPU_DESC cd,
77 const char ** strp,
78 int opindex,
79 int opinfo,
80 enum cgen_parse_operand_result * resultp,
81 bfd_vma *valuep);
82
83 /* Allows reason codes to be output when assembler errors occur. */
84 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
85
86 \f
87 /* -- opc.c */
88
89
90 \f
91 /* -- asm.c */
92 const char *
93 parse_shortregs (CGEN_CPU_DESC cd,
94 const char ** strp,
95 CGEN_KEYWORD * keywords,
96 long * regno)
97 {
98 const char * errmsg;
99
100 /* Parse register. */
101 errmsg = cgen_parse_keyword (cd, strp, keywords, regno);
102
103 if (errmsg)
104 return errmsg;
105
106 if (*regno > 7)
107 errmsg = _("register unavailable for short instructions");
108
109 return errmsg;
110 }
111
112 static const char * parse_simm_not_reg (CGEN_CPU_DESC, const char **, int,
113 long *);
114
115 static const char *
116 parse_uimm_not_reg (CGEN_CPU_DESC cd,
117 const char ** strp,
118 int opindex,
119 unsigned long * valuep)
120 {
121 long * svalp = (void *) valuep;
122 return parse_simm_not_reg (cd, strp, opindex, svalp);
123 }
124
125 /* Handle simm3/simm11/imm3/imm12. */
126
127 static const char *
128 parse_simm_not_reg (CGEN_CPU_DESC cd,
129 const char ** strp,
130 int opindex,
131 long * valuep)
132 {
133 const char * errmsg;
134
135 int sign = 0;
136 int bits = 0;
137
138 switch (opindex)
139 {
140 case EPIPHANY_OPERAND_SIMM3:
141 sign = 1; bits = 3; break;
142 case EPIPHANY_OPERAND_SIMM11:
143 sign = 1; bits = 11; break;
144 case EPIPHANY_OPERAND_DISP3:
145 sign = 0; bits = 3; break;
146 case EPIPHANY_OPERAND_DISP11:
147 /* Load/store displacement is a sign-magnitude 12 bit value. */
148 sign = 0; bits = 11; break;
149 }
150
151 /* First try to parse as a register name and reject the operand. */
152 errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names,valuep);
153 if (!errmsg)
154 return _("register name used as immediate value");
155
156 errmsg = (sign ? cgen_parse_signed_integer (cd, strp, opindex, valuep)
157 : cgen_parse_unsigned_integer (cd, strp, opindex,
158 (unsigned long *) valuep));
159 if (errmsg)
160 return errmsg;
161
162 if (sign)
163 errmsg = cgen_validate_signed_integer (*valuep,
164 -((1L << bits) - 1), (1 << (bits - 1)) - 1);
165 else
166 errmsg = cgen_validate_unsigned_integer (*valuep, 0, (1L << bits) - 1);
167
168 return errmsg;
169 }
170
171 static const char *
172 parse_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
173 const char ** strp,
174 int opindex ATTRIBUTE_UNUSED,
175 unsigned long *valuep)
176 {
177 if (**strp == '#')
178 ++*strp; /* Skip leading hashes. */
179
180 if (**strp == '-')
181 {
182 *valuep = 1;
183 ++*strp;
184 }
185 else if (**strp == '+')
186 {
187 *valuep = 0;
188 ++*strp;
189 }
190 else
191 *valuep = 0;
192
193 return NULL;
194 }
195
196 static const char *
197 parse_imm8 (CGEN_CPU_DESC cd,
198 const char ** strp,
199 int opindex,
200 bfd_reloc_code_real_type code,
201 enum cgen_parse_operand_result * result_type,
202 bfd_vma * valuep)
203 {
204 const char * errmsg;
205 enum cgen_parse_operand_result rt;
206 long dummyval;
207
208 if (!result_type)
209 result_type = &rt;
210
211 code = BFD_RELOC_NONE;
212
213 if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, &dummyval)
214 || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
215 &dummyval))
216 /* Don't treat "mov ip,ip" as a move-immediate. */
217 return _("register source in immediate move");
218
219 errmsg = cgen_parse_address (cd, strp, opindex, code, result_type, valuep);
220 if (errmsg)
221 return errmsg;
222
223 if (*result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
224 errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xff);
225 else
226 errmsg = _("byte relocation unsupported");
227
228 *valuep &= 0xff;
229 return errmsg;
230 }
231
232 static const char * MISSING_CLOSE_PARENTHESIS = N_("missing `)'");
233
234 static const char *
235 parse_imm16 (CGEN_CPU_DESC cd,
236 const char ** strp,
237 int opindex,
238 bfd_reloc_code_real_type code ATTRIBUTE_UNUSED,
239 enum cgen_parse_operand_result * result_type,
240 bfd_vma * valuep)
241 {
242 const char * errmsg;
243 enum cgen_parse_operand_result rt;
244 long dummyval;
245
246 if (!result_type)
247 result_type = &rt;
248
249 if (strncasecmp (*strp, "%high(", 6) == 0)
250 {
251 *strp += 6;
252 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_HIGH,
253 result_type, valuep);
254 if (**strp != ')')
255 return MISSING_CLOSE_PARENTHESIS;
256 ++*strp;
257 *valuep >>= 16;
258 }
259 else if (strncasecmp (*strp, "%low(", 5) == 0)
260 {
261 *strp += 5;
262 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_LOW,
263 result_type, valuep);
264 if (**strp != ')')
265 return MISSING_CLOSE_PARENTHESIS;
266 ++*strp;
267 }
268 else if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names,
269 &dummyval)
270 || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
271 &dummyval))
272 /* Don't treat "mov ip,ip" as a move-immediate. */
273 return _("register source in immediate move");
274 else
275 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_16,
276 result_type, valuep);
277
278 if (!errmsg && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
279 errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xffff);
280
281 *valuep &= 0xffff;
282 return errmsg;
283 }
284
285 const char *
286 parse_branch_addr (CGEN_CPU_DESC cd,
287 const char ** strp,
288 int opindex,
289 int opinfo ATTRIBUTE_UNUSED,
290 enum cgen_parse_operand_result * resultp ATTRIBUTE_UNUSED,
291 bfd_vma *valuep ATTRIBUTE_UNUSED)
292 {
293 const char * errmsg;
294 enum cgen_parse_operand_result result_type;
295 bfd_reloc_code_real_type code = BFD_RELOC_NONE;
296 bfd_vma value;
297
298 switch (opindex)
299 {
300 case EPIPHANY_OPERAND_SIMM24:
301 code = BFD_RELOC_EPIPHANY_SIMM24;
302 break;
303
304 case EPIPHANY_OPERAND_SIMM8:
305 code = BFD_RELOC_EPIPHANY_SIMM8;
306 break;
307
308 default:
309 errmsg = _("ABORT: unknown operand");
310 return errmsg;
311 }
312
313 errmsg = cgen_parse_address (cd, strp, opindex, code,
314 &result_type, &value);
315 if (errmsg == NULL)
316 {
317 if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
318 {
319 /* Act as if we had done a PC-relative branch, ala .+num. */
320 char buf[20];
321 const char * bufp = (const char *) buf;
322
323 sprintf (buf, ".+%ld", (long) value);
324 errmsg = cgen_parse_address (cd, &bufp, opindex, code, &result_type,
325 &value);
326 }
327
328 if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
329 {
330 /* This will happen for things like (s2-s1) where s2 and s1
331 are labels. */
332 /* Nothing further to be done. */
333 }
334 else
335 errmsg = _("Not a pc-relative address.");
336 }
337 return errmsg;
338 }
339 \f
340 /* -- dis.c */
341
342 #define CGEN_PRINT_INSN epiphany_print_insn
343
344 static int
345 epiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
346 {
347 bfd_byte buf[CGEN_MAX_INSN_SIZE];
348 int buflen;
349 int status;
350
351 info->bytes_per_chunk = 2;
352 info->bytes_per_line = 4;
353
354 /* Attempt to read the base part of the insn. */
355 buflen = cd->base_insn_bitsize / 8;
356 status = (*info->read_memory_func) (pc, buf, buflen, info);
357
358 /* Try again with the minimum part, if min < base. */
359 if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
360 {
361 buflen = cd->min_insn_bitsize / 8;
362 status = (*info->read_memory_func) (pc, buf, buflen, info);
363 }
364
365 if (status != 0)
366 {
367 (*info->memory_error_func) (status, pc, info);
368 return -1;
369 }
370
371 return print_insn (cd, pc, info, buf, buflen);
372 }
373
374
375 static void
376 print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
377 void * dis_info,
378 long value,
379 unsigned int attrs ATTRIBUTE_UNUSED,
380 bfd_vma pc ATTRIBUTE_UNUSED,
381 int length ATTRIBUTE_UNUSED)
382 {
383 disassemble_info *info = (disassemble_info *) dis_info;
384 (*info->fprintf_func) (info->stream, value ? "-" : "+");
385 }
386
387 static void
388 print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
389 void * dis_info,
390 long value,
391 unsigned int attrs ATTRIBUTE_UNUSED,
392 bfd_vma pc ATTRIBUTE_UNUSED,
393 int length ATTRIBUTE_UNUSED)
394 {
395 print_address (cd, dis_info, value, attrs, pc, length);
396 }
397
398 static void
399 print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
400 void * dis_info,
401 unsigned long value,
402 unsigned int attrs ATTRIBUTE_UNUSED,
403 bfd_vma pc ATTRIBUTE_UNUSED,
404 int length ATTRIBUTE_UNUSED)
405 {
406 disassemble_info *info = (disassemble_info *)dis_info;
407
408 if (value & 0x800)
409 (*info->fprintf_func) (info->stream, "-");
410
411 value &= 0x7ff;
412 print_address (cd, dis_info, value, attrs, pc, length);
413 }
414
415 \f
416 /* -- */
417