1 /* M32R opcode support. -*- C -*-
3 Copyright 1998, 1999, 2000, 2001, 2004, 2005, 2007, 2009
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 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
24 MA 02110-1301, USA. */
27 /* This file is an addendum to m32r.cpu. Heavy use of C code isn't
28 appropriate in .cpu files, so it resides here. This especially applies
29 to assembly/disassembly where parsing/printing can be quite involved.
30 Such things aren't really part of the specification of the cpu, per se,
31 so .cpu files provide the general framework and .opc files handle the
32 nitty-gritty details as necessary.
34 Each section is delimited with start and end markers.
36 <arch>-opc.h additions use: "-- opc.h"
37 <arch>-opc.c additions use: "-- opc.c"
38 <arch>-asm.c additions use: "-- asm.c"
39 <arch>-dis.c additions use: "-- dis.c"
40 <arch>-ibd.h additions use: "-- ibd.h" */
44 #undef CGEN_DIS_HASH_SIZE
45 #define CGEN_DIS_HASH_SIZE 256
48 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
49 #define CGEN_DIS_HASH(buffer, value) \
51 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
52 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
53 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
54 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
56 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
57 extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
64 m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
68 if (value & 0xffff0000) /* 32bit instructions. */
69 value = (value >> 16) & 0xffff;
71 x = (value >> 8) & 0xf0;
72 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
75 if (x == 0x70 || x == 0xf0)
76 return x | ((value >> 8) & 0x0f);
79 return x | ((value & 0x70) >> 4);
81 return x | ((value & 0xf0) >> 4);
87 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
89 /* Handle '#' prefixes (i.e. skip over them). */
92 parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
94 int opindex ATTRIBUTE_UNUSED,
95 long *valuep ATTRIBUTE_UNUSED)
102 /* Handle shigh(), high(). */
105 parse_hi16 (CGEN_CPU_DESC cd,
108 unsigned long *valuep)
111 enum cgen_parse_operand_result result_type;
117 if (strncasecmp (*strp, "high(", 5) == 0)
120 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
121 & result_type, & value);
123 return MISSING_CLOSING_PARENTHESIS;
126 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
134 else if (strncasecmp (*strp, "shigh(", 6) == 0)
137 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
138 & result_type, & value);
140 return MISSING_CLOSING_PARENTHESIS;
143 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
153 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
156 /* Handle low() in a signed context. Also handle sda().
157 The signedness of the value doesn't matter to low(), but this also
158 handles the case where low() isn't present. */
161 parse_slo16 (CGEN_CPU_DESC cd,
167 enum cgen_parse_operand_result result_type;
173 if (strncasecmp (*strp, "low(", 4) == 0)
176 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
177 & result_type, & value);
179 return MISSING_CLOSING_PARENTHESIS;
182 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
183 value = ((value & 0xffff) ^ 0x8000) - 0x8000;
188 if (strncasecmp (*strp, "sda(", 4) == 0)
191 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
194 return MISSING_CLOSING_PARENTHESIS;
200 return cgen_parse_signed_integer (cd, strp, opindex, valuep);
203 /* Handle low() in an unsigned context.
204 The signedness of the value doesn't matter to low(), but this also
205 handles the case where low() isn't present. */
208 parse_ulo16 (CGEN_CPU_DESC cd,
211 unsigned long *valuep)
214 enum cgen_parse_operand_result result_type;
220 if (strncasecmp (*strp, "low(", 4) == 0)
223 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
224 & result_type, & value);
226 return MISSING_CLOSING_PARENTHESIS;
229 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
235 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
242 /* Print signed operands with '#' prefixes. */
245 print_signed_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
248 unsigned int attrs ATTRIBUTE_UNUSED,
249 bfd_vma pc ATTRIBUTE_UNUSED,
250 int length ATTRIBUTE_UNUSED)
252 disassemble_info *info = (disassemble_info *) dis_info;
254 (*info->fprintf_func) (info->stream, "#");
255 (*info->fprintf_func) (info->stream, "%ld", value);
258 /* Print unsigned operands with '#' prefixes. */
261 print_unsigned_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
264 unsigned int attrs ATTRIBUTE_UNUSED,
265 bfd_vma pc ATTRIBUTE_UNUSED,
266 int length ATTRIBUTE_UNUSED)
268 disassemble_info *info = (disassemble_info *) dis_info;
270 (*info->fprintf_func) (info->stream, "#");
271 (*info->fprintf_func) (info->stream, "0x%lx", value);
274 /* Handle '#' prefixes as operands. */
277 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
279 long value ATTRIBUTE_UNUSED,
280 unsigned int attrs ATTRIBUTE_UNUSED,
281 bfd_vma pc ATTRIBUTE_UNUSED,
282 int length ATTRIBUTE_UNUSED)
284 disassemble_info *info = (disassemble_info *) dis_info;
286 (*info->fprintf_func) (info->stream, "#");
289 #undef CGEN_PRINT_INSN
290 #define CGEN_PRINT_INSN my_print_insn
293 my_print_insn (CGEN_CPU_DESC cd,
295 disassemble_info *info)
297 bfd_byte buffer[CGEN_MAX_INSN_SIZE];
298 bfd_byte *buf = buffer;
300 int buflen = (pc & 3) == 0 ? 4 : 2;
301 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
304 /* Read the base part of the insn. */
306 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
310 (*info->memory_error_func) (status, pc, info);
315 x = (big_p ? &buf[0] : &buf[3]);
316 if ((pc & 3) == 0 && (*x & 0x80) != 0)
317 return print_insn (cd, pc, info, buf, buflen);
319 /* Print the first insn. */
322 buf += (big_p ? 0 : 2);
323 if (print_insn (cd, pc, info, buf, 2) == 0)
324 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
325 buf += (big_p ? 2 : -2);
328 x = (big_p ? &buf[0] : &buf[1]);
332 (*info->fprintf_func) (info->stream, " || ");
336 (*info->fprintf_func) (info->stream, " -> ");
338 /* The "& 3" is to pass a consistent address.
339 Parallel insns arguably both begin on the word boundary.
340 Also, branch insns are calculated relative to the word boundary. */
341 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
342 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
344 return (pc & 3) ? 2 : 4;