1 /* M32R opcode support. -*- C -*-
3 Copyright 1998, 1999, 2000, 2001, 2004, 2005
4 Free Software Foundation, Inc.
6 Contributed by Red Hat Inc; developed under contract from
7 Mitsubishi Electric Corporation.
9 This file is part of the GNU Binutils.
11 Contributed by Red Hat Inc; developed under contract from Fujitsu.
13 This file is part of the GNU Binutils.
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
29 /* This file is an addendum to m32r.cpu. Heavy use of C code isn't
30 appropriate in .cpu files, so it resides here. This especially applies
31 to assembly/disassembly where parsing/printing can be quite involved.
32 Such things aren't really part of the specification of the cpu, per se,
33 so .cpu files provide the general framework and .opc files handle the
34 nitty-gritty details as necessary.
36 Each section is delimited with start and end markers.
38 <arch>-opc.h additions use: "-- opc.h"
39 <arch>-opc.c additions use: "-- opc.c"
40 <arch>-asm.c additions use: "-- asm.c"
41 <arch>-dis.c additions use: "-- dis.c"
42 <arch>-ibd.h additions use: "-- ibd.h" */
46 #undef CGEN_DIS_HASH_SIZE
47 #define CGEN_DIS_HASH_SIZE 256
50 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
51 #define CGEN_DIS_HASH(buffer, value) \
53 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
54 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
55 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
56 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
58 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash(buffer, value)
59 extern unsigned int m32r_cgen_dis_hash(const char *, CGEN_INSN_INT);
66 m32r_cgen_dis_hash (buf, value)
67 const char * buf ATTRIBUTE_UNUSED;
72 if (value & 0xffff0000) /* 32bit instructions */
73 value = (value >> 16) & 0xffff;
75 x = (value>>8) & 0xf0;
76 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
79 if (x == 0x70 || x == 0xf0)
80 return x | ((value>>8) & 0x0f);
83 return x | ((value & 0x70) >> 4);
85 return x | ((value & 0xf0) >> 4);
91 static const char * parse_hash
92 PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
93 static const char * parse_hi16
94 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
95 static const char * parse_slo16
96 PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
97 static const char * parse_ulo16
98 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
100 /* Handle '#' prefixes (i.e. skip over them). */
103 parse_hash (cd, strp, opindex, valuep)
104 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
106 int opindex ATTRIBUTE_UNUSED;
107 long *valuep ATTRIBUTE_UNUSED;
114 /* Handle shigh(), high(). */
117 parse_hi16 (cd, strp, opindex, valuep)
121 unsigned long *valuep;
124 enum cgen_parse_operand_result result_type;
130 if (strncasecmp (*strp, "high(", 5) == 0)
133 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
134 &result_type, &value);
136 return "missing `)'";
139 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
144 else if (strncasecmp (*strp, "shigh(", 6) == 0)
147 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
148 &result_type, &value);
150 return "missing `)'";
153 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
155 value = value + (value & 0x8000 ? 0x10000 : 0);
162 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
165 /* Handle low() in a signed context. Also handle sda().
166 The signedness of the value doesn't matter to low(), but this also
167 handles the case where low() isn't present. */
170 parse_slo16 (cd, strp, opindex, valuep)
177 enum cgen_parse_operand_result result_type;
183 if (strncasecmp (*strp, "low(", 4) == 0)
186 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
187 &result_type, &value);
189 return "missing `)'";
192 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
202 if (strncasecmp (*strp, "sda(", 4) == 0)
205 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
208 return "missing `)'";
214 return cgen_parse_signed_integer (cd, strp, opindex, valuep);
217 /* Handle low() in an unsigned context.
218 The signedness of the value doesn't matter to low(), but this also
219 handles the case where low() isn't present. */
222 parse_ulo16 (cd, strp, opindex, valuep)
226 unsigned long *valuep;
229 enum cgen_parse_operand_result result_type;
235 if (strncasecmp (*strp, "low(", 4) == 0)
238 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
239 &result_type, &value);
241 return "missing `)'";
244 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
250 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
256 static void print_hash PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
257 static int my_print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
259 /* Immediate values are prefixed with '#'. */
261 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
264 if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
265 (*info->fprintf_func) (info->stream, "#"); \
269 /* Handle '#' prefixes as operands. */
272 print_hash (cd, dis_info, value, attrs, pc, length)
273 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
275 long value ATTRIBUTE_UNUSED;
276 unsigned int attrs ATTRIBUTE_UNUSED;
277 bfd_vma pc ATTRIBUTE_UNUSED;
278 int length ATTRIBUTE_UNUSED;
280 disassemble_info *info = (disassemble_info *) dis_info;
281 (*info->fprintf_func) (info->stream, "#");
284 #undef CGEN_PRINT_INSN
285 #define CGEN_PRINT_INSN my_print_insn
288 my_print_insn (cd, pc, info)
291 disassemble_info *info;
293 char buffer[CGEN_MAX_INSN_SIZE];
296 int buflen = (pc & 3) == 0 ? 4 : 2;
297 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
300 /* Read the base part of the insn. */
302 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
306 (*info->memory_error_func) (status, pc, info);
311 x = (big_p ? &buf[0] : &buf[3]);
312 if ((pc & 3) == 0 && (*x & 0x80) != 0)
313 return print_insn (cd, pc, info, buf, buflen);
315 /* Print the first insn. */
318 buf += (big_p ? 0 : 2);
319 if (print_insn (cd, pc, info, buf, 2) == 0)
320 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
321 buf += (big_p ? 2 : -2);
324 x = (big_p ? &buf[0] : &buf[1]);
328 (*info->fprintf_func) (info->stream, " || ");
332 (*info->fprintf_func) (info->stream, " -> ");
334 /* The "& 3" is to pass a consistent address.
335 Parallel insns arguably both begin on the word boundary.
336 Also, branch insns are calculated relative to the word boundary. */
337 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
338 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
340 return (pc & 3) ? 2 : 4;