1 /* M32R opcode support. -*- C -*-
3 Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
5 Contributed by Red Hat Inc; developed under contract from
6 Mitsubishi Electric Corporation.
8 This file is part of the GNU Binutils.
10 Contributed by Red Hat Inc; developed under contract from Fujitsu.
12 This file is part of the GNU Binutils.
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
28 /* This file is an addendum to m32r.cpu. Heavy use of C code isn't
29 appropriate in .cpu files, so it resides here. This especially applies
30 to assembly/disassembly where parsing/printing can be quite involved.
31 Such things aren't really part of the specification of the cpu, per se,
32 so .cpu files provide the general framework and .opc files handle the
33 nitty-gritty details as necessary.
35 Each section is delimited with start and end markers.
37 <arch>-opc.h additions use: "-- opc.h"
38 <arch>-opc.c additions use: "-- opc.c"
39 <arch>-asm.c additions use: "-- asm.c"
40 <arch>-dis.c additions use: "-- dis.c"
41 <arch>-ibd.h additions use: "-- ibd.h" */
45 #undef CGEN_DIS_HASH_SIZE
46 #define CGEN_DIS_HASH_SIZE 256
49 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
50 #define CGEN_DIS_HASH(buffer, value) \
52 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
53 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
54 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
55 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
57 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash(buffer, value)
58 extern unsigned int m32r_cgen_dis_hash(const char *, CGEN_INSN_INT);
65 m32r_cgen_dis_hash (buf, value)
66 const char * buf ATTRIBUTE_UNUSED;
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 * parse_hash
91 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
92 static const char * parse_hi16
93 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
94 static const char * parse_slo16
95 PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
96 static const char * parse_ulo16
97 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
99 /* Handle '#' prefixes (i.e. skip over them). */
102 parse_hash (cd, strp, opindex, valuep)
103 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
105 int opindex ATTRIBUTE_UNUSED;
106 unsigned long *valuep ATTRIBUTE_UNUSED;
113 /* Handle shigh(), high(). */
116 parse_hi16 (cd, strp, opindex, valuep)
120 unsigned long *valuep;
123 enum cgen_parse_operand_result result_type;
129 if (strncasecmp (*strp, "high(", 5) == 0)
132 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
133 &result_type, &value);
135 return "missing `)'";
138 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
143 else if (strncasecmp (*strp, "shigh(", 6) == 0)
146 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
147 &result_type, &value);
149 return "missing `)'";
152 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
154 value = value + (value & 0x8000 ? 0x10000 : 0);
161 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
164 /* Handle low() in a signed context. Also handle sda().
165 The signedness of the value doesn't matter to low(), but this also
166 handles the case where low() isn't present. */
169 parse_slo16 (cd, strp, opindex, valuep)
176 enum cgen_parse_operand_result result_type;
182 if (strncasecmp (*strp, "low(", 4) == 0)
185 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
186 &result_type, &value);
188 return "missing `)'";
191 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
201 if (strncasecmp (*strp, "sda(", 4) == 0)
204 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
207 return "missing `)'";
213 return cgen_parse_signed_integer (cd, strp, opindex, valuep);
216 /* Handle low() in an unsigned context.
217 The signedness of the value doesn't matter to low(), but this also
218 handles the case where low() isn't present. */
221 parse_ulo16 (cd, strp, opindex, valuep)
225 unsigned long *valuep;
228 enum cgen_parse_operand_result result_type;
234 if (strncasecmp (*strp, "low(", 4) == 0)
237 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
238 &result_type, &value);
240 return "missing `)'";
243 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
249 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
255 static void print_hash PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
256 static int my_print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
258 /* Immediate values are prefixed with '#'. */
260 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
263 if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
264 (*info->fprintf_func) (info->stream, "#"); \
268 /* Handle '#' prefixes as operands. */
271 print_hash (cd, dis_info, value, attrs, pc, length)
272 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
274 long value ATTRIBUTE_UNUSED;
275 unsigned int attrs ATTRIBUTE_UNUSED;
276 bfd_vma pc ATTRIBUTE_UNUSED;
277 int length ATTRIBUTE_UNUSED;
279 disassemble_info *info = (disassemble_info *) dis_info;
280 (*info->fprintf_func) (info->stream, "#");
283 #undef CGEN_PRINT_INSN
284 #define CGEN_PRINT_INSN my_print_insn
287 my_print_insn (cd, pc, info)
290 disassemble_info *info;
292 char buffer[CGEN_MAX_INSN_SIZE];
295 int buflen = (pc & 3) == 0 ? 4 : 2;
296 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
299 /* Read the base part of the insn. */
301 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
305 (*info->memory_error_func) (status, pc, info);
310 x = (big_p ? &buf[0] : &buf[3]);
311 if ((pc & 3) == 0 && (*x & 0x80) != 0)
312 return print_insn (cd, pc, info, buf, buflen);
314 /* Print the first insn. */
317 buf += (big_p ? 0 : 2);
318 if (print_insn (cd, pc, info, buf, 2) == 0)
319 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
320 buf += (big_p ? 2 : -2);
323 x = (big_p ? &buf[0] : &buf[1]);
327 (*info->fprintf_func) (info->stream, " || ");
331 (*info->fprintf_func) (info->stream, " -> ");
333 /* The "& 3" is to pass a consistent address.
334 Parallel insns arguably both begin on the word boundary.
335 Also, branch insns are calculated relative to the word boundary. */
336 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
337 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
339 return (pc & 3) ? 2 : 4;