xref: /netbsd-src/external/gpl3/binutils/dist/cpu/m32r.opc (revision be12b8bcaf6171e22ce54bb82a70fb1a78be9ab5)
12a6b7db3Sskrll/* M32R opcode support.  -*- C -*-
22a6b7db3Sskrll
3*be12b8bcSchristos   Copyright 1998, 1999, 2000, 2001, 2004, 2005, 2007, 2009
42a6b7db3Sskrll   Free Software Foundation, Inc.
52a6b7db3Sskrll
62a6b7db3Sskrll   Contributed by Red Hat Inc; developed under contract from
72a6b7db3Sskrll   Mitsubishi Electric Corporation.
82a6b7db3Sskrll
92a6b7db3Sskrll   This file is part of the GNU Binutils.
102a6b7db3Sskrll
112a6b7db3Sskrll   This program is free software; you can redistribute it and/or modify
122a6b7db3Sskrll   it under the terms of the GNU General Public License as published by
132a6b7db3Sskrll   the Free Software Foundation; either version 3 of the License, or
142a6b7db3Sskrll   (at your option) any later version.
152a6b7db3Sskrll
162a6b7db3Sskrll   This program is distributed in the hope that it will be useful,
172a6b7db3Sskrll   but WITHOUT ANY WARRANTY; without even the implied warranty of
182a6b7db3Sskrll   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
192a6b7db3Sskrll   GNU General Public License for more details.
202a6b7db3Sskrll
212a6b7db3Sskrll   You should have received a copy of the GNU General Public License
222a6b7db3Sskrll   along with this program; if not, write to the Free Software
232a6b7db3Sskrll   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
242a6b7db3Sskrll   MA 02110-1301, USA.  */
252a6b7db3Sskrll
262a6b7db3Sskrll
272a6b7db3Sskrll/* This file is an addendum to m32r.cpu.  Heavy use of C code isn't
282a6b7db3Sskrll   appropriate in .cpu files, so it resides here.  This especially applies
292a6b7db3Sskrll   to assembly/disassembly where parsing/printing can be quite involved.
302a6b7db3Sskrll   Such things aren't really part of the specification of the cpu, per se,
312a6b7db3Sskrll   so .cpu files provide the general framework and .opc files handle the
322a6b7db3Sskrll   nitty-gritty details as necessary.
332a6b7db3Sskrll
342a6b7db3Sskrll   Each section is delimited with start and end markers.
352a6b7db3Sskrll
362a6b7db3Sskrll   <arch>-opc.h additions use: "-- opc.h"
372a6b7db3Sskrll   <arch>-opc.c additions use: "-- opc.c"
382a6b7db3Sskrll   <arch>-asm.c additions use: "-- asm.c"
392a6b7db3Sskrll   <arch>-dis.c additions use: "-- dis.c"
402a6b7db3Sskrll   <arch>-ibd.h additions use: "-- ibd.h"  */
412a6b7db3Sskrll
422a6b7db3Sskrll/* -- opc.h */
432a6b7db3Sskrll
442a6b7db3Sskrll#undef  CGEN_DIS_HASH_SIZE
452a6b7db3Sskrll#define CGEN_DIS_HASH_SIZE 256
462a6b7db3Sskrll#undef  CGEN_DIS_HASH
472a6b7db3Sskrll#if 0
482a6b7db3Sskrll#define X(b) (((unsigned char *) (b))[0] & 0xf0)
492a6b7db3Sskrll#define CGEN_DIS_HASH(buffer, value) \
502a6b7db3Sskrll(X (buffer) | \
512a6b7db3Sskrll (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
522a6b7db3Sskrll  : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
532a6b7db3Sskrll  : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
542a6b7db3Sskrll  : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
552a6b7db3Sskrll#else
562a6b7db3Sskrll#define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
572a6b7db3Sskrllextern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
582a6b7db3Sskrll#endif
592a6b7db3Sskrll
602a6b7db3Sskrll/* -- */
612a6b7db3Sskrll
622a6b7db3Sskrll/* -- opc.c */
632a6b7db3Sskrllunsigned int
642a6b7db3Sskrllm32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
652a6b7db3Sskrll{
662a6b7db3Sskrll  unsigned int x;
672a6b7db3Sskrll
682a6b7db3Sskrll  if (value & 0xffff0000) /* 32bit instructions.  */
692a6b7db3Sskrll    value = (value >> 16) & 0xffff;
702a6b7db3Sskrll
712a6b7db3Sskrll  x = (value >> 8) & 0xf0;
722a6b7db3Sskrll  if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
732a6b7db3Sskrll    return x;
742a6b7db3Sskrll
752a6b7db3Sskrll  if (x == 0x70 || x == 0xf0)
762a6b7db3Sskrll    return x | ((value >> 8) & 0x0f);
772a6b7db3Sskrll
782a6b7db3Sskrll  if (x == 0x30)
792a6b7db3Sskrll    return x | ((value & 0x70) >> 4);
802a6b7db3Sskrll  else
812a6b7db3Sskrll    return x | ((value & 0xf0) >> 4);
822a6b7db3Sskrll}
832a6b7db3Sskrll
842a6b7db3Sskrll/* -- */
852a6b7db3Sskrll
862a6b7db3Sskrll/* -- asm.c */
872a6b7db3Sskrllstatic const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
882a6b7db3Sskrll
892a6b7db3Sskrll/* Handle '#' prefixes (i.e. skip over them).  */
902a6b7db3Sskrll
912a6b7db3Sskrllstatic const char *
922a6b7db3Sskrllparse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
932a6b7db3Sskrll	    const char **strp,
942a6b7db3Sskrll	    int opindex ATTRIBUTE_UNUSED,
952a6b7db3Sskrll	    long *valuep ATTRIBUTE_UNUSED)
962a6b7db3Sskrll{
972a6b7db3Sskrll  if (**strp == '#')
982a6b7db3Sskrll    ++*strp;
992a6b7db3Sskrll  return NULL;
1002a6b7db3Sskrll}
1012a6b7db3Sskrll
1022a6b7db3Sskrll/* Handle shigh(), high().  */
1032a6b7db3Sskrll
1042a6b7db3Sskrllstatic const char *
1052a6b7db3Sskrllparse_hi16 (CGEN_CPU_DESC cd,
1062a6b7db3Sskrll	    const char **strp,
1072a6b7db3Sskrll	    int opindex,
1082a6b7db3Sskrll	    unsigned long *valuep)
1092a6b7db3Sskrll{
1102a6b7db3Sskrll  const char *errmsg;
1112a6b7db3Sskrll  enum cgen_parse_operand_result result_type;
1122a6b7db3Sskrll  bfd_vma value;
1132a6b7db3Sskrll
1142a6b7db3Sskrll  if (**strp == '#')
1152a6b7db3Sskrll    ++*strp;
1162a6b7db3Sskrll
1172a6b7db3Sskrll  if (strncasecmp (*strp, "high(", 5) == 0)
1182a6b7db3Sskrll    {
1192a6b7db3Sskrll      *strp += 5;
1202a6b7db3Sskrll      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
1212a6b7db3Sskrll				   & result_type, & value);
1222a6b7db3Sskrll      if (**strp != ')')
1232a6b7db3Sskrll	return MISSING_CLOSING_PARENTHESIS;
1242a6b7db3Sskrll      ++*strp;
1252a6b7db3Sskrll      if (errmsg == NULL
1262a6b7db3Sskrll	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1272a6b7db3Sskrll	{
1282a6b7db3Sskrll	  value >>= 16;
1292a6b7db3Sskrll	  value &= 0xffff;
1302a6b7db3Sskrll	}
1312a6b7db3Sskrll      *valuep = value;
1322a6b7db3Sskrll      return errmsg;
1332a6b7db3Sskrll    }
1342a6b7db3Sskrll  else if (strncasecmp (*strp, "shigh(", 6) == 0)
1352a6b7db3Sskrll    {
1362a6b7db3Sskrll      *strp += 6;
1372a6b7db3Sskrll      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
1382a6b7db3Sskrll				   & result_type, & value);
1392a6b7db3Sskrll      if (**strp != ')')
1402a6b7db3Sskrll	return MISSING_CLOSING_PARENTHESIS;
1412a6b7db3Sskrll      ++*strp;
1422a6b7db3Sskrll      if (errmsg == NULL
1432a6b7db3Sskrll	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1442a6b7db3Sskrll	{
1452a6b7db3Sskrll	  value += 0x8000;
1462a6b7db3Sskrll	  value >>= 16;
1472a6b7db3Sskrll	  value &= 0xffff;
1482a6b7db3Sskrll	}
1492a6b7db3Sskrll      *valuep = value;
1502a6b7db3Sskrll      return errmsg;
1512a6b7db3Sskrll    }
1522a6b7db3Sskrll
1532a6b7db3Sskrll  return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1542a6b7db3Sskrll}
1552a6b7db3Sskrll
1562a6b7db3Sskrll/* Handle low() in a signed context.  Also handle sda().
1572a6b7db3Sskrll   The signedness of the value doesn't matter to low(), but this also
1582a6b7db3Sskrll   handles the case where low() isn't present.  */
1592a6b7db3Sskrll
1602a6b7db3Sskrllstatic const char *
1612a6b7db3Sskrllparse_slo16 (CGEN_CPU_DESC cd,
1622a6b7db3Sskrll	     const char ** strp,
1632a6b7db3Sskrll	     int opindex,
1642a6b7db3Sskrll	     long * valuep)
1652a6b7db3Sskrll{
1662a6b7db3Sskrll  const char *errmsg;
1672a6b7db3Sskrll  enum cgen_parse_operand_result result_type;
1682a6b7db3Sskrll  bfd_vma value;
1692a6b7db3Sskrll
1702a6b7db3Sskrll  if (**strp == '#')
1712a6b7db3Sskrll    ++*strp;
1722a6b7db3Sskrll
1732a6b7db3Sskrll  if (strncasecmp (*strp, "low(", 4) == 0)
1742a6b7db3Sskrll    {
1752a6b7db3Sskrll      *strp += 4;
1762a6b7db3Sskrll      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
1772a6b7db3Sskrll				   & result_type, & value);
1782a6b7db3Sskrll      if (**strp != ')')
1792a6b7db3Sskrll	return MISSING_CLOSING_PARENTHESIS;
1802a6b7db3Sskrll      ++*strp;
1812a6b7db3Sskrll      if (errmsg == NULL
1822a6b7db3Sskrll	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1832a6b7db3Sskrll	value = ((value & 0xffff) ^ 0x8000) - 0x8000;
1842a6b7db3Sskrll      *valuep = value;
1852a6b7db3Sskrll      return errmsg;
1862a6b7db3Sskrll    }
1872a6b7db3Sskrll
1882a6b7db3Sskrll  if (strncasecmp (*strp, "sda(", 4) == 0)
1892a6b7db3Sskrll    {
1902a6b7db3Sskrll      *strp += 4;
1912a6b7db3Sskrll      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
1922a6b7db3Sskrll				   NULL, & value);
1932a6b7db3Sskrll      if (**strp != ')')
1942a6b7db3Sskrll	return MISSING_CLOSING_PARENTHESIS;
1952a6b7db3Sskrll      ++*strp;
1962a6b7db3Sskrll      *valuep = value;
1972a6b7db3Sskrll      return errmsg;
1982a6b7db3Sskrll    }
1992a6b7db3Sskrll
2002a6b7db3Sskrll  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
2012a6b7db3Sskrll}
2022a6b7db3Sskrll
2032a6b7db3Sskrll/* Handle low() in an unsigned context.
2042a6b7db3Sskrll   The signedness of the value doesn't matter to low(), but this also
2052a6b7db3Sskrll   handles the case where low() isn't present.  */
2062a6b7db3Sskrll
2072a6b7db3Sskrllstatic const char *
2082a6b7db3Sskrllparse_ulo16 (CGEN_CPU_DESC cd,
2092a6b7db3Sskrll	     const char **strp,
2102a6b7db3Sskrll	     int opindex,
2112a6b7db3Sskrll	     unsigned long *valuep)
2122a6b7db3Sskrll{
2132a6b7db3Sskrll  const char *errmsg;
2142a6b7db3Sskrll  enum cgen_parse_operand_result result_type;
2152a6b7db3Sskrll  bfd_vma value;
2162a6b7db3Sskrll
2172a6b7db3Sskrll  if (**strp == '#')
2182a6b7db3Sskrll    ++*strp;
2192a6b7db3Sskrll
2202a6b7db3Sskrll  if (strncasecmp (*strp, "low(", 4) == 0)
2212a6b7db3Sskrll    {
2222a6b7db3Sskrll      *strp += 4;
2232a6b7db3Sskrll      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
2242a6b7db3Sskrll				   & result_type, & value);
2252a6b7db3Sskrll      if (**strp != ')')
2262a6b7db3Sskrll	return MISSING_CLOSING_PARENTHESIS;
2272a6b7db3Sskrll      ++*strp;
2282a6b7db3Sskrll      if (errmsg == NULL
2292a6b7db3Sskrll	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
2302a6b7db3Sskrll	value &= 0xffff;
2312a6b7db3Sskrll      *valuep = value;
2322a6b7db3Sskrll      return errmsg;
2332a6b7db3Sskrll    }
2342a6b7db3Sskrll
2352a6b7db3Sskrll  return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
2362a6b7db3Sskrll}
2372a6b7db3Sskrll
2382a6b7db3Sskrll/* -- */
2392a6b7db3Sskrll
2402a6b7db3Sskrll/* -- dis.c */
2412a6b7db3Sskrll
242*be12b8bcSchristos/* Print signed operands with '#' prefixes.  */
243*be12b8bcSchristos
244*be12b8bcSchristosstatic void
245*be12b8bcSchristosprint_signed_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
246*be12b8bcSchristos			       void * dis_info,
247*be12b8bcSchristos			       long value,
248*be12b8bcSchristos			       unsigned int attrs ATTRIBUTE_UNUSED,
249*be12b8bcSchristos			       bfd_vma pc ATTRIBUTE_UNUSED,
250*be12b8bcSchristos			       int length ATTRIBUTE_UNUSED)
251*be12b8bcSchristos{
252*be12b8bcSchristos  disassemble_info *info = (disassemble_info *) dis_info;
253*be12b8bcSchristos
254*be12b8bcSchristos  (*info->fprintf_func) (info->stream, "#");
255*be12b8bcSchristos  (*info->fprintf_func) (info->stream, "%ld", value);
256*be12b8bcSchristos}
257*be12b8bcSchristos
258*be12b8bcSchristos/* Print unsigned operands with '#' prefixes.  */
259*be12b8bcSchristos
260*be12b8bcSchristosstatic void
261*be12b8bcSchristosprint_unsigned_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
262*be12b8bcSchristos				 void * dis_info,
263*be12b8bcSchristos				 long value,
264*be12b8bcSchristos				 unsigned int attrs ATTRIBUTE_UNUSED,
265*be12b8bcSchristos				 bfd_vma pc ATTRIBUTE_UNUSED,
266*be12b8bcSchristos				 int length ATTRIBUTE_UNUSED)
267*be12b8bcSchristos{
268*be12b8bcSchristos  disassemble_info *info = (disassemble_info *) dis_info;
269*be12b8bcSchristos
270*be12b8bcSchristos  (*info->fprintf_func) (info->stream, "#");
271*be12b8bcSchristos  (*info->fprintf_func) (info->stream, "0x%lx", value);
272*be12b8bcSchristos}
2732a6b7db3Sskrll
2742a6b7db3Sskrll/* Handle '#' prefixes as operands.  */
2752a6b7db3Sskrll
2762a6b7db3Sskrllstatic void
2772a6b7db3Sskrllprint_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
2782a6b7db3Sskrll	    void * dis_info,
2792a6b7db3Sskrll	    long value ATTRIBUTE_UNUSED,
2802a6b7db3Sskrll	    unsigned int attrs ATTRIBUTE_UNUSED,
2812a6b7db3Sskrll	    bfd_vma pc ATTRIBUTE_UNUSED,
2822a6b7db3Sskrll	    int length ATTRIBUTE_UNUSED)
2832a6b7db3Sskrll{
2842a6b7db3Sskrll  disassemble_info *info = (disassemble_info *) dis_info;
2852a6b7db3Sskrll
2862a6b7db3Sskrll  (*info->fprintf_func) (info->stream, "#");
2872a6b7db3Sskrll}
2882a6b7db3Sskrll
2892a6b7db3Sskrll#undef  CGEN_PRINT_INSN
2902a6b7db3Sskrll#define CGEN_PRINT_INSN my_print_insn
2912a6b7db3Sskrll
2922a6b7db3Sskrllstatic int
2932a6b7db3Sskrllmy_print_insn (CGEN_CPU_DESC cd,
2942a6b7db3Sskrll	       bfd_vma pc,
2952a6b7db3Sskrll	       disassemble_info *info)
2962a6b7db3Sskrll{
2972a6b7db3Sskrll  bfd_byte buffer[CGEN_MAX_INSN_SIZE];
2982a6b7db3Sskrll  bfd_byte *buf = buffer;
2992a6b7db3Sskrll  int status;
3002a6b7db3Sskrll  int buflen = (pc & 3) == 0 ? 4 : 2;
3012a6b7db3Sskrll  int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
3022a6b7db3Sskrll  bfd_byte *x;
3032a6b7db3Sskrll
3042a6b7db3Sskrll  /* Read the base part of the insn.  */
3052a6b7db3Sskrll
3062a6b7db3Sskrll  status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
3072a6b7db3Sskrll				      buf, buflen, info);
3082a6b7db3Sskrll  if (status != 0)
3092a6b7db3Sskrll    {
3102a6b7db3Sskrll      (*info->memory_error_func) (status, pc, info);
3112a6b7db3Sskrll      return -1;
3122a6b7db3Sskrll    }
3132a6b7db3Sskrll
3142a6b7db3Sskrll  /* 32 bit insn?  */
3152a6b7db3Sskrll  x = (big_p ? &buf[0] : &buf[3]);
3162a6b7db3Sskrll  if ((pc & 3) == 0 && (*x & 0x80) != 0)
3172a6b7db3Sskrll    return print_insn (cd, pc, info, buf, buflen);
3182a6b7db3Sskrll
3192a6b7db3Sskrll  /* Print the first insn.  */
3202a6b7db3Sskrll  if ((pc & 3) == 0)
3212a6b7db3Sskrll    {
3222a6b7db3Sskrll      buf += (big_p ? 0 : 2);
3232a6b7db3Sskrll      if (print_insn (cd, pc, info, buf, 2) == 0)
3242a6b7db3Sskrll	(*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
3252a6b7db3Sskrll      buf += (big_p ? 2 : -2);
3262a6b7db3Sskrll    }
3272a6b7db3Sskrll
3282a6b7db3Sskrll  x = (big_p ? &buf[0] : &buf[1]);
3292a6b7db3Sskrll  if (*x & 0x80)
3302a6b7db3Sskrll    {
3312a6b7db3Sskrll      /* Parallel.  */
3322a6b7db3Sskrll      (*info->fprintf_func) (info->stream, " || ");
3332a6b7db3Sskrll      *x &= 0x7f;
3342a6b7db3Sskrll    }
3352a6b7db3Sskrll  else
3362a6b7db3Sskrll    (*info->fprintf_func) (info->stream, " -> ");
3372a6b7db3Sskrll
3382a6b7db3Sskrll  /* The "& 3" is to pass a consistent address.
3392a6b7db3Sskrll     Parallel insns arguably both begin on the word boundary.
3402a6b7db3Sskrll     Also, branch insns are calculated relative to the word boundary.  */
3412a6b7db3Sskrll  if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
3422a6b7db3Sskrll    (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
3432a6b7db3Sskrll
3442a6b7db3Sskrll  return (pc & 3) ? 2 : 4;
3452a6b7db3Sskrll}
3462a6b7db3Sskrll
3472a6b7db3Sskrll/* -- */
348