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,
28 MA 02110-1301, USA. */
30 /* This file is an addendum to m32r.cpu. Heavy use of C code isn't
31 appropriate in .cpu files, so it resides here. This especially applies
32 to assembly/disassembly where parsing/printing can be quite involved.
33 Such things aren't really part of the specification of the cpu, per se,
34 so .cpu files provide the general framework and .opc files handle the
35 nitty-gritty details as necessary.
37 Each section is delimited with start and end markers.
39 <arch>-opc.h additions use: "-- opc.h"
40 <arch>-opc.c additions use: "-- opc.c"
41 <arch>-asm.c additions use: "-- asm.c"
42 <arch>-dis.c additions use: "-- dis.c"
43 <arch>-ibd.h additions use: "-- ibd.h" */
47 #undef CGEN_DIS_HASH_SIZE
48 #define CGEN_DIS_HASH_SIZE 256
51 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
52 #define CGEN_DIS_HASH(buffer, value) \
54 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
55 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
56 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
57 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
59 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
60 extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
67 m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
71 if (value & 0xffff0000) /* 32bit instructions. */
72 value = (value >> 16) & 0xffff;
74 x = (value >> 8) & 0xf0;
75 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
78 if (x == 0x70 || x == 0xf0)
79 return x | ((value >> 8) & 0x0f);
82 return x | ((value & 0x70) >> 4);
84 return x | ((value & 0xf0) >> 4);
90 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
92 /* Handle '#' prefixes (i.e. skip over them). */
95 parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
97 int opindex ATTRIBUTE_UNUSED,
98 long *valuep ATTRIBUTE_UNUSED)
105 /* Handle shigh(), high(). */
108 parse_hi16 (CGEN_CPU_DESC cd,
111 unsigned long *valuep)
114 enum cgen_parse_operand_result result_type;
120 if (strncasecmp (*strp, "high(", 5) == 0)
123 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
124 & result_type, & value);
126 return MISSING_CLOSING_PARENTHESIS;
129 && 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)
145 value = value + (value & 0x8000 ? 0x10000 : 0);
152 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
155 /* Handle low() in a signed context. Also handle sda().
156 The signedness of the value doesn't matter to low(), but this also
157 handles the case where low() isn't present. */
160 parse_slo16 (CGEN_CPU_DESC cd,
166 enum cgen_parse_operand_result result_type;
172 if (strncasecmp (*strp, "low(", 4) == 0)
175 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
176 & result_type, & value);
178 return MISSING_CLOSING_PARENTHESIS;
181 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
191 if (strncasecmp (*strp, "sda(", 4) == 0)
194 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
197 return MISSING_CLOSING_PARENTHESIS;
203 return cgen_parse_signed_integer (cd, strp, opindex, valuep);
206 /* Handle low() in an unsigned context.
207 The signedness of the value doesn't matter to low(), but this also
208 handles the case where low() isn't present. */
211 parse_ulo16 (CGEN_CPU_DESC cd,
214 unsigned long *valuep)
217 enum cgen_parse_operand_result result_type;
223 if (strncasecmp (*strp, "low(", 4) == 0)
226 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
227 & result_type, & value);
229 return MISSING_CLOSING_PARENTHESIS;
232 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
238 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
244 /* Immediate values are prefixed with '#'. */
246 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
249 if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
250 (*info->fprintf_func) (info->stream, "#"); \
254 /* Handle '#' prefixes as operands. */
257 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
259 long value ATTRIBUTE_UNUSED,
260 unsigned int attrs ATTRIBUTE_UNUSED,
261 bfd_vma pc ATTRIBUTE_UNUSED,
262 int length ATTRIBUTE_UNUSED)
264 disassemble_info *info = (disassemble_info *) dis_info;
266 (*info->fprintf_func) (info->stream, "#");
269 #undef CGEN_PRINT_INSN
270 #define CGEN_PRINT_INSN my_print_insn
273 my_print_insn (CGEN_CPU_DESC cd,
275 disassemble_info *info)
277 bfd_byte buffer[CGEN_MAX_INSN_SIZE];
278 bfd_byte *buf = buffer;
280 int buflen = (pc & 3) == 0 ? 4 : 2;
281 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
284 /* Read the base part of the insn. */
286 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
290 (*info->memory_error_func) (status, pc, info);
295 x = (big_p ? &buf[0] : &buf[3]);
296 if ((pc & 3) == 0 && (*x & 0x80) != 0)
297 return print_insn (cd, pc, info, buf, buflen);
299 /* Print the first insn. */
302 buf += (big_p ? 0 : 2);
303 if (print_insn (cd, pc, info, buf, 2) == 0)
304 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
305 buf += (big_p ? 2 : -2);
308 x = (big_p ? &buf[0] : &buf[1]);
312 (*info->fprintf_func) (info->stream, " || ");
316 (*info->fprintf_func) (info->stream, " -> ");
318 /* The "& 3" is to pass a consistent address.
319 Parallel insns arguably both begin on the word boundary.
320 Also, branch insns are calculated relative to the word boundary. */
321 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
322 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
324 return (pc & 3) ? 2 : 4;