xref: /netbsd-src/external/gpl3/binutils/dist/cpu/epiphany.opc (revision 8cbf5cb7c47586c462bde6a6b4444605bb6ef4e2)
1883529b6Schristos/* Adapteva epiphany opcode support.  -*- C -*-
2883529b6Schristos
3883529b6Schristos   Copyright 2009, 2011 Free Software Foundation, Inc.
4883529b6Schristos
5883529b6Schristos   Contributed by Embecosm on behalf of Adapteva, Inc.
6883529b6Schristos
7883529b6Schristos   This file is part of the GNU Binutils and of GDB.
8883529b6Schristos
9883529b6Schristos   This program is free software; you can redistribute it and/or modify
10883529b6Schristos   it under the terms of the GNU General Public License as published by
11883529b6Schristos   the Free Software Foundation; either version 3 of the License, or
12883529b6Schristos   (at your option) any later version.
13883529b6Schristos
14883529b6Schristos   This program is distributed in the hope that it will be useful,
15883529b6Schristos   but WITHOUT ANY WARRANTY; without even the implied warranty of
16883529b6Schristos   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17883529b6Schristos   GNU General Public License for more details.
18883529b6Schristos
19883529b6Schristos   You should have received a copy of the GNU General Public License
20883529b6Schristos   along with this program; if not, write to the Free Software
21883529b6Schristos   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22883529b6Schristos   MA 02110-1301, USA.  */
23883529b6Schristos
24883529b6Schristos/*
25883529b6Schristos   Each section is delimited with start and end markers.
26883529b6Schristos
27883529b6Schristos   <arch>-opc.h additions use: "-- opc.h"
28883529b6Schristos   <arch>-opc.c additions use: "-- opc.c"
29883529b6Schristos   <arch>-asm.c additions use: "-- asm.c"
30883529b6Schristos   <arch>-dis.c additions use: "-- dis.c"
31883529b6Schristos   <arch>-ibd.h additions use: "-- ibd.h".  */
32883529b6Schristos
33883529b6Schristos/* -- opc.h */
34883529b6Schristos
35883529b6Schristos/* enumerate relaxation types for gas. */
36883529b6Schristostypedef enum epiphany_relax_types
37883529b6Schristos{
38883529b6Schristos  EPIPHANY_RELAX_NONE=0,
39883529b6Schristos  EPIPHANY_RELAX_NEED_RELAXING,
40883529b6Schristos
41883529b6Schristos  EPIPHANY_RELAX_BRANCH_SHORT,	/* Fits into +127..-128 */
42883529b6Schristos  EPIPHANY_RELAX_BRANCH_LONG,	/* b/bl/b<cond> +-2*16 */
43883529b6Schristos
44883529b6Schristos  EPIPHANY_RELAX_ARITH_SIMM3,	/* add/sub -7..3 */
45883529b6Schristos  EPIPHANY_RELAX_ARITH_SIMM11,	/* add/sub -2**11-1 .. 2**10-1 */
46883529b6Schristos
47883529b6Schristos  EPIPHANY_RELAX_MOV_IMM8,		/* mov r,imm8 */
48883529b6Schristos  EPIPHANY_RELAX_MOV_IMM16,	/* mov r,imm16 */
49883529b6Schristos
50883529b6Schristos  EPIPHANY_RELAX_LDST_IMM3,	/* (ldr|str)* r,[r,disp3] */
51883529b6Schristos  EPIPHANY_RELAX_LDST_IMM11	/* (ldr|str)* r,[r,disp11] */
52883529b6Schristos
53883529b6Schristos} EPIPHANY_RELAX_TYPES;
54883529b6Schristos
55883529b6Schristos/* Override disassembly hashing... */
56883529b6Schristos
57883529b6Schristos/* Can only depend on instruction having 4 decode bits which gets us to the
58883529b6Schristos   major groups of 16/32 instructions. */
59883529b6Schristos#undef CGEN_DIS_HASH_SIZE
60883529b6Schristos#if 1
61883529b6Schristos
62883529b6Schristos/* hash code on the 4 LSBs */
63883529b6Schristos#define CGEN_DIS_HASH_SIZE 16
64883529b6Schristos
65883529b6Schristos#define CGEN_DIS_HASH(buf, value) ((*buf) & 0xf)
66883529b6Schristos#else
67883529b6Schristos#define CGEN_DIS_HASH_SIZE 1
68883529b6Schristos#define CGEN_DIS_HASH(buf, value) 0
69883529b6Schristos#endif
70883529b6Schristos
71883529b6Schristosextern const char * parse_shortregs (CGEN_CPU_DESC cd,
72883529b6Schristos				     const char ** strp,
73883529b6Schristos				     CGEN_KEYWORD * keywords,
74883529b6Schristos				     long * valuep);
75883529b6Schristos
76883529b6Schristosextern const char * parse_branch_addr (CGEN_CPU_DESC cd,
77883529b6Schristos				       const char ** strp,
78883529b6Schristos				       int opindex,
79883529b6Schristos				       int opinfo,
80883529b6Schristos				       enum cgen_parse_operand_result * resultp,
81883529b6Schristos				       bfd_vma *valuep);
82883529b6Schristos
83883529b6Schristos/* Allows reason codes to be output when assembler errors occur.  */
84883529b6Schristos#define CGEN_VERBOSE_ASSEMBLER_ERRORS
85883529b6Schristos
86883529b6Schristos
87883529b6Schristos/* -- opc.c */
88883529b6Schristos
89883529b6Schristos
90883529b6Schristos
91883529b6Schristos/* -- asm.c */
92883529b6Schristosconst char *
93883529b6Schristosparse_shortregs (CGEN_CPU_DESC cd,
94883529b6Schristos		 const char ** strp,
95883529b6Schristos		 CGEN_KEYWORD * keywords,
96883529b6Schristos		 long * regno)
97883529b6Schristos{
98883529b6Schristos  const char * errmsg;
99883529b6Schristos
100883529b6Schristos  /* Parse register.  */
101883529b6Schristos  errmsg = cgen_parse_keyword (cd, strp, keywords, regno);
102883529b6Schristos
103883529b6Schristos  if (errmsg)
104883529b6Schristos    return errmsg;
105883529b6Schristos
106883529b6Schristos  if (*regno > 7)
107883529b6Schristos    errmsg = _("register unavailable for short instructions");
108883529b6Schristos
109883529b6Schristos  return errmsg;
110883529b6Schristos}
111883529b6Schristos
112883529b6Schristosstatic const char * parse_simm_not_reg (CGEN_CPU_DESC, const char **, int,
113883529b6Schristos					long *);
114883529b6Schristos
115883529b6Schristosstatic const char *
116883529b6Schristosparse_uimm_not_reg (CGEN_CPU_DESC cd,
117883529b6Schristos		    const char ** strp,
118883529b6Schristos		    int opindex,
119883529b6Schristos		    unsigned long * valuep)
120883529b6Schristos{
121883529b6Schristos  long * svalp = (void *) valuep;
122883529b6Schristos  return parse_simm_not_reg (cd, strp, opindex, svalp);
123883529b6Schristos}
124883529b6Schristos
125883529b6Schristos/* Handle simm3/simm11/imm3/imm12.  */
126883529b6Schristos
127883529b6Schristosstatic const char *
128883529b6Schristosparse_simm_not_reg (CGEN_CPU_DESC cd,
129883529b6Schristos		   const char ** strp,
130883529b6Schristos		   int opindex,
131883529b6Schristos		   long * valuep)
132883529b6Schristos{
133883529b6Schristos  const char * errmsg;
134883529b6Schristos
135883529b6Schristos  int   sign = 0;
136883529b6Schristos  int   bits = 0;
137883529b6Schristos
138883529b6Schristos  switch (opindex)
139883529b6Schristos    {
140883529b6Schristos    case EPIPHANY_OPERAND_SIMM3:
141883529b6Schristos      sign = 1; bits = 3; break;
142883529b6Schristos    case EPIPHANY_OPERAND_SIMM11:
143883529b6Schristos      sign = 1; bits = 11; break;
144883529b6Schristos    case EPIPHANY_OPERAND_DISP3:
145883529b6Schristos      sign = 0; bits = 3; break;
146883529b6Schristos    case EPIPHANY_OPERAND_DISP11:
147883529b6Schristos      /* Load/store displacement is a sign-magnitude 12 bit value.  */
148883529b6Schristos      sign = 0; bits = 11; break;
149883529b6Schristos    }
150883529b6Schristos
151883529b6Schristos  /* First try to parse as a register name and reject the operand.  */
152883529b6Schristos  errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names,valuep);
153883529b6Schristos  if (!errmsg)
154883529b6Schristos    return _("register name used as immediate value");
155883529b6Schristos
156883529b6Schristos  errmsg = (sign ? cgen_parse_signed_integer (cd, strp, opindex, valuep)
157883529b6Schristos	    : cgen_parse_unsigned_integer (cd, strp, opindex,
158883529b6Schristos					  (unsigned long *) valuep));
159883529b6Schristos  if (errmsg)
160883529b6Schristos    return errmsg;
161883529b6Schristos
162883529b6Schristos  if (sign)
163883529b6Schristos    errmsg = cgen_validate_signed_integer (*valuep,
164883529b6Schristos					  -((1L << bits) - 1), (1 << (bits - 1)) - 1);
165883529b6Schristos  else
166883529b6Schristos    errmsg = cgen_validate_unsigned_integer (*valuep, 0, (1L << bits) - 1);
167883529b6Schristos
168883529b6Schristos  return errmsg;
169883529b6Schristos}
170883529b6Schristos
171883529b6Schristosstatic const char *
172883529b6Schristosparse_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
173883529b6Schristos		 const char ** strp,
174883529b6Schristos		 int opindex ATTRIBUTE_UNUSED,
175883529b6Schristos		 unsigned long *valuep)
176883529b6Schristos{
177883529b6Schristos  if (**strp == '#')
178883529b6Schristos    ++*strp;			/* Skip leading hashes.  */
179883529b6Schristos
180883529b6Schristos  if (**strp == '-')
181883529b6Schristos    {
182883529b6Schristos      *valuep = 1;
183883529b6Schristos      ++*strp;
184883529b6Schristos    }
185883529b6Schristos  else if (**strp == '+')
186883529b6Schristos    {
187883529b6Schristos      *valuep = 0;
188883529b6Schristos      ++*strp;
189883529b6Schristos    }
190883529b6Schristos  else
191883529b6Schristos    *valuep = 0;
192883529b6Schristos
193883529b6Schristos  return NULL;
194883529b6Schristos}
195883529b6Schristos
196883529b6Schristosstatic const char *
197883529b6Schristosparse_imm8 (CGEN_CPU_DESC cd,
198883529b6Schristos	    const char ** strp,
199883529b6Schristos	    int opindex,
200883529b6Schristos	    bfd_reloc_code_real_type code,
201883529b6Schristos	    enum cgen_parse_operand_result * result_type,
202883529b6Schristos	    bfd_vma * valuep)
203883529b6Schristos{
204883529b6Schristos  const char * errmsg;
205883529b6Schristos  enum cgen_parse_operand_result rt;
206883529b6Schristos  long dummyval;
207883529b6Schristos
208883529b6Schristos  if (!result_type)
209883529b6Schristos    result_type = &rt;
210883529b6Schristos
211883529b6Schristos  code = BFD_RELOC_NONE;
212883529b6Schristos
213883529b6Schristos  if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, &dummyval)
214883529b6Schristos      || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
215883529b6Schristos			      &dummyval))
216883529b6Schristos    /* Don't treat "mov ip,ip" as a move-immediate.  */
217883529b6Schristos    return _("register source in immediate move");
218883529b6Schristos
219883529b6Schristos  errmsg = cgen_parse_address (cd, strp, opindex, code, result_type, valuep);
220883529b6Schristos  if (errmsg)
221883529b6Schristos    return errmsg;
222883529b6Schristos
223883529b6Schristos  if (*result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
224883529b6Schristos    errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xff);
225883529b6Schristos  else
226883529b6Schristos    errmsg = _("byte relocation unsupported");
227883529b6Schristos
228883529b6Schristos  *valuep &= 0xff;
229883529b6Schristos  return errmsg;
230883529b6Schristos}
231883529b6Schristos
232883529b6Schristosstatic const char * MISSING_CLOSE_PARENTHESIS = N_("missing `)'");
233883529b6Schristos
234883529b6Schristosstatic const char *
235883529b6Schristosparse_imm16 (CGEN_CPU_DESC cd,
236883529b6Schristos	     const char ** strp,
237883529b6Schristos	     int opindex,
238883529b6Schristos	     bfd_reloc_code_real_type code ATTRIBUTE_UNUSED,
239883529b6Schristos	     enum cgen_parse_operand_result * result_type,
240883529b6Schristos	     bfd_vma * valuep)
241883529b6Schristos{
242883529b6Schristos  const char * errmsg;
243883529b6Schristos  enum cgen_parse_operand_result rt;
244883529b6Schristos  long dummyval;
245883529b6Schristos
246883529b6Schristos  if (!result_type)
247883529b6Schristos    result_type = &rt;
248883529b6Schristos
249883529b6Schristos  if (strncasecmp (*strp, "%high(", 6) == 0)
250883529b6Schristos    {
251883529b6Schristos      *strp += 6;
252883529b6Schristos      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_HIGH,
253883529b6Schristos				   result_type, valuep);
254883529b6Schristos      if (**strp != ')')
255883529b6Schristos	return MISSING_CLOSE_PARENTHESIS;
256883529b6Schristos      ++*strp;
257883529b6Schristos      *valuep >>= 16;
258883529b6Schristos    }
259883529b6Schristos  else if (strncasecmp (*strp, "%low(", 5) == 0)
260883529b6Schristos    {
261883529b6Schristos      *strp += 5;
262883529b6Schristos      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_LOW,
263883529b6Schristos				   result_type, valuep);
264883529b6Schristos      if (**strp != ')')
265883529b6Schristos	return MISSING_CLOSE_PARENTHESIS;
266883529b6Schristos      ++*strp;
267883529b6Schristos    }
268883529b6Schristos  else if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names,
269883529b6Schristos				&dummyval)
270883529b6Schristos	   || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
271883529b6Schristos				   &dummyval))
272883529b6Schristos    /* Don't treat "mov ip,ip" as a move-immediate.  */
273883529b6Schristos    return _("register source in immediate move");
274883529b6Schristos  else
275883529b6Schristos    errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_16,
276883529b6Schristos				 result_type, valuep);
277883529b6Schristos
278883529b6Schristos  if (!errmsg && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
279883529b6Schristos    errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xffff);
280883529b6Schristos
281883529b6Schristos  *valuep &= 0xffff;
282883529b6Schristos  return errmsg;
283883529b6Schristos}
284883529b6Schristos
285883529b6Schristosconst char *
286883529b6Schristosparse_branch_addr (CGEN_CPU_DESC cd,
287883529b6Schristos		   const char ** strp,
288883529b6Schristos		   int opindex,
289883529b6Schristos		   int opinfo ATTRIBUTE_UNUSED,
290883529b6Schristos		   enum cgen_parse_operand_result * resultp ATTRIBUTE_UNUSED,
291883529b6Schristos		   bfd_vma *valuep ATTRIBUTE_UNUSED)
292883529b6Schristos{
293883529b6Schristos  const char * errmsg;
294883529b6Schristos  enum cgen_parse_operand_result result_type;
295883529b6Schristos  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
296883529b6Schristos  bfd_vma value;
297883529b6Schristos
298883529b6Schristos  switch (opindex)
299883529b6Schristos    {
300883529b6Schristos    case EPIPHANY_OPERAND_SIMM24:
301883529b6Schristos      code = BFD_RELOC_EPIPHANY_SIMM24;
302883529b6Schristos      break;
303883529b6Schristos
304883529b6Schristos    case EPIPHANY_OPERAND_SIMM8:
305883529b6Schristos      code = BFD_RELOC_EPIPHANY_SIMM8;
306883529b6Schristos      break;
307883529b6Schristos
308883529b6Schristos    default:
309883529b6Schristos      errmsg = _("ABORT: unknown operand");
310883529b6Schristos      return errmsg;
311883529b6Schristos    }
312883529b6Schristos
313883529b6Schristos  errmsg = cgen_parse_address (cd, strp, opindex, code,
314883529b6Schristos			       &result_type, &value);
315883529b6Schristos  if (errmsg == NULL)
316883529b6Schristos    {
317883529b6Schristos      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
318883529b6Schristos	{
319883529b6Schristos	  /* Act as if we had done a PC-relative branch, ala .+num.  */
320883529b6Schristos	  char buf[20];
321883529b6Schristos	  const char * bufp = (const char *) buf;
322883529b6Schristos
323883529b6Schristos	  sprintf (buf, ".+%ld", (long) value);
324883529b6Schristos	  errmsg = cgen_parse_address (cd, &bufp, opindex, code, &result_type,
325883529b6Schristos				       &value);
326883529b6Schristos	}
327883529b6Schristos
328883529b6Schristos      if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
329883529b6Schristos	{
330883529b6Schristos	  /* This will happen for things like (s2-s1) where s2 and s1
331883529b6Schristos	     are labels.  */
332883529b6Schristos	  /* Nothing further to be done.  */
333883529b6Schristos	}
334883529b6Schristos      else
335883529b6Schristos	errmsg = _("Not a pc-relative address.");
336883529b6Schristos    }
337883529b6Schristos  return errmsg;
338883529b6Schristos}
339883529b6Schristos
340883529b6Schristos/* -- dis.c */
341883529b6Schristos
342883529b6Schristos#define CGEN_PRINT_INSN epiphany_print_insn
343883529b6Schristos
344883529b6Schristosstatic int
345883529b6Schristosepiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
346883529b6Schristos{
347883529b6Schristos  bfd_byte buf[CGEN_MAX_INSN_SIZE];
348883529b6Schristos  int buflen;
349883529b6Schristos  int status;
350883529b6Schristos
351883529b6Schristos  info->bytes_per_chunk = 2;
352*8cbf5cb7Schristos  info->bytes_per_line = 4;
353883529b6Schristos
354883529b6Schristos  /* Attempt to read the base part of the insn.  */
355*8cbf5cb7Schristos  buflen = cd->base_insn_bitsize / 8;
356883529b6Schristos  status = (*info->read_memory_func) (pc, buf, buflen, info);
357883529b6Schristos
358883529b6Schristos  /* Try again with the minimum part, if min < base.  */
359883529b6Schristos  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
360883529b6Schristos    {
361*8cbf5cb7Schristos      buflen = cd->min_insn_bitsize / 8;
362883529b6Schristos      status = (*info->read_memory_func) (pc, buf, buflen, info);
363883529b6Schristos    }
364883529b6Schristos
365883529b6Schristos  if (status != 0)
366883529b6Schristos    {
367883529b6Schristos      (*info->memory_error_func) (status, pc, info);
368883529b6Schristos      return -1;
369883529b6Schristos    }
370883529b6Schristos
371883529b6Schristos  return print_insn (cd, pc, info, buf, buflen);
372883529b6Schristos}
373883529b6Schristos
374883529b6Schristos
375883529b6Schristosstatic void
376883529b6Schristosprint_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
377883529b6Schristos		 void * dis_info,
378883529b6Schristos		 long value,
379883529b6Schristos		 unsigned int attrs ATTRIBUTE_UNUSED,
380883529b6Schristos		 bfd_vma pc ATTRIBUTE_UNUSED,
381883529b6Schristos		 int length ATTRIBUTE_UNUSED)
382883529b6Schristos{
383883529b6Schristos  disassemble_info *info = (disassemble_info *) dis_info;
384883529b6Schristos  (*info->fprintf_func) (info->stream, value ? "-" : "+");
385883529b6Schristos}
386883529b6Schristos
387883529b6Schristosstatic void
388883529b6Schristosprint_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
389883529b6Schristos		    void * dis_info,
390883529b6Schristos		    long value,
391883529b6Schristos		    unsigned int attrs ATTRIBUTE_UNUSED,
392883529b6Schristos		    bfd_vma pc ATTRIBUTE_UNUSED,
393883529b6Schristos		    int length ATTRIBUTE_UNUSED)
394883529b6Schristos{
395883529b6Schristos  print_address (cd, dis_info, value, attrs, pc, length);
396883529b6Schristos}
397883529b6Schristos
398883529b6Schristosstatic void
399883529b6Schristosprint_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
400883529b6Schristos		    void * dis_info,
401883529b6Schristos		    unsigned long value,
402883529b6Schristos		    unsigned int attrs ATTRIBUTE_UNUSED,
403883529b6Schristos		    bfd_vma pc ATTRIBUTE_UNUSED,
404883529b6Schristos		    int length ATTRIBUTE_UNUSED)
405883529b6Schristos{
406883529b6Schristos  disassemble_info *info = (disassemble_info *)dis_info;
407883529b6Schristos
408883529b6Schristos  if (value & 0x800)
409883529b6Schristos    (*info->fprintf_func) (info->stream, "-");
410883529b6Schristos
411883529b6Schristos  value &= 0x7ff;
412883529b6Schristos  print_address (cd, dis_info, value, attrs, pc, length);
413883529b6Schristos}
414883529b6Schristos
415883529b6Schristos
416883529b6Schristos/* -- */
417883529b6Schristos
418