* buildsym.c (subfile_stack): Move here from buildsym.h.
[platform/upstream/binutils.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
353   /* Attempt to read the base part of the insn.  */
354   info->bytes_per_line = buflen = cd->base_insn_bitsize / 8;
355   status = (*info->read_memory_func) (pc, buf, buflen, info);
356
357   /* Try again with the minimum part, if min < base.  */
358   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
359     {
360       info->bytes_per_line = buflen = cd->min_insn_bitsize / 8;
361       status = (*info->read_memory_func) (pc, buf, buflen, info);
362     }
363
364   if (status != 0)
365     {
366       (*info->memory_error_func) (status, pc, info);
367       return -1;
368     }
369
370   return print_insn (cd, pc, info, buf, buflen);
371 }
372
373
374 static void
375 print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
376                  void * dis_info,
377                  long value,
378                  unsigned int attrs ATTRIBUTE_UNUSED,
379                  bfd_vma pc ATTRIBUTE_UNUSED,
380                  int length ATTRIBUTE_UNUSED)
381 {
382   disassemble_info *info = (disassemble_info *) dis_info;
383   (*info->fprintf_func) (info->stream, value ? "-" : "+");
384 }
385
386 static void
387 print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
388                     void * dis_info,
389                     long value,
390                     unsigned int attrs ATTRIBUTE_UNUSED,
391                     bfd_vma pc ATTRIBUTE_UNUSED,
392                     int length ATTRIBUTE_UNUSED)
393 {
394   print_address (cd, dis_info, value, attrs, pc, length);
395 }
396
397 static void
398 print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
399                     void * dis_info,
400                     unsigned long value,
401                     unsigned int attrs ATTRIBUTE_UNUSED,
402                     bfd_vma pc ATTRIBUTE_UNUSED,
403                     int length ATTRIBUTE_UNUSED)
404 {
405   disassemble_info *info = (disassemble_info *)dis_info;
406
407   if (value & 0x800)
408     (*info->fprintf_func) (info->stream, "-");
409
410   value &= 0x7ff;
411   print_address (cd, dis_info, value, attrs, pc, length);
412 }
413
414 \f
415 /* -- */
416